【发布时间】:2019-06-08 17:13:52
【问题描述】:
我正在尝试制作一个统计系统库,以便将来在尽可能多的游戏中使用,但统一的序列化阻碍了。
知道统一序列化有多糟糕,并且派生实例在序列化期间转换为基类型,我决定让基类派生自 ScriptableObject,但它不起作用。 在这一点上,我的代码变得有点混乱,所以我决定按照本书从头开始制作一个更简单的测试版本,如下所述:
https://forum.unity.com/threads/serialization-best-practices-megapost.155352/
但这也没有用。
基类:
[System.Serializable]
public class BaseClass : ScriptableObject
{
[SerializeField]
private string m_Name;
[SerializeField]
public string Name { get => m_Name; set => m_Name = value; }
public static BaseClass NewInstance()
{
BaseClass b = CreateInstance<BaseClass>();
b.Name = string.Empty;
return b;
}
public static BaseClass NewInstance(string name)
{
BaseClass b = CreateInstance<BaseClass>();
b.Name = name;
return b;
}
}
派生类:
[System.Serializable]
public class DerivedClass : BaseClass
{
[SerializeField]
private string m_Value;
[SerializeField]
public string Value { get => m_Value; set => m_Value = value; }
public new static DerivedClass NewInstance()
{
DerivedClass d = CreateInstance<DerivedClass>();
d.Name = string.Empty;
d.Value = string.Empty;
return d;
}
public static DerivedClass NewInstance(string name, string value)
{
DerivedClass d = CreateInstance<DerivedClass>();
d.Name = name;
d.Value = value;
return d;
}
}
最后是集合类:
[System.Serializable] [CreateAssetMenu(menuName = "CollectionA")]
public class CollectionA : ScriptableObject
{
[SerializeField]
private List<BaseClass> m_TestList;
[SerializeField]
public List<BaseClass> TestList { get => m_TestList; set => m_TestList = value; }
public static CollectionA NewInstance()
{
CollectionA c = CreateInstance<CollectionA>();
c.TestList = new List<BaseClass>();
return c;
}
public List<T> GetAllWithType<T>()
{
try { return TestList.OfType<T>().ToList<T>(); }
catch { return new List<T>(); }
}
}
我正在创建实例并检查如下列表:
private void Update()
{
if (Input.GetKeyDown("k"))
{
print("Derived stats:");
List<DerivedClass> derived = collection.GetAllWithType<DerivedClass>();
foreach (DerivedClass t in derived)
{ print(t.Name + " | " + t.Value); }
}
if (Input.GetKeyDown("p"))
{
DerivedClass d = DerivedClass.NewInstance("Hey", "Hello");
collection.TestList.Add(d);
}
}
我正在使用的自定义编辑器:
[CustomEditor(typeof(CollectionA))]
public class CollectionAEditor : Editor
{
private CollectionA collection;
private List<DerivedClass> derived;
struct derivedValues
{
public string name, value;
}
derivedValues addDerived = new derivedValues();
public override void OnInspectorGUI()
{
if (target is CollectionA)
collection = (CollectionA)target;
if (collection != null)
{
DrawInspector();
}
}
private void DrawInspector()
{
derived = collection.GetAllWithType<DerivedClass>();
// title
EditorGUILayout.Space();
GUILayout.Label("CLASS LIST", EditorStyles.largeLabel);
// title
EditorGUILayout.Space();
GUILayout.Label("Derived classes:", EditorStyles.boldLabel);
// layout labels
GUILayout.BeginHorizontal();
GUILayout.Label("Name", GUILayout.MinWidth(35));
GUILayout.Label("Value", GUILayout.MinWidth(35));
GUILayout.EndHorizontal();
// derived classes list
if (derived.Count <= 0)
GUILayout.Label("Class list empty", EditorStyles.centeredGreyMiniLabel);
else
{
foreach (DerivedClass x in derived)
{
GUILayout.BeginHorizontal();
x.Name = GUILayout.TextField(x.Name, GUILayout.MinWidth(35));
x.Value = GUILayout.TextField(x.Value, GUILayout.MinWidth(35));
GUILayout.EndHorizontal();
}
}
// add derived stat
EditorGUILayout.Space();
GUILayout.BeginHorizontal();
GUILayout.Label("Values:", GUILayout.Width(50f));
addDerived.name = GUILayout.TextField(addDerived.name, GUILayout.MinWidth(35));
addDerived.value = GUILayout.TextField(addDerived.value, GUILayout.MinWidth(35));
GUILayout.EndHorizontal();
if (GUILayout.Button("Add derived class"))
{
collection.TestList.Add(
DerivedClass.NewInstance(addDerived.name, addDerived.value));
addDerived = new derivedValues();
}
// default stats title
EditorGUILayout.Space();
GUILayout.BeginHorizontal();
GUILayout.Label("All classes as default:", EditorStyles.boldLabel);
if (collection.TestList == null) Debug.Log("NULL");
GUILayout.Label(collection.TestList.Count.ToString());
GUILayout.EndHorizontal();
EditorGUILayout.Space();
if (GUILayout.Button("Delete all instances"))
collection.TestList.Clear();
GUILayout.BeginHorizontal();
GUILayout.Label("Name", GUILayout.MinWidth(35));
GUILayout.EndHorizontal();
// all classes list
if (collection.TestList.Count <= 0)
GUILayout.Label("Class list empty", EditorStyles.centeredGreyMiniLabel);
else
{
foreach (BaseClass x in collection.TestList)
{
GUILayout.BeginHorizontal();
x.name = GUILayout.TextField(x.name, GUILayout.MinWidth(35));
GUILayout.EndHorizontal();
}
}
}
}
如果我按下 Play 并将一个新的派生实例添加到列表中,它会被正确识别,直到我再次按下 Play 时,派生实例被移动到基本类型。
我尝试了很多东西,但似乎都没有奏效,所以感谢您尝试帮助我。
【问题讨论】:
-
您能否添加您实际生成并添加新实例的代码部分?
-
我不完全理解这个问题。我很快使用了您的三个脚本,为每个脚本创建了一个实例,并将它们添加到
TestList字段中。不管我多久启动一次播放模式,我总是会看到两个条目:NewBaseClass (BaseClass)和NewDerivedClass (DerivedClass) -
我用您要求的代码更新了帖子。我不知道是否值得一提,但我还有一个
CollectionA的自定义检查器。我使用它只是为了帮助我更好地查看更改并修改Name和Value等值。 -
那么在这种情况下,Inspector 当然也可以是 iisue 的一部分
-
我已将其添加到帖子中