【发布时间】:2019-03-25 12:24:10
【问题描述】:
在 Unity 3D 中,我有一个 MonoBehaviour,其中包含一个类派生列表,这些派生类都基于一个常见的 ScriptableObject。
该列表在自定义编辑器中填充和处理。这工作完美无缺,但有一个例外:每当我复制/粘贴我的MonoBehaviour,或在 Unity 编辑器中复制包含它的游戏对象时,我的列表只包含实例而不包含唯一的克隆。
这是一些示例代码(注意,这只是剥离了测试代码,我的实际类要复杂得多,需要一个单独的数据类):
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
public abstract class MyAbstractBaseClass : ScriptableObject
{
public abstract void foo();
}
public class MyTestScriptableObject : MyAbstractBaseClass
{
public string stringMember;
public override void foo()
{
}
}
public class MyTestMonoBehaviour : MonoBehaviour
{
public List<MyAbstractBaseClass> testList;
}
[CustomEditor(typeof(MyTestMonoBehaviour))]
public class MyTestMonoBehaviourEditor : Editor
{
const int NUM_LISTENTRIES = 5;
public override void OnInspectorGUI()
{
SerializedProperty testListProp = serializedObject.FindProperty("testList");
for (int i = 0; i < testListProp.arraySize; i++)
{
SerializedObject myTestScriptableObjectSO = new SerializedObject(testListProp.GetArrayElementAtIndex(i).objectReferenceValue);
SerializedProperty stringMemberProp = myTestScriptableObjectSO.FindProperty("stringMember");
EditorGUILayout.PropertyField(stringMemberProp);
myTestScriptableObjectSO.ApplyModifiedProperties();
}
if( GUILayout.Button("Generate List"))
{
testListProp.arraySize = NUM_LISTENTRIES;
for( int i=0; i<NUM_LISTENTRIES; i++)
testListProp.GetArrayElementAtIndex(i).objectReferenceValue = ScriptableObject.CreateInstance<MyTestScriptableObject>();
}
serializedObject.ApplyModifiedProperties();
}
}
就像我说的,除了引用/克隆问题之外,这段代码完美无缺。这意味着,当我更改游戏对象 A 上的字符串 1 时,复制的游戏对象 B 上的字符串 1 也会更改。
我当然可以很容易地用ScriptableObject.Instantiate() 克隆ScriptableObject 引用——我的问题是,我不知道何时克隆。
我的问题是:
- 当我的
MonoBehaviour在编辑器中被复制(通过 C&P 或复制的游戏对象?)时,是否有任何回调/虚拟方法或类似方法告诉我? - 或者,在 C# 或 Unity-wise 中是否有任何类型的引用计数,它可以告诉我对象被引用的频率?由于它只是编辑器代码,因此使用反射的方法也可以。
- 对于必须唯一的数据类的基础,
ScriptableObject是最佳选择,还是有其他选择?
frankhermes 已经在 cmets 中建议使用简单的序列化数据类。这适用于单个类,但不幸的是不适用于具有基类的类层次结构,因为 Unity 序列化不支持它们。
【问题讨论】:
-
似乎可编写脚本的对象不是您用例的正确选择,为什么不在 MonoBehaviour 中使用字符串? ScriptableObjects 是用来重复使用和引用的吗?
-
感谢您的评论。我发布的代码当然只是测试代码——实际的类比一个字符串成员复杂得多:一个基类和具有不同成员的多个派生类。这会使在 MonoBehaviour 本身中处理所有这些变得非常尴尬,所以我认为我需要一个单独的数据类。我也已经问过自己,是否可以替代使用 ScriptableObject 作为我的数据类的基础。我将据此扩展我的问题。
-
您可以有一个单独的数据类,它不保存到可编写脚本的对象中,而是序列化到您的 Monobehaviour 实例中。然后,当您复制或复制 GameObject 而不是引用单独的 Scriptable Object 时,它将被克隆。
-
嗯...必须考虑一下...谢谢
-
现在试用了,不适用于类层次结构。据此调整了我的问题。