Я пытаюсь создать библиотеку систем статистики, чтобы в будущем можно было использовать как можно больше игр, но мешает сериализация Unity.
Зная, насколько ужасна сериализация в 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 и добавляюновый производный экземпляр в списке, он распознается должным образом до тех пор, пока я снова не нажму «Воспроизвести», когда производный экземпляр будет перемещен в базовый тип.
Я пробовал много вещей, но ни одна из них, похоже, не работает, поэтому спасибо за попыткучтобы помочь мне.