编辑器关闭后,Unity Scriptable Object 不保留其值

Unity Scriptable Object does not retain his values after the editor is closed

我有以下可编写脚本的对象:

[CreateAssetMenu(fileName = "Assets/Gladio Games/Resources/Levels/LEVLE_TMP", menuName = "Utils/Crossword/Generate Empty Level", order = 100)]
public class Level : ScriptableObject
{
    public char[,] Table { get; protected set; }
    public  List<Crossword> Crosswords { get; protected set; }
    protected static char EMPTY_CHAR = '[=10=]';


    public Crossword GetCrosswordAtIndex(int x, int y, Direction direction)
    {
        //Ottieni la prima e l'unica parola che si trova sotto quell'indice
        return Crosswords.First(crossword => crossword.Direction == direction && crossword.GetCrosswordIndexes().Contains(new Vector2(x, y)));
    }
}

这是我用来保存脚本对象的代码

private static void Save(Level level, string path)
{            
    EditorUtility.SetDirty(level);
    AssetDatabase.CreateAsset(level, path + ".asset");
    AssetDatabase.SaveAssets();
    AssetDatabase.Refresh();
        EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
}

该对象已通过编辑器脚本成功创建,并且保存了所有数据,但如果我关闭并重新打开编辑器,并尝试加载字段,则字段为空。用于保存和加载脚本对象的脚本在场景中使用

我做错了什么?

查看 Script serialization rules

特别是你的情况

  • Serializers in Unity work directly on the fields of your C# classes rather than their properties, so there are rules that your fields must conform to to be serialized.

  • Note: Unity doesn’t support serialization of multilevel types (multidimensional arrays, jagged arrays, dictionaries, and nested container types)

所以你的属性根本没有序列化(=保存)。


作为解决方案

  • 对于Crosswords

    • 确保类型 Crossword 本身是 [Serializable]

    • 改用字段

      public  List<Crossword> Crosswords;
      
  • 对于Table有多种方法。

    我可能会简单地使用包装器 class,例如

     // Could of course make this generic but for the drawer it easier this way for now
     [Serializable]
     public class Table
     {
         [SerializeField]
         [Min(1)]
         private int xDimension = 1;
    
         [SerializeField]
         [Min(1)]
         private int yDimension = 1;
    
         [SerializeField]
         private char[] flatArray = new char[1];
    
         public Table() { }
    
         public Table(char[,] array)
         {
             xDimension = array.GetLength(0);
             yDimension = array.GetLength(1);
             flatArray = new char[xDimension * yDimension];
    
             for (var x = 0; x < xDimension; x++)
             {
                 for (var y = 0; y < yDimension; y++)
                 {
                     flatArray[x * yDimension + y] = array[x, y];
                 }
             }
         }
    
         public Table(int x, int y)
         {
             xDimension = x;
             yDimension = y;
             flatArray = new char[x * y];
         }
    
         public Table(char[] array, int x, int y)
         {
             xDimension = x;
             yDimension = y;
             flatArray = array;
         }
    
         public char this[int x, int y]
         {
             get => flatArray[x * yDimension + y];
    
             set => flatArray[x * yDimension + y] = value;
         }
    
     #if UNITY_EDITOR
         [CustomPropertyDrawer(typeof(Table))]
         private class TableDrawer : PropertyDrawer
         {
             private const int k_elementSpacing = 5;
    
             public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
             {
                 var height = 1f;
    
                 if (property.isExpanded)
                 {
                     height += property.FindPropertyRelative(nameof(Table.xDimension)).intValue * 1.5f;
                 }
    
                 return height * EditorGUIUtility.singleLineHeight;
             }
    
             public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
             {
                 var foldoutRect = position;
                 foldoutRect.height = EditorGUIUtility.singleLineHeight;
                 foldoutRect.width = EditorGUIUtility.labelWidth;
                 property.isExpanded = EditorGUI.Foldout(foldoutRect, property.isExpanded, label);
    
                 if (property.isExpanded)
                 {
                     var xRect = position;
                     xRect.height = EditorGUIUtility.singleLineHeight;
                     xRect.x += foldoutRect.width;
                     xRect.width -= foldoutRect.width;
                     xRect.width *= 0.5f;
    
                     var yRect = xRect;
                     yRect.x += xRect.width;
    
                     var xDimension = property.FindPropertyRelative(nameof(Table.xDimension));
                     var yDimension = property.FindPropertyRelative(nameof(Table.yDimension));
                     var array = property.FindPropertyRelative(nameof(Table.flatArray));
    
                     using (var changeCheck = new EditorGUI.ChangeCheckScope())
                     {
                         EditorGUI.PropertyField(xRect, xDimension, GUIContent.none);
                         EditorGUI.PropertyField(yRect, yDimension, GUIContent.none);
    
                         if (changeCheck.changed)
                         {
                             array.arraySize = xDimension.intValue * yDimension.intValue;
                         }
                     }
    
                     position.y += EditorGUIUtility.singleLineHeight * 1.5f;
                     EditorGUI.indentLevel++;
                     var elementRect = EditorGUI.IndentedRect(position);
                     EditorGUI.indentLevel--;
    
                     var elementWidth = elementRect.width / yDimension.intValue - k_elementSpacing;
                     var elementHeight = EditorGUIUtility.singleLineHeight;
    
                     var currentPosition = elementRect;
                     currentPosition.width = elementWidth;
                     currentPosition.height = elementHeight;
    
                     for (var x = 0; x < xDimension.intValue; x++)
                     {
                         for (var y = 0; y < yDimension.intValue; y++)
                         {
                             var element = array.GetArrayElementAtIndex(x * yDimension.intValue + y);
    
                             EditorGUI.PropertyField(currentPosition, element, GUIContent.none);
    
                             currentPosition.x += elementWidth + k_elementSpacing;
                         }
    
                         currentPosition.x = elementRect.x;
                         currentPosition.y += elementHeight * 1.5f;
                     }
                 }
             }
         }
     #endif
     }
    

    然后宁愿有例如

    public Table Table;