我正在尝试建立一个统计系统库,以在将来尽可能多的游戏中使用,但是unity的序列化阻碍了这一工作。
知道序列化的统一性是多么糟糕,并且派生的实例在序列化过程中被转换为基类型,所以我决定使基类从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为止。
我尝试了很多事情,但是似乎都没有用,所以感谢您尝试帮助我。
答案 0 :(得分:0)
好,我知道了。我不是在2类中创建资产。 ScriptableObjects作为资产不能在没有明显丢失引用的情况下引用非资产/预制实例,因此我的BaseClass
列表中的数据丢失了。
结论:仅仅为您使用资产的ScriptableObject字段创建ScriptableObject包装器是不够的,但是您也需要从这些字段中制作资产,以免引用丢失。
@derHugo谢谢您的宝贵时间。