Search Unity

Question Create Inspector UI for parent class that changes depending on the type of child

Discussion in 'Scripting' started by unity_8I_suMy7c9iU0g, Mar 28, 2023.

  1. unity_8I_suMy7c9iU0g

    unity_8I_suMy7c9iU0g

    Joined:
    May 29, 2020
    Posts:
    26
    What i want to do is create interface for status effects in RPG.

    The skills are ScriptableObjects and going to have a field for effects. The problem is i need to be able to add effects and change them. But the base class is going to have child classes with new fields, for example PoisonEffect with a new variable dmgTick.

    I'm thinking about creating an enum on base class with all effect type names and update gui depending on it.

    How can i do it?

    (Another thing is i plan on changing base class to abstract, so unity will not be able to show it with just simple [Serializable] attribute. Can GUI show variables from abstract classes?)

    Here's code of StatusEffect classes:

    Code (CSharp):
    1. [Serializable]
    2. public class StatusEffect
    3. {
    4.     public string statusName;
    5.     public int duration;
    6.  
    7.     public virtual void Tick(Stats target)
    8.     {
    9.         duration--;
    10.     }
    11. }
    12.  
    13. [Serializable]
    14. public class PoisonEffect : StatusEffect
    15. {
    16.     public int dmgTick;
    17.  
    18.     public override void Tick(Stats target)
    19.     {
    20.         target.TakeDmg(dmgTick);
    21.  
    22.         base.Tick(target);
    23.     }
    24. }
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
  3. unity_8I_suMy7c9iU0g

    unity_8I_suMy7c9iU0g

    Joined:
    May 29, 2020
    Posts:
    26
  4. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,935
    Firstly, this polymorphic serialisation needs to be achieved by using the SerializeReference attribute: https://docs.unity3d.com/ScriptReference/SerializeReference.html

    Secondly, you will need write your own editor or property drawer for the specified type, though there's lots of existing examples out there. Do a google search or look through the asset store and I imagine you'll find something.
     
  5. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    4,008
    Actually not really necessary. The inspector would actually just draw the child class fields correctly depending on what actual type is stored in the field. However Unity currently does not have any mechanism to create those different child classes. So all you need is implement this creation process of the specific types. The rest is already handled by EditorGUI.PropertyField. Setting or "changing" the type of a field is the tricky part. First you need a list of all possible types. This can be achieved through reflection. The UnityEditor already provides you with the TypeCache.GetTypesDerivedFrom method which should make this part easy.

    Of course you can not simply "change" the type of an instance in an array. Instead you have to create a new instance of that new type and replace the old one. Maybe you provide a CopyFrom method in your base class to be able to copy the base fields over to the new type. That way you would not loose those values when "switching" types.

    But just to make that clear, Spiney is right that for such a polymorphic structure you need to use SerializeReference. If you need this behaviour in an array as well as for single fields, its generally better to create a wrapping type and just write a property drawer for that wrapping type. Otherwise you would have trouble with arrays since we can not attach attributes to the elements of an array, only the array / List itself.
     
  6. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,935
    What you're on about is what I meant really; my bad for not being clear. Unity doesn't have the out of the box support for this otherwise powerful serialisation feature for selecting/swapping the serialised reference type.

    It really should, but we're stuck rolling our own to make it possible, or using asset store tools, such as Odin Inspector.
     
    Bunny83 likes this.
  7. unity_8I_suMy7c9iU0g

    unity_8I_suMy7c9iU0g

    Joined:
    May 29, 2020
    Posts:
    26
    Hey, thanks for the answer. It did help and i was able to create a property drawer for the class! However now, if the SerializeReference field is null or empty, PropertyDrawer still tries to draw the GUI. How can i prevent this?
     
  8. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,935
    Just check if the value is null, and if so, don't draw it?

    Your property drawer has access to the value, so just run the necessary checks.
     
  9. unity_8I_suMy7c9iU0g

    unity_8I_suMy7c9iU0g

    Joined:
    May 29, 2020
    Posts:
    26
    Yeah, my bad, i was checking objectReferenceValue instead of managedReferenceValue