c0d3n4m 发表于 2022-12-4 18:46

Unity:嵌套ScriptableObject的持久化存储

假设我们有一个继承自 ScriptableObject 的子类:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace TestCode
{
    public class TestChildAsset : ScriptableObject
    {
      public List<string> testStrs;

      public TestChildAsset()
      {
            testStrs = new List<string>();
      }
    }
}
有一个继承自 ScriptableObject 的父类,其中包含子类的 List :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

namespace TestCode
{
   
    public class TestParentAsset : ScriptableObject
    {
      public List<TestChildAsset> childs;

      public void AddChild(TestChildAsset child)
      {
            if(childs == null)
            {
                childs = new List<TestChildAsset>();
            }
            childs.Add(child);
      }
    }


   
    public class TestParentAssetInspector : Editor
    {
      public override void OnInspectorGUI()
      {
            base.OnInspectorGUI();
            if (GUILayout.Button("Add New Child"))
            {
                TestParentAsset parent = this.target as TestParentAsset;
                TestChildAsset child = ScriptableObject.CreateInstance<TestChildAsset>();
                child.name = "TestChild";
                parent.AddChild(child);
            }
      }
    }
}

此时创建父类,添加新节点时会显示:


点击 TypeMissMatch 可以进入编辑,然而这个数据是无法存储下来的。触发代码编译或者 Unity 重启后这个数据都会丢失。
原因是 ScriptableObject 只能引用资产,引用了未被序列化的对象就会出现这个问题。因此结论是我们没有正确序列化子类,因为 CreateInstance 只是在内存中创建数据,并没有保存到磁盘里。
解决方案是把子类也都序列化保存下来:




只需要在父类里加一行修改就可以:
public void AddChild(TestChildAsset child)
{
    //调用 AddObjectToAsset 将子资源添加到父资源中
    AssetDatabase.AddObjectToAsset(child, this);
    if(childs == null)
    {
      childs = new List<TestChildAsset>();
    }
    childs.Add(child);
}用脚本执行上述过程:
string testPath = "Assets/Dango/ConfigInfo/Test.asset";
var parent = CreateInstance<TestParentAsset>();
var child = CreateInstance<TestChildAsset>();
var child2 = CreateInstance<TestChildAsset>();
child.name = "TestChild1";
child2.name = "TestChild2";
AssetDatabase.CreateAsset(parent, testPath);
parent.AddChild(child);
parent.AddChild(child2);
//更新数据
EditorUtility.SetDirty(parent);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
结果:

页: [1]
查看完整版本: Unity:嵌套ScriptableObject的持久化存储