Can a class's Editor call its component's Editor? Likewise, can a derived class's Editor call its base class's Editor?

Dear all,
I’m trying to customize Unity Editor, and the following problem keep bothering me.
To make it brief: Can the OnInspectorGUI() of Customized Editor behaves like a Constructor **that can call its components’ OnInspectorGUI() **? How? Likewise for the derived class, how can I call its base class’s OnInspectorGUI()?

For Component Case:

Suppose I’m writing class Player, and it has a Component: CharacterAttribute. And now I’m writing the Customized Editor for Player, can I call the Editor of CharacterAttribute?


    // In "Player.cs":
    public class Player : MonoBehaviour
    {
        CharacterAttribute attribute;
        [SerializeField] Armer armer;
    }
    
    // In "CharacterAttribute.cs", it has Customized Editor already defined in "CharacterAttributeEditor.cs"
    public class CharacterAttribute  : MonoBehaviour
    {
        float healthPoins;
    }
    
    // In "PlayerEditor.cs":
    [CustomEditor( typeof(Player), true )]
    public class PlayerEditor: Editor
    {
        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI (); // this seems only display "armer" in the Inspector, but no CharacterAttribute
        }
    }

For Inheritance Case:

For inheritance case, suppose I have a abstract class Human, it define some basic Live attribute. Then I define a custom Editor for abstract class Human.

Latter, I define a class Warrior that inherit from Human, and has extra data members such as Attack attribute (thus a Editor with extra column should be added.). However, the base.OnInspectorGUI() of Warrior seems will not call the Editor of Human at all…

I have tried to use another approach by eliminate the HumanEditor. Instead, in class Human I define a drawInspector() that contained the original content in HumanEditor.OnInspectorGUI(). And will be called by WarriorEditor.OnInspectorGUI(). This approach can fulfill what I want in the Inspector but kind of silly. Moreover, I can’t use the Unity default inspector of class Warrior by base.OnInspectorGUI(). Otherwise, not only the Warrior will be Draw, but also the Human


    // Human.cs
    [System.Serializable]
    public abstract class Human : MonoBehaviour  // its Editor has been customized
    {
        [SerializeField] private float health;
        
        public void drawInspector() //define a Editor callback
        {
            // Draw the Basic Inspector for Human

            EditorUtility.SetDirty (this);
        }
    }
        
    // Warrior.cs
    public class Warrior : Human
    {
        float attack;
    }
        
    // WarriorEditor.cs
    [CustomEditor( typeof(Warrior) )]
    public class WarriorEditor : Editor
    {
         public override void OnInspectorGUI()
         {
             Warrior warrior = this.target as warrior;
             warrior.drawInspector(); //display the Inspector of Human
         }
    }

Any idea? Thanks.

PS. I’m using Unity 4.6.1

You are using the term class and component a little weird so it was kind of hard to follow this question at the beginning. In Unity a Component is a class which inherits from MonoBehaviour and they cannot have other components, but they can have references to them in a variable/property.

Anyway, yes what you are describing is perfectly possible.

Component case:

The most elegant solution here would be to create a PropertyDrawer for the CharacterAttribute. This will make it easy to have the EditorGUI for CharacterAttribute be drawn wherever CharacterAttribute is used, except it cannot be used for a MonoBehaviour (which CharacterAttribute is).

Another way would be to create a normal CustomEditor Inspector for it and have all its GUI functionality done in a public static function which both the custom inspector for characterattribute and player uses.

Example:

[CustomEditor(typeof(CharacterAttribute))]
public class CharacterAttributeInspector : Editor
{
    private CharacterAttribute attribute;
    private void Awake()
    {
        attribute = (CharacterAttribute)target;
    }

    public override void OnInspectorGUI()
    {
        OnCustomInspectorGUI(attribute);
    }

    public static void OnCustomInspectorGUI(CharacterAttribute characterAttribute)
    {
        //Do gui stuff here
    }
}

Then also call the static function from the Player inspector when needed.

Example:

[CustomEditor(typeof(Player))]
public class PlayerInspector : Editor
{
    private Player player;
    protected virtual void Awake()
    {
        player = (Player)target;
    }

    public override void OnInspectorGUI()
    {
        //Draw the characterAttribute gui:
        CharacterAttributeInspector.OnCustomInspectorGUI(player.characterAttribute);

        //Do other player GUI stuff...
    }
}

Inheritance case:

You cannot do Editor functionality inside of MonoBehaviours, so the drawInspector thing will not work (it may seem like you can if you include using UnityEditor in the class, but then you will get a lot of problems when building the project).

What you want can be achieved by having the custom Inspector for the warrior class inherit from the inspector for the human class. So the warrior inspector will call base.OnInspectorGUI() which will be the human inspectors OnInspectorGUI().

Here are some example scripts:

public class Human : MonoBehaviour 
{
    public float health;
}

public class Warrior : Human 
{
    public float attack;
}

[CustomEditor(typeof(Human))]
public class HumanInspector : Editor
{
    private Human human;
    protected virtual void Awake()
    {
        human = (Human)target;
    }

    public override void OnInspectorGUI()
    {
        EditorGUILayout.BeginVertical(GUI.skin.box);
        EditorGUILayout.LabelField("Human Settings");
        human.health = EditorGUILayout.Slider("Health", human.health, 0, 100);
        EditorGUILayout.EndVertical();
    }
}

[CustomEditor(typeof(Warrior))]
public class WarriorInspector : HumanInspector 
{
    private Warrior warrior;
    protected virtual void Awake()
    {
        base.Awake();

        warrior = (Warrior)target;
    }

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        EditorGUILayout.Space();

        EditorGUILayout.BeginVertical(GUI.skin.box);
        EditorGUILayout.LabelField("Warrior Settings");
        warrior.attack = EditorGUILayout.Slider("Attack Power", warrior.attack, 0, 100);
        EditorGUILayout.EndVertical();
    }
}

If you attach a Human to a GameObject you will see it only draws the Health slider, and when you attach a Warrior to a GameObject you see it draws both the Health slider and the Attack Power slider. Note that the Human Inspector has the awake function set as protected (so the warrior inspector can get it) and virtual (so the warrior inspector can override it), because only the Warrior Inspector will have its functions called by Unity so the Warrior Inspector will have to call the Human Inspectors functions.