C# 场景重新加载后,统一引用将中断

C# 场景重新加载后,统一引用将中断,c#,unity3d,C#,Unity3d,我在unity中遇到了一个奇怪的问题,当我重新加载一个场景时,引用不断中断,我试图理解到底发生了什么,但没有运气。 我制作了一个脚本来复制你可以在下面找到的问题 当我通过更改大小编辑最后一个数据元素“列表”时,更改会反映在其他数据对象列表上,因为它们被视为引用。 . 如果重新加载场景,更改将不再像以前那样反映出来,这次它的行为类似于副本而不是引用。 有人能帮我弄清楚发生了什么事吗? . 使用系统集合; 使用System.Collections.Generic; 使用UnityEditor

我在unity中遇到了一个奇怪的问题,当我重新加载一个场景时,引用不断中断,我试图理解到底发生了什么,但没有运气。 我制作了一个脚本来复制你可以在下面找到的问题

当我通过更改大小编辑最后一个数据元素“列表”时,更改会反映在其他数据对象列表上,因为它们被视为引用。
.

如果重新加载场景,更改将不再像以前那样反映出来,这次它的行为类似于副本而不是引用。
有人能帮我弄清楚发生了什么事吗?
.

使用系统集合;
使用System.Collections.Generic;
使用UnityEditor;
使用UnityEngine;
公共课堂测试:单一行为
{
公共列表数据=新列表();
}
[系统可序列化]
公共类数据
{
公共列表=新列表();
}
[自定义编辑器(类型(测试))]
公共类测试员:编辑器
{
试验;
public void OnEnable()
{
测试=(测试)目标;
}
公共覆盖无效OnInspectorGUI()
{
DrawDefaultInspector();
if(GUILayout.按钮(“添加”))
{
数据=新数据();
如果(test.Data.Count>=1)Data.list=test.Data[test.Data.Count-1].list;
测试.数据.添加(数据);
EditorUtility.SetDirty(测试);
}
如果(GUILayout.按钮(“清除”))
{
test.Data.Clear();
EditorUtility.SetDirty(测试);
}
}
}

一般来说:不要直接访问和更改您的
MonoBehavior
实例的值

正如你所指出的,你将不得不处理各种各样的污点,拯救你自己。在编辑器中重新打开场景时,您的体验是,某些内容没有正确标记为脏,因此没有与场景一起保存


始终通过s处理所有标记脏和保存,尤其是自动撤消/重做等:

[CustomEditor(typeof(test))]
public class testEditor : Editor
{
    private SerializedProperty Data;

    public void OnEnable()
    {
        Data = serializedObject.FindProperty(nameof(test.Data));
    }

    public override void OnInspectorGUI()
    {
        DrawDefaultInspector();

        // load all current values of the properties in test into the SerializedProperty "clones"
        serializedObject.Update();

        if (GUILayout.Button("Add"))
        {
            // this simply adds a new entry to the list
            // since the data and list are both serializable this already initializes them with values
            Data.arraySize++;


            // Actually the entire following block is redundant 
            // by using Data.arraySize++; the new added entry automatically 
            // is a full copy of the entry before!
            // I just decided to add it as example how you would access further nested SerializedProperties

            //// if there was an element before now there are two
            //if (Data.arraySize >= 2)
            //{
            //    // get the last added element
            //    var lastElement = Data.GetArrayElementAtIndex(Data.arraySize - 1);
            //    var beforeElement = Data.GetArrayElementAtIndex(Data.arraySize - 2);

            //    // deep clone the list
            //    var lastElementList = lastElement.FindPropertyRelative(nameof(data.list));
            //    var beforeElementList = beforeElement.FindPropertyRelative(nameof(data.list));

            //    lastElementList.arraySize = beforeElementList.arraySize;
            //    for (var i = 0; i < lastElementList.arraySize; i++)
            //    {
            //        lastElementList.GetArrayElementAtIndex(i).intValue = beforeElementList.GetArrayElementAtIndex(i).intValue;
            //    }
            //}
        }

        if (GUILayout.Button("Clear"))
        {
            Data.arraySize = 0;
        }

        // write back the values of the SerializedProperty "clones" into the real properties of test
        serializedObject.ApplyModifiedProperties();
    }
}


注意如果情况并非如此:
测试器
部件应

  • 可以将其放置在名为
    Editor
  • 或者,您应该将与
    UnityEditor
    名称空间相关的任何内容包装在预处理器中,如

    #if UNITY_EDITOR
    using UnityEditor;
    using UnityEditorInternal;
    #endif
    
    ...
    
    #if UNITY_EDITOR
    [CustomEditor(typeof(test))]
    public class testEditor : Editor
    {
        ...
    }
    #endif
    

否则,您将在构建应用程序时出错,因为
UnityEditor
命名空间在构建中被剥离,并且仅存在于Unity编辑器本身中

尝试添加
DontDestroyOnLoad(this.gameObject)
在您的Awake functionHi开始时,这是一个编辑器插件问题,我发现了这个问题,我在thanxHi下面的评论中提到了它,感谢您花时间,并感谢您建议使用可重排序列表和序列化属性,事实上我一直在使用它们,但在我上面的示例中,我只是想复制这个问题,就像我发现了这一切,我上面写的代码是正确的,问题是Unity没有像文档中提到的那样序列化自定义类,当Unity进行反序列化时,它会创建类对象的副本,而不是再次链接引用,@Bardouah不,正如所说的,序列化是有效的,因为您可以在inspector中看到类。。。脚本中不起作用的是将内容标记为“脏”,因此它不会正确保存到场景中,而是在重新打开场景之前保留为临时值。因此,如前所述:不要直接编写值,而是使用SerializedProperty,这是编写编辑器scriptsHi的正确方法。您是否阅读了我上面发布的unity docs链接的这一部分。使用非从UnityEngine派生的自定义类。对象Unity按值内联序列化它们,类似于它序列化结构的方式。如果在几个不同的字段中存储对自定义类实例的引用,则序列化时它们将成为单独的对象。然后,当Unity反序列化字段时,它们包含不同的距离增加具有相同数据的对象。”
using UnityEditor;
using UnityEditorInternal;

[CustomEditor(typeof(test))]
public class testEditor : Editor
{
    private SerializedProperty Data;
    private ReorderableList dataList;

    public void OnEnable()
    {
        Data = serializedObject.FindProperty(nameof(test.Data));

        //                                 should the list
        //                                                     | be reorderable by drag&drop of the entries?
        //                                                     |     | display a header for the list?
        //                                                     |     |     | have an Add button?
        //                                                     |     |     |     | have a Remove button?
        //                                                     v     v     v     v
        dataList = new ReorderableList(serializedObject, Data, true, true, true, true)
        {
            // what shall be displayed as header
            drawHeaderCallback = rect => EditorGUI.LabelField(rect, Data.displayName),

            elementHeightCallback = index =>
            {
                var element = Data.GetArrayElementAtIndex(index);
                var elementList = element.FindPropertyRelative(nameof(data.list));
                return EditorGUIUtility.singleLineHeight * (elementList.isExpanded ? elementList.arraySize + 4 : 3);
            },

            drawElementCallback = (rect, index, isFocused, isActive) =>
            {
                var element = Data.GetArrayElementAtIndex(index);

                EditorGUI.LabelField(new Rect(rect.x,rect.y,rect.width,EditorGUIUtility.singleLineHeight), element.displayName);
                // in order to print the list in the next line
                rect.y += EditorGUIUtility.singleLineHeight;

                var elementList = element.FindPropertyRelative(nameof(data.list));
                EditorGUI.PropertyField(new Rect(rect.x, rect.y, rect.width,  EditorGUIUtility.singleLineHeight * (elementList.isExpanded ? elementList.arraySize + 1 : 1)), elementList, true);
            }
        };
    }

    public override void OnInspectorGUI()
    {
        // load all current values of the properties in test into the SerializedProperty "clones"
        serializedObject.Update();

        dataList.DoLayoutList();

        // write back the values of the SerializedProperty "clones" into the real properties of test
        serializedObject.ApplyModifiedProperties();
    }
}
#if UNITY_EDITOR
using UnityEditor;
using UnityEditorInternal;
#endif

...

#if UNITY_EDITOR
[CustomEditor(typeof(test))]
public class testEditor : Editor
{
    ...
}
#endif