1
\$\begingroup\$

I want to make a custom inspector that I'm not really sure how to approach. The idea is I have a quest framework with a class that holds onto the quest data and another class that is intended to hold onto dialogue data. The quest system is agnostic of my dialogue system.

I want to be able to display the quest and dialogue data this way:

QuestName0

  • DialogueGiveQuest (TextAsset field)
  • DialogueQuestIsActive (TextAsset field)
  • DialogueQuestIsComplete (TextAsset field)

QuestName1

  • DialogueGiveQuest (TextAsset field)
  • DialogueQuestIsActive (TextAsset field)
  • DialogueQuestIsComplete (TextAsset field)

etc...

Here's a pseudocode class layout

public class QuestData : MonoBehaviour
{
    List<Quest> quests;
}

public class DialogueData : MonoBehaviour
{
    public TextAsset dialogueGiveQuest;
    public TextAsset dialogueQuestIsActive;
    public TextAsset dialogueQuestIsComplete;
}

public class Interaction : MonoBehaviour
{
    QuestData questData;
    List<DialogueData> dialogueData;
}

[CustomEditor(typeof(Interaction))]
public class InteractionEditor : Editor
{
    public override void OnInspectorGUI()
    {
        var interactionData = (InteractionData)target;
        //foreach interactionData.questData.quests
          // draw quest name
          // make sure there's a dialogueData element for each quest
          // draw field for each DialogueData
    }
}

An obvious issue is dialogueData doesn't care about what's going on with questData.quests so if the inspector were to draw normally it would display 2 lists. I'd like the dialogue data to add and remove elements to itself depending on the quest data but that sounds like it be a real challenge to serialize.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

You should check EditorGUILAyout's API to check the drawing field functions. To get the classes's properties (or GameObject's for that matter) you will need to use reflection to get their data, so you can know which EditorGUILayout fields to draw. A vague example (haven't tested it, but it goes sorta this way):

    public MonoBehaviour mono;
    FieldInfo[] fieldsInfo; 
    BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; /// You should check .NET's documentation to get detailed info about it.

    void Awake()
    {
        fieldsInfo = mono.GetType().GetFields(flags);
        foreach(FiendInfo field in fieldsInfo)
        {
            Debug.Log("Field is called: " + field.Name);
        }
    }

    void OnInspectorGUI()
    {
        fieldsInfo = mono.GetType().GetFields(flags);
        foreach(FiendInfo field in fieldsInfo)
        {
            if(field.GetType == typeof(UnityEngine.Object))
            {
                Unity.Object obj = null;
                EditorGUILayout.ObjectField(obj, typeof(UnityEngine.Object), true);
            }
        }
    }

That seems kinda complex, so what you can do is to have classes, like DialogueData, don't inherit from monobehaviour, and give it the [System.Serializable] attribute, so in a controller GameObject, you can have a list of those classes so they show on that GameObject's inspector, exmaple:

    [System.Serializable]
    public class DialogueSentence
    {
        [SerializeField] private String _actor;
        [SerializeField] private string _sentence;

        public string Actor
        {
            get { return _actor; }
            set { _actor = value; }
        }

        public string Sentence
        {
            get { return _sentence; } 
            set { _sentence = value; }
        }
    }

    public class DialogueController : MonoBehaviour
    {
        public List<DialogueSentence> sentences; /// Now you have your Senence class's list on the inspector.
    }

Sorry if I didn't use examples directly from your classes.

As a side note, I suggest you explore Text Area's Attribute to stylize your dialogue boxes on the inspector.

Edit: I forgot to give [SerializeField] attributes to the DialogueSentence fields, so they appear on your public list. Also, I changed the class's names for the sake of avoiding ambiguity.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .