Search Unity

How to draw serialized classes and sub classes in Editor Window?

Discussion in 'Immediate Mode GUI (IMGUI)' started by eses, Dec 10, 2019.

  1. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    Hi

    I've been tackling this for a while.

    I'm trying to draw standard C# classes and sub classes in custom Editor Window without manually drawing individual fields.

    As serialized classes don't have inspector like MonoBehaviours I can't just draw default inspector for class, so I resorted to using serialized object / serialized property, which I wrap to a ScriptableObject class, where I store the classes ItemData or SubItemData (example), which can then be drawn to editor window like this:

    EditorGUILayout.PropertyField(prop, true);


    Which will with the second parameter set to true draw all the fields of the class.

    However the problem with this is the fact that I wouldn't like to duplicate code. If I have a class ItemData and then SubItemData derived from it, I can't just do:

    itemScriptableObject.itemData = someSubItemData;


    As the EditorGUILayout.PropertyField will draw it using the type of the field (= ItemData). So I'll have to start doing either separate ScriptableObject classes or several fields for each sub class, which I also have to check with is type:

    Code (CSharp):
    1. if (item is SubItemData)
    2. {
    3.     itemScriptableObject.subItemData = item as SubItemData;
    4.     prop = so.FindProperty("subItemData");
    5. }
    Any ideas how to do this in some better way?

    It wouldn't be a problem if I only had 1 or 2 sub classes but I guess I'll have 10-15.
     
    Last edited: Dec 10, 2019
  2. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,329
    Could you use Editor.CreateEditor to get the Editor for the whole ScriptableObject and use that when drawing in the custom EditorWindow?

    Another option would be to use reflection to examine the fields contained inside the ScriptableObject and build the SerializedProperties dynamically using this information.
     
    eses likes this.
  3. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    @SisusCo

    "Could you use Editor.CreateEditor to get the Editor for the whole ScriptableObject and use that when drawing in the custom EditorWindow?"

    TBH that is exactly what I did and I don't quite know if I like it or not. And reflection I've only tried once and it is above my skills.

    I created a container scriptable object class, that just had fields for ClassBase, ClassSub1, ClassSub2 and so on. Basically item class and sub classes. Then in editor window, when rendering the item, I create an instance of this scriptable object "container" and put suitable serializable class in its field. Then I can turn it into serialized object, and get the suitable subclass and render it with EditorGUILayout.PropertyField.

    But the issue here is the fact that I wish I could just have one field of base type, like "ClassBase" in the scriptable object, but then the EditorGUILayout.PropertyField only renders the exact type's fields. I didn't find any options to fix this... so no sub class fields unless I give it the correct field with proper type, so I'll have to have a custom editor for the scriptable object container class that hides the not used fields, so I can only show one of the fields.

    Just now I was building another version, where I have a static helper class/methods that spit out editor fields for an item class instance based on its type. This felt like a lot of work before I tried, but actually it is less lines of code (because classes don't have many fields at least yet). Lists have to be handled manually, object fields look horrible, and I have to create the fields for each class manually, but it is OK I guess. And I don't even have time or skills for this.

    Edit:
    All this just because I need to draw different items in my map editor based on user selection.
     
    Last edited: Dec 12, 2019
  4. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,329
    Yeah, unfortunately Unity has always been really bad at visualizing (or serializing) polymorphic data properly, forcing us developers to come up with all kinds of workaround to get past the problem.

    Thankfully there is light at the end of the tunnel (finally!). If you can upgrade your project to Unity 2019.3 Beta or 2020.1 Beta you can add the SerializeReference attribute to the ClassBase field, and that PropertyField should just start working.
     
    eses likes this.
  5. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637