• Unity开发笔记-使用AssetDatabase.AddObjectToAsset函数,正确序列化ScriptableObject的多态数组,修复TypeMissMatch错误


    假设我们需要使用ScriptableObject来保存一个图的结构,我们先创建2个ScriptableObject的子类,Graph和GraphNodeBase

    GraphNodeBase类如下

    namespace YaoJZ.SerializeTest
    {
        public class GraphNodeBase:ScriptableObject
        {
            
        }
    }
    

    Graph类如下

    namespace YaoJZ.SerializeTest
    {
        [CreateAssetMenu(fileName = "graph.asset",menuName = "yaojz/graph")]
        public class Graph:ScriptableObject
        {
            public List<GraphNodeBase> Nodes;
    
            public void AddNode(GraphNodeBase node)
            {
                Nodes.Add(node);
            }
        }
    }
    

    我们需要根据需求扩展GraphNodeBase的子类,比如AnimationClipNode

    namespace YaoJZ.SerializeTest
    {
        public class AnimationClipNode:GraphNodeBase
        {
            public AnimationClip Clip;
        }
    }
    

    我们需要CreateAssetMenu用来创建Graph.asset资产

    现在我们需要扩展一下Graph的Inspector,增加一个按钮,用来添加节点,用来添加AnimationClipNode

    
    namespace YaoJZ.SerializeTest.Editor
    {
        [CustomEditor(typeof(Graph))]
        public class GraphInspector:UnityEditor.Editor
        {
            public override void OnInspectorGUI()
            {
                base.OnInspectorGUI();
                if (GUILayout.Button("add animation node"))
                {
                    Graph g = this.target as Graph;
                    g.AddNode(ScriptableObject.CreateInstance<AnimationClipNode>());
                }
            }
        }
    }
    

    现在我们点击一下按钮

    出现了TypeMissMatch,这显然不是我们想要的AnimationClipNode,原因是ScriptableObject只能引用资产,引用了未被序列化的对象就会出现这个问题。因此结论是我们没有正确序列化AnimationClipNode,因为CreateInstance只是创建再内存中,并没有保存到磁盘里。

    解决方案很简单,只需要AssetDatabase.AddObjectToAsset,将AnimationClipNode嵌入到已被序列化好的Graph中即可

    更新后的Graph类

    
    public class Graph:ScriptableObject
        {
            public List<GraphNodeBase> Nodes;
    
            public void AddNode(GraphNodeBase node)
            {
                AssetDatabase.AddObjectToAsset(node,this);      //将node序列化,并嵌入graph对象中
                if (Nodes == null)
                {
                    Nodes = new List<GraphNodeBase>();
                }
                Nodes.Add(node);
            }
        }
    

    按一下ctrl+s保存下项目,查看graph.asset,就可以发现node已作为孩子节点被序列化在graph中了

  • 相关阅读:
    什么是 Linux
    Java常用几种加密算法
    Java多线程
    SpringSecurity相关配置【SpringSecurityConfig】
    应用上下文配置【AppConfig】
    web.xml
    Web上下文配置【MvcConfig】
    SpringMVC4零配置--Web上下文配置【MvcConfig】
    HTML <meta> 标签 遇到<meta http-equiv="refresh" content="0; url=">详解
    java如何获取当前机器ip和容器port
  • 原文地址:https://www.cnblogs.com/terrynoya/p/14417952.html
Copyright © 2020-2023  润新知