如何在Inspector编辑器脚本中绘制列表及其所有项目? [英] How can I draw a List and all it's items in Inspector editor script?

查看:83
本文介绍了如何在Inspector编辑器脚本中绘制列表及其所有项目?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

主要脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DialogueTrigger : MonoBehaviour
{
    public List<Dialogue> dialogue = new List<Dialogue>();

    [HideInInspector]
    public int dialogueNum = 0;

    private bool triggered = false;

    public void TriggerDialogue()
    {
        if (triggered == false)
        {
            if (FindObjectOfType<DialogueManager>() != null)
            {
                FindObjectOfType<DialogueManager>().StartDialogue(dialogue[dialogueNum]);
                dialogueNum += 1;
            }
            triggered = true;
        }
    }

    private void Update()
    {
        if (DialogueManager.dialogueEnded == true)
        {
            if (dialogueNum == dialogue.Count)
            {
                return;
            }
            else
            {
                FindObjectOfType<DialogueManager>().StartDialogue(dialogue[dialogueNum]);
                DialogueManager.dialogueEnded = false;
                dialogueNum += 1;
            }
        }
    }
}

创建项目名称和句子的对话脚本:

The dialogue script that create the items name and sentences:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
public class Dialogue
{
    public string name;

    [TextArea(1, 10)]
    public string[] sentences;
}

编辑器脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(DialogueTrigger))]
public class DialogueTriggerEditor : Editor
{
    private SerializedProperty _dialogues;

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

        _dialogues = serializedObject.FindProperty("dialogue");
        serializedObject.Update();

        for (int i = 0; i < _dialogues.arraySize; i++)
        {
            var dialogue = _dialogues.GetArrayElementAtIndex(i);
            EditorGUILayout.PropertyField(dialogue, new GUIContent("Dialogue " + i));
        }
    }
}

但是现在我在检查器中有了一个对话框变量,可以在其中设置对话框的数量以及每个对话框的名称和句子.

But now I have one variable of the dialogue in the Inspector there I can set the number of dialogues and each dialogue name and sentences.

但是在此之下,它会根据我设置的对话数量创建更多的对话.

But under it it's creating more Dialogues according to the number of dialogues I set.

我想在检查器中使用的是一种主要的对话:

What I want to have instead in the Inspector is one main Dialogues:

然后在其中设置对话次数.例如,如果我设置5,则在对话"下将有:对话1对话2对话3对话4对话5

Then inside it I can set the number of dialogues. For example if I set 5 then under Dialogues there will be: Dialogue 1 Dialogue 2 Dialogue 3 Dialogue 4 Dialogue 5

然后在每个对话"下,例如对话1"下,将显示其名称和句子.能够更改每个对话的句子大小.

And then inside under each Dialogue for example Dialogue 1 there will be the Name and Sentences of it. With the able to change the sentences size of each dialogue.

推荐答案

问题是默认情况下EditorGUILayout.PropertyField不支持嵌套属性.

The problem is that EditorGUILayout.PropertyField by default doesn't support nested properties.

最简单的解决方法是使用正确的重载 PropertyField(SerializedProperty property, GUIContent label, bool includeChildren, params GUILayoutOption[] options);

The simplest fix would be to use the correct overload PropertyField(SerializedProperty property, GUIContent label, bool includeChildren, params GUILayoutOption[] options);

需要bool includeChildren:

[CustomEditor(typeof(DialogueTrigger))]
public class DialogueTriggerEditor : Editor
{
    private SerializedProperty _dialogues;

    private void OnEnable()
    {
        // do this only once here
        _dialogues = serializedObject.FindProperty("dialogue");
    }

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

        serializedObject.Update();

        // Ofcourse you also want to change the list size here
        _dialogues.arraySize = EditorGUILayout.IntField("Size", _dialogues.arraySize);

        for (int i = 0; i < _dialogues.arraySize; i++)
        {
            var dialogue = _dialogues.GetArrayElementAtIndex(i);
            EditorGUILayout.PropertyField(dialogue, new GUIContent("Dialogue " + i), true);
        }

        // Note: You also forgot to add this
        serializedObject.ApplyModifiedProperties();
    }
}

请注意,还有其他更具可辩护性的解决方案.另一个快速的例如手动获取这些嵌套属性并定义应如何绘制它们:

Note there are other more custumizeable solutions. Another quick one might e.g. be to manually get those nested properties and define how they should be drawn:

[CustomEditor(typeof(DialogueTrigger))]
public class DialogueTriggerEditor : Editor
{
    private SerializedProperty _dialogues;

    // store which dialogue is foldout
    private List<bool> dialogueFoldout = new List<bool>();

    private void OnEnable()
    {
        _dialogues = serializedObject.FindProperty("dialogue");

        for (var i = 0; i < _dialogues.arraySize; i++)
        {
            dialogueFoldout.Add(false);
        }
    }

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

        serializedObject.Update();

        var color = GUI.color;

        EditorGUI.BeginChangeCheck();
        _dialogues.arraySize = EditorGUILayout.IntField("Size", _dialogues.arraySize);
        if (EditorGUI.EndChangeCheck())
        {
            dialogueFoldout.Clear();

            for (var i = 0; i < _dialogues.arraySize; i++)
            {
                dialogueFoldout.Add(false);
            }

            serializedObject.ApplyModifiedProperties();
            return;
        }

        for (var i = 0; i < _dialogues.arraySize; i++)
        {
            var dialogue = _dialogues.GetArrayElementAtIndex(i);

            dialogueFoldout[i] = EditorGUILayout.Foldout(dialogueFoldout[i], "Dialogue " + i);

            // make the next fields look nested below the before one
            EditorGUI.indentLevel++;

            if (dialogueFoldout[i])
            {
                var name = dialogue.FindPropertyRelative("name");
                var sentences = dialogue.FindPropertyRelative("sentences");

                if (string.IsNullOrWhiteSpace(name.stringValue)) GUI.color = Color.yellow;
                EditorGUILayout.PropertyField(name);
                GUI.color = color;

                // if you still want to be able to controll the size
                sentences.arraySize = EditorGUILayout.IntField("Senteces size", sentences.arraySize);

                // make the next fields look nested below the before one
                EditorGUI.indentLevel++;
                for (var s = 0; s < sentences.arraySize; s++)
                {
                    var sentence = sentences.GetArrayElementAtIndex(s);
                    if (string.IsNullOrWhiteSpace(sentence.stringValue)) GUI.color = Color.yellow;
                    EditorGUILayout.PropertyField(sentence, new GUIContent("Sentece " + s));
                    GUI.color = color;
                }
                EditorGUI.indentLevel--;
            }

            EditorGUI.indentLevel--;
        }

        serializedObject.ApplyModifiedProperties();
    }
}


您可以再次迈出一步,而是为您使用完整的 CustomPropertyDrawer Dialogue类.这样做的巨大优势在于,不仅是在DialogueTrigger类中,而且在您拥有public Dialogue字段的任何地方中,它都将使用自定义抽屉显示出来!


You can again take a step forward and instead use a complete CustomPropertyDrawer for your Dialogue class. The huge advantage of this would be that not only in this one class DialogueTrigger but everywhere where you ever have a public Dialogue field it would be displayed using the custom drawer instead!

或者,如果您真的想要精美的列表(可重新排序),可以轻松删除任何索引等元素,则强烈建议您查看我在这里的问题中,我们也解决了如何将其用于嵌套列表(如您的情况).

Or if you really want fancy Lists (reorderable), simple to remove elements at any index etc I strongly recommend to have a look at ReorderableList. It is a not documented feature Unity uses e.g. in the UnityEvent (like onClick) and a bit complex to get into it but as soon as you got it once it is really powerful! (In my question here we also solved how to use this for nested Lists like in your case.)

这篇关于如何在Inspector编辑器脚本中绘制列表及其所有项目?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆