如何在“编辑器”窗口中以相同大小显示“检查器”窗口?

时间:2019-07-12 14:05:34

标签: c# unity3d

问题在于,在Inspector中看起来不错,但是在“编辑器”窗口中,控件和字段不在同一位置。

在屏幕截图中,“检查器”窗口位于右侧,“编辑器”窗口位于左侧。问题出在检查器上的“对话名称”上,“名称”字段紧随“对话名称”之后,但是在“编辑器”窗口中,“名称”字段似乎有点超出“对话名称”:

Conversation Name

这是编辑器脚本:

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

[CustomEditor(typeof(ConversationTrigger))]
public class ConversationTriggerEditor : Editor
{
    private ConversationTrigger _conversationTrigger;

    [SerializeField] private ReorderableList conversationsList;

    private SerializedProperty _conversations;

    private int _currentlySelectedConversationIndex = -1;
    private int newSize = 0;
    private Vector2 scrollPos;
    private SerializedProperty conversationsCounter;

    private readonly Dictionary<string, ReorderableList> _dialoguesListDict = new Dictionary<string, ReorderableList>();
    private readonly Dictionary<string, ReorderableList> _sentencesListDict = new Dictionary<string, ReorderableList>();

    private void OnEnable()
    {
        _conversationTrigger = (ConversationTrigger)target;
        _conversations = serializedObject.FindProperty("conversations");

        conversationsList = new ReorderableList(serializedObject, _conversations)
        {
            displayAdd = true,
            displayRemove = true,
            draggable = true,

            drawHeaderCallback = DrawConversationsHeader,

            drawElementCallback = DrawConversationsElement,

            onAddCallback = (list) =>
            {
                SerializedProperty addedElement;
                // if something is selected add after that element otherwise on the end
                if (_currentlySelectedConversationIndex >= 0)
                {
                    list.serializedProperty.InsertArrayElementAtIndex(_currentlySelectedConversationIndex + 1);
                    addedElement = list.serializedProperty.GetArrayElementAtIndex(_currentlySelectedConversationIndex + 1);
                }
                else
                {
                    list.serializedProperty.arraySize++;
                    addedElement = list.serializedProperty.GetArrayElementAtIndex(list.serializedProperty.arraySize - 1);
                }

                var name = addedElement.FindPropertyRelative("Name");
                var foldout = addedElement.FindPropertyRelative("Foldout");
                var dialogues = addedElement.FindPropertyRelative("Dialogues");

                name.stringValue = "";
                foldout.boolValue = false;
                dialogues.arraySize = 0;

                conversationsCounter = addedElement.FindPropertyRelative("ConversationIndex");
            },

            elementHeightCallback = (index) =>
            {
                return GetConversationHeight(_conversations.GetArrayElementAtIndex(index));
            }
        };
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update();

        // if there are no elements reset _currentlySelectedConversationIndex
        if (conversationsList.serializedProperty.arraySize - 1 < _currentlySelectedConversationIndex) _currentlySelectedConversationIndex = -1;

        EditorGUILayout.LabelField("Conversations", EditorStyles.boldLabel);
        EditorGUI.BeginChangeCheck();
        {
            newSize = EditorGUILayout.IntField(_conversations.arraySize);
        }
        if (EditorGUI.EndChangeCheck())
        {
            if (newSize > _conversations.arraySize)
            {
                // elements have to be added -> how many?
                var toAdd = newSize - _conversations.arraySize - 1;
                // why -1 ? -> We add the first element and set its values to default
                // now if we simply increase the arraySize for the rest of the elements
                // they will be all a copy of the first -> all defaults ;)

                // first add one element
                _conversations.arraySize++;
                // then get that element
                var newIndex = _conversations.arraySize - 1;
                var newElement = _conversations.GetArrayElementAtIndex(newIndex);

                // now reset all properties like
                var name = newElement.FindPropertyRelative("Name");
                name.stringValue = "";

                // now for the rest simply increase arraySize
                _conversations.arraySize += toAdd;
            }
            else
            {
                // for removing just make sure the arraySize is not under 0
                _conversations.arraySize = Mathf.Max(newSize, 0);
            }
        }

        scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.Height(250));

        GUILayout.Space(10);
        conversationsList.DoLayoutList();

        EditorGUILayout.EndScrollView();

        if (GUILayout.Button("Save Conversations"))
        {
            _conversationTrigger.SaveConversations();
        }

        if (GUILayout.Button("Load Conversations"))
        {
            Undo.RecordObject(_conversationTrigger, "Loaded conversations from JSON");
            _conversationTrigger.LoadConversations();
        }

        serializedObject.ApplyModifiedProperties();
    }

    #region Drawers

    #region List Headers

    private void DrawConversationsHeader(Rect rect)
    {
        //EditorGUI.LabelField(rect, "Conversations");
    }

    private void DrawDialoguesHeader(Rect rect)
    {
        EditorGUI.LabelField(rect, "Dialogues");
    }

    private void DrawSentencesHeader(Rect rect)
    {
        EditorGUI.LabelField(rect, "Sentences");
    }

    #endregion List Headers

    #region Elements

    private void DrawConversationsElement(Rect rect, int index, bool isActive, bool isFocused)
    {
        if (isActive) _currentlySelectedConversationIndex = index;

        var conversation = _conversations.GetArrayElementAtIndex(index);

        var position = new Rect(rect);

        var name = conversation.FindPropertyRelative("Name");
        var foldout = conversation.FindPropertyRelative("Foldout");
        var dialogues = conversation.FindPropertyRelative("Dialogues");
        string dialoguesListKey = conversation.propertyPath;

        EditorGUI.indentLevel++;
        {
            // make the label be a foldout
            //GUI.TextField(new Rect(position.x, position.y, 15, EditorGUIUtility.singleLineHeight), itemscounter.ToString());
            foldout.boolValue = EditorGUI.Foldout(new Rect(position.x, position.y, 10, EditorGUIUtility.singleLineHeight), foldout.boolValue, "Conversation Name ", true);
            name.stringValue = EditorGUI.TextField(new Rect(position.x + 120, position.y, 244, EditorGUIUtility.singleLineHeight), name.stringValue);

            if (foldout.boolValue)
            {
                // draw the name field
                //name.stringValue = EditorGUI.TextField(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), name.stringValue);
                position.y += EditorGUIUtility.singleLineHeight;

                if (!_dialoguesListDict.ContainsKey(dialoguesListKey))
                {
                    // create reorderabl list and store it in dict
                    var dialoguesList = new ReorderableList(conversation.serializedObject, dialogues)
                    {
                        displayAdd = true,
                        displayRemove = true,
                        draggable = true,

                        drawHeaderCallback = DrawDialoguesHeader,

                        drawElementCallback = (convRect, convIndex, convActive, convFocused) => { DrawDialoguesElement(_dialoguesListDict[dialoguesListKey], convRect, convIndex, convActive, convFocused); },

                        elementHeightCallback = (dialogIndex) =>
                        {
                            return GetDialogueHeight(_dialoguesListDict[dialoguesListKey].serializedProperty.GetArrayElementAtIndex(dialogIndex));
                        },

                        onAddCallback = (list) =>
                        {
                            list.serializedProperty.arraySize++;
                            var addedElement = list.serializedProperty.GetArrayElementAtIndex(list.serializedProperty.arraySize - 1);

                            var newDialoguesName = addedElement.FindPropertyRelative("Name");
                            var newDialoguesFoldout = addedElement.FindPropertyRelative("Foldout");
                            var sentences = addedElement.FindPropertyRelative("Sentences");

                            newDialoguesName.stringValue = "";
                            newDialoguesFoldout.boolValue = true;
                            sentences.arraySize = 0;
                        }
                    };
                    _dialoguesListDict[dialoguesListKey] = dialoguesList;
                }

                _dialoguesListDict[dialoguesListKey].DoList(new Rect(position.x, position.y, position.width, position.height - EditorGUIUtility.singleLineHeight));
            }

        }
        EditorGUI.indentLevel--;
    }

    private void DrawDialoguesElement(ReorderableList list, Rect rect, int index, bool isActive, bool isFocused)
    {
        if (list == null) return;

        var dialog = list.serializedProperty.GetArrayElementAtIndex(index);

        var position = new Rect(rect);

        var foldout = dialog.FindPropertyRelative("Foldout");
        var name = dialog.FindPropertyRelative("Name");

        {
            // make the label be a foldout
            foldout.boolValue = EditorGUI.Foldout(new Rect(position.x, position.y, 10, EditorGUIUtility.singleLineHeight), foldout.boolValue, foldout.boolValue ? "" : name.stringValue);

            var sentencesListKey = dialog.propertyPath;
            var sentences = dialog.FindPropertyRelative("Sentences");

            if (foldout.boolValue)
            {
                // draw the name field
                name.stringValue = EditorGUI.TextField(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), name.stringValue);
                position.y += EditorGUIUtility.singleLineHeight;

                if (!_sentencesListDict.ContainsKey(sentencesListKey))
                {
                    // create reorderabl list and store it in dict
                    var sentencesList = new ReorderableList(sentences.serializedObject, sentences)
                    {
                        displayAdd = true,
                        displayRemove = true,
                        draggable = true,

                        // header for the dialog list
                        drawHeaderCallback = DrawSentencesHeader,

                        // how a sentence is displayed
                        drawElementCallback = (sentenceRect, sentenceIndex, sentenceIsActive, sentenceIsFocused) =>
                        {
                            var sentence = sentences.GetArrayElementAtIndex(sentenceIndex);

                            // draw simple textArea for sentence
                            sentence.stringValue = EditorGUI.TextArea(sentenceRect, sentence.stringValue);
                        },

                        // Sentences have simply a fixed height of 2 lines
                        elementHeight = EditorGUIUtility.singleLineHeight * 2,

                        // when a sentence is added
                        onAddCallback = (sentList) =>
                        {
                            sentList.serializedProperty.arraySize++;
                            var addedElement = sentList.serializedProperty.GetArrayElementAtIndex(sentList.serializedProperty.arraySize - 1);

                            addedElement.stringValue = "";
                        }
                    };

                    // store the created ReorderableList
                    _sentencesListDict[sentencesListKey] = sentencesList;
                }

                // Draw the list
                _sentencesListDict[sentencesListKey].DoList(new Rect(position.x, position.y, position.width, position.height - EditorGUIUtility.singleLineHeight));
            }
        }
    }

    #endregion Elements

    #endregion Drawers


    #region Helpers

    #region HeightGetter

    /// <summary>
    /// Returns the height of given Conversation property
    /// </summary>
    /// <param name="conversation"></param>
    /// <returns>height of given Conversation property</returns>
    private float GetConversationHeight(SerializedProperty conversation)
    {
        var foldout = conversation.FindPropertyRelative("Foldout");

        // if not foldout the height is simply 1 line
        var height = EditorGUIUtility.singleLineHeight;

        // otherwise we sum up every controls and child heights
        if (foldout.boolValue)
        {
            // we need some more lines:
            //  for the Name field,
            // the list header,
            // the list buttons and a bit buffer
            height += EditorGUIUtility.singleLineHeight * 5;


            var dialogues = conversation.FindPropertyRelative("Dialogues");

            for (var d = 0; d < dialogues.arraySize; d++)
            {
                var dialog = dialogues.GetArrayElementAtIndex(d);
                height += GetDialogueHeight(dialog);
            }
        }

        return height;
    }

    /// <summary>
    /// Returns the height of given Dialogue property
    /// </summary>
    /// <param name="dialog"></param>
    /// <returns>height of given Dialogue property</returns>
    private float GetDialogueHeight(SerializedProperty dialog)
    {
        var foldout = dialog.FindPropertyRelative("Foldout");

        // same game for the dialog if not foldout it is only a single line
        var height = EditorGUIUtility.singleLineHeight;

        // otherwise sum up controls and child heights
        if (foldout.boolValue)
        {
            // we need some more lines:
            //  for the Name field,
            // the list header,
            // the list buttons and a bit buffer
            height += EditorGUIUtility.singleLineHeight * 4;

            var sentences = dialog.FindPropertyRelative("Sentences");

            // the sentences are easier since they always have the same height
            // in this example 2 lines so simply do
            // at least have space for 1 sentences even if there is none
            height += EditorGUIUtility.singleLineHeight * Mathf.Max(1, sentences.arraySize) * 2;
        }

        return height;
    }

    #endregion

    #endregion Helpers
}

这是我添加“对话名称”和“名称”字段的部分:

foldout.boolValue = EditorGUI.Foldout(new Rect(position.x, position.y, 10, EditorGUIUtility.singleLineHeight), foldout.boolValue, "Conversation Name ", true);
name.stringValue = EditorGUI.TextField(new Rect(position.x + 120, position.y, 244, EditorGUIUtility.singleLineHeight), name.stringValue);

这是“编辑器窗口”脚本:

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

public class ConversationsEditorWindow : EditorWindow
{
    private ConversationTriggerEditor editor;

    [MenuItem("Conversations/Conversations System")]
    static void Init()
    {
        const int width = 800;
        const int height = 800;

        var x = (Screen.currentResolution.width - width) / 2;
        var y = (Screen.currentResolution.height - height) / 2;

        var window = GetWindow<ConversationsEditorWindow>();
        var ff = FindObjectOfType<ConversationTrigger>();
        window.position = new Rect(x, y, width, height);
        window.editor = (ConversationTriggerEditor)Editor.CreateEditor(ff);
    }

    void OnGUI()
    {
        editor.OnInspectorGUI();
    }
}

0 个答案:

没有答案