- Home /
Can’t serialize custom class variable in ScriptableObject.Or add instance of a class to a list with overridden method in custom editor.
I’m making simple inventory system. I got a class for an Item
[System.Serializable]
public class Item
{
public string itemName;
public int itemId;
//some more variables
public Effect itemEffect;
//some more code
public void Use(Entity x)
{
itemEffect.UseEffect(x);
}
}
All the items are stored in the list inside ScriptableObject with a custom editor. The best way of implementing item effect I came up with is this. Every item has method “Use” which is calling “UseEffect” method of itemEffect variable which is an instance of Effect class This is the Effect class.
[Serializable]
public class Effect
{
public string effectName;
public Effect ()
{
this.effectName = "BaseEffect";
}
public virtual void UseEffect (SomeParameter x)
{
Debug.Log("This is base effect"+ x.Something.ToString());
}
}
This is my Test Effect derived from Effect class
public class TestEffect: Effect
{
public TestEffect()
{
this.effectName = "TestEffect";
}
public override void UseEffect(SomeParameter x)
{
Debug.Log("This is TEST EFFECT");
x.something = x.something+1;
Debug.Log(x.something.ToStirng());
}
}
This is how i assign TestEffect object to Item variable i custom editor.
if (GUI.Button(//someRect,"Apply test effect to test item"))
{
//Item_Database_Asset is the ScriptableObject with Items_Database_List of all items
Item_Database_Asset.Items_Database_List[1].itemEffect = new TestEffect();;
EditorUtility.SetDirty(Item_Database_Asset);
}
So the problem is after i click "Apply test effect to test item" when i press play and using this item it’s calling UseEffect of BaseEffect. Although in inspector i see that item[1] itemEffect.effectName is TestEffect. So is basically working but it’s still calling BaseEffect. But if i click "Apply test effect to test item" on runtime in play mode it works fine. It's a bit long and convoluted.I hope it's readable. Thank you.
Answer by Bunny83 · Aug 18, 2017 at 12:46 AM
Unity has no polymorphism support for custom serialized classes. Read the documentation about serialization. Especially the part:
When might the serializer behave unexpectedly?
Custom serialized classes are mainly meant to be data containers. The serializer serializes custom classes based on the variable type, not the actual type.
Thank you, you are right
No support for polymorphism
I didn't know that. Well, it's so stupid i googled it and found a request to add support of this back in 2012. Is there any workaround or better yet can propose another way to assign method from one script to object from another(well scriptable-object) in the editor.
$$anonymous$$y first approach was a save list of delegates/Actions, turns out delegates are not serializable (duh). Then i tried this. I'm out of ideas.
Well, there are alternatives. However it depends on what's your goal.
First of all if you just want to serialize method references you can use a UnityEvent. It's basically a serializable delegate class, however with some differences. You can only serialize delegates to methods that belong to a class that is derived from UnityEngine.Object as those are the only class references that can be serialized. The only baseclasses you can actually derive your classes from are $$anonymous$$onoBehaviour and ScriptableObject.
If you actually need polymorphism / inheritance and you want to serialize the references you have to derive your base class either from $$anonymous$$onoBehaviour or ScriptableObject. Since those can be stored as assets Unity can serialize references to them. While $$anonymous$$onoBehaviours are components which need to be attached to a GameObject (in the scene or to a prefab asset), ScriptableObjects need to be serialized as seperate assets.
Thank you, i will try both things just to see which is more appropriate for my thing.