2013.12.10 04:48

유니티의 상속클래스를 어셋으로 저장하는 방법을 기록한다.


1. 기본노드.

기본 노드는 스크립터블 오브젝트(ScriptableObject) 를 상속한다.

// Node.cs

using UnityEngine;


public abstract class Node : ScriptableObject

{

    public int BaseData;


    public virtual void Draw()

    {

        Debug.Log("Base Draw");

    }


    public virtual void OnInspector()

    {

        GUILayout.Label("Base Node");

    }


// Hide 플래그를 지정하지 않으면 릭이 발생한다.

    public void OnEnable() { hideFlags = HideFlags.HideAndDontSave; }

}


2. 상속받은 노드.

특별한건 없다.

// NodeA.cs

using UnityEngine;


public class NodeA : Node

{

    public float AData;


    public override void Draw()

    {

        Debug.Log("A Draw");

    }


    public override void OnInspector()

    {

        GUILayout.Label("A Node");

    }

}


// NodeB.cs

using UnityEngine;


public class NodeB : Node

{

    public string BData;


    public override void Draw()

    {

        Debug.Log("B Draw");

    }


    public override void OnInspector()

    {

        GUILayout.Label("B Node");

    }

}


3. 리스트.

노드들의 리스트를 가진 클래스. 이역시 ScriptableObject 를 상속받는다.

// NodeList.cs

using UnityEngine;

using System.Collections.Generic;


public class NodeList : ScriptableObject

{

   public List<Node> nodes = new List<Node>();


// Hide 플래그를 지정하지 않으면 릭이 발생한다.

    public void OnEnable() { hideFlags = HideFlags.HideAndDontSave; }

}


4. 저장.

노드가 ScriptableObject를 상속받았으므로, ScriptableObject.CreateInstance 를 이용해 인스턴스를 생성한다.

특이점은, 각각의 노드 또한 AssetDatabase.AddObjectToAsset 를 사용해 추가 저장해줘야한다는것.

노드 요소들에 hideFlag 를 정해주지 않으면, 빈 어셋에 여러개의 서브어셋이 들어간 모양새가 된다.

MainAsset을 제외하고는 hideFlags 를 HideFlags.HideInHierarchy 로 설정해준다.

        NodeList list = ScriptableObject.CreateInstance<NodeList>();

list.hideFlags = HideFlags.None;


        NodeB n = ScriptableObject.CreateInstance<NodeB>();

        n.BaseData = 10;

        n.BData = "Ho!!";

        n.hideFlags = HideFlags.HideInHierarchy;


        NodeA a = ScriptableObject.CreateInstance<NodeA>();

        a.BaseData = 20;

        a.AData = 2.1f;

        a.hideFlags = HideFlags.HideInHierarchy;


        NodeA b = ScriptableObject.CreateInstance<NodeA>();

        b.BaseData = 30;

        b.AData = 3.1f;

        b.hideFlags = HideFlags.HideInHierarchy;


        list.nodes.Add(n);

        list.nodes.Add(a);

        list.nodes.Add(b);


        AssetDatabase.CreateAsset(list, path);

        list.nodes.ForEach(node => { AssetDatabase.AddObjectToAsset(node, list); });


        AssetDatabase.SaveAssets();

        EditorUtility.FocusProjectWindow();

        Selection.activeObject = list;


5. 로드

NodeList list = AssetDatabase.LoadAssetAtPath(path, typeof(NodeList)) as NodeList;

        if (list == null)

            Debug.Log("Error:)");

        else

            list.nodes.ForEach(node => { Debug.Log(node.BaseData); });


6. 주의 할것.

1) ScriptableObject 에 저장되는 유효값은 public 이거나, [SerializeField] 속성을 가져야 한다.

2) AssetDatabase.CreateAsset 에 저장되는 path는 '.asset' extension 을 가져야 한다. 그 외의 확장자명은 정상 처리되지 않는다.

3) hideFlags 를 평소에는 HideFlags.HideAndDontSave 로 설정해줘야지 에디터 창을 닫는다던가 할때 릭이 발생하지 않는다.

저장할때만 리스트는 HideFlags.None 노드는 HideFlags.HideInHierarchy 로 설정하여 저장한다(아니면 에러가 뜬다.)

이후 저장이 종료되면 다시 HideAndDontSave로 설정해줘야 하는데 OnEnable() 에서 설정해주면 알아서 된다.


참고 : http://forum.unity3d.com/threads/155352-Serialization-Best-Practices-Megapost


Posted by 바하무트