Custom editor won't show the variables of inheritance/sub class

Recently, I have been stuck into some problem which I am not able to find any solution online.
First, I have a base class called NPCAction.

[System.Serializable]
public class NPCAction
{
    public ActionType actionType;
    public int test = 0; //Just to be sure that the variables of the base class are correctly shown.

    public NPCAction(ActionType actionType){this.actionType = actionType;}

    public virtual IEnumerator onAction ()  { }
}

Then, I have a sub class which inheritance class NPCAction, called NPCAction_Speak.

[System.Serializable]
public class NPCAction_Speak : NPCAction
{
    public String[] dialog;

    public NPCAction_Speak() : base(ActionType.speak) { }

    public override IEnumerator onAction()
    {
        //Speaks...
    }
}

After that, I have a NPC controller script, which does the actions of the NPC.

[System.Serializable]
public class NPC : MonoBehaviour
{
    public NPCAction[] actions;
    //...
    private IEnumerator doActions()
    {
        foreach (NPCAction action in actions)
            yield return StartCoroutine(action.onAction());
    }
    //...
}

Something like that.

Then, I have a custom editor script which looks something like this.

[CustomEditor(typeof(NPC))]
public class NPCEditor : Editor
{
    public override void OnInspectorGUI()
    {
        serializedObject.Update();
        NPC npcScript = (NPC)target;
        showActions(serializedObject.FindProperty("actions"), npcScript);
        serializedObject.ApplyModifiedProperties();
    }

    public static void showActions(SerializedProperty list, NPC npcScript)
    {
        EditorGUILayout.PropertyField(list);
        if (list.isExpanded)
        {
            EditorGUILayout.PropertyField(list.FindPropertyRelative("Array.size")); //View and edit the size of array

            for (int i = 0; i < list.arraySize; i++)
            {
                EditorGUILayout.LabelField("Action " + (i + 1), EditorStyles.boldLabel);
                ActionType type =
                    (ActionType)EditorGUILayout.EnumPopup("Action Type", npcScript.interactActions[i].actionType);

//For instance, when ActionType.speak is selected in the EnumPopup, the variables of the class
//NPCAction_Speak will be shown, and when ActionType.moveForward is selected, the
//variables of the class NPCAction_Speak will be hidden, And the variables of the class
//NPCAction_MoveForward will be shown. It basically like the light component in Unity which
//when you select different light type, it will show different options of the light.

                switch (type)
                {
                    //...
                    case ActionType.speak:
                        npcScript.actions[i] = new NPCAction_Speak();
                        break;
                    //...
                }
                EditorGUILayout.PropertyField(list.GetArrayElementAtIndex(i), true);
//List the public variables which can be edited.
            }
        }
    }
}

So, the problem is here. The custom editor script only show public variables of the base class NPCAction. It doesn’t show the public variables of the sub class NPCAction_Speak. It shows the variable int test of the NPCAction class, but it doesn’t show the variable string[ ] dialog of the NPCAction_Speak class.
How can I solve it? Any help will be appreciated.

Unity and C# inheritance of classes (which don’t inherit from UnityEngine.Object) don’t get along too well. Inside your NPC class, whenever Unity serializes and deserializes it, the array of NPCAction is treated as literally that. The serialization process has no awareness of inheritance; it just directly saves and restores everything precisely as if it were the type specified.

If you really need inheritance, you’ll need to research ScriptableObject, and make your NPCAction class inherit from that. But be warned, ScriptableObject is also something of a beast that can be tricky to tame, since it has its own idiosyncracies to learn and adapt to.

2 Likes