Unity - 如何创建自定义编辑器以动态更改具有自定义大小的其他列表中列表的大小?

Unity - How to create a Custom Editor for dynamically change size of a list inside an other list with custom size?

我想为 Unity 创建一个自定义编辑器,其中一个列表包含一个列表,并允许动态编辑大小并在第二个列表中包含一个弹出窗口。

这里有几个我想要的例子:

问题是我无法更改第二个列表的大小,因为它会更改第二个列表中所有元素的大小,所以我不能为列表的每个元素设置不同的大小。

我的弹出窗口也有同样的问题,所有弹出窗口选择的项目总是相同的(正如你在第二张图片中看到的那样)。

如何在不更改其他选项的情况下保存每个所选项目的每个维度或所选弹出窗口?

这是我的代码:

ScriptableObject class

public class MyClass : ScriptableObject {

public class MyInsideClass
{
    public List<string> data;

    public MyInsideClass()
    {
        data = new List<string>();
    }
}

public List<MyInsideClass> allData;
}

Custom Editor (Database just have the popup list names)

[CustomEditor(typeof(MyClass))]
public class TempEdior : Editor
{
    int numberOfCombinations = 0;
    int numberOfDataForCombination = 0;
    int selected = 0;

    public override void OnInspectorGUI()
    {
        GUILayout.BeginHorizontal();
        GUILayout.Label("Number of combinations:");
        numberOfCombinations =         EditorGUILayout.IntField(numberOfCombinations);
        GUILayout.EndHorizontal();

        for (int i = 0; i < numberOfCombinations; i++)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label("Combination " + (i + 1) + " - number of data:");
            numberOfDataForCombination =     EditorGUILayout.IntField(numberOfDataForCombination);
            GUILayout.EndHorizontal();

            for (int j = 0; j < numberOfDataForCombination; j++)
            {
                Rect rect = EditorGUILayout.GetControlRect();
                selected = EditorGUI.Popup(new Rect(rect.x + 63, rect.y, 100, EditorGUIUtility.singleLineHeight), selected,     Database.Instance.slotTypes.ToArray());
            }
        }
    }
}

在我看来,您的做法是错误的。永远编写检查器代码很容易得意忘形,以令人费解的方式打破 Unity 的范式,却收效甚微。尽可能多地依赖 SerializedProperties,因为它将处理撤消、multi-edit 等

基本上您想要的只是使用弹出窗口编辑字符串,对吧?然后为此使用一个 PropertyDrawer,剩下的就让 Unity 的数组检查器发挥它的魔力:

using System;
using UnityEditor;
using UnityEngine;

public class TestArrayOfArray : MonoBehaviour
{
    [Serializable]
    public struct ComboItem
    {
        public string value;
    }

    [Serializable]
    public struct Combo
    {
        public ComboItem[] items;
    }

    public Combo[] combos;
}

[CustomPropertyDrawer(typeof(TestArrayOfArray.ComboItem))]
public class ComboItemDrawer : PropertyDrawer
{
    static readonly string[] comboItemDatabase = { "Bla", "Bli", "Blu" };
    static readonly GUIContent[] comboItemDatabaseGUIContents = Array.ConvertAll(comboItemDatabase, i => new GUIContent(i));

    public override void OnGUI( Rect position, SerializedProperty property, GUIContent label )
    {
        property = property.FindPropertyRelative("value");

        EditorGUI.BeginChangeCheck();
        int selectedIndex = Array.IndexOf(comboItemDatabase, property.stringValue);
        selectedIndex = EditorGUI.Popup(position, label, selectedIndex, comboItemDatabaseGUIContents);
        if (EditorGUI.EndChangeCheck())
        {
            property.stringValue = comboItemDatabase[selectedIndex];
        }
    }
}

这是非常粗糙的,运行时 + 检查器代码在单个文件中,将 "database" hard-coded 伪造为静态数组,在 multi-edit 的情况下不处理混合值等等等等,但它应该可以帮助您入门。

--

一般建议:如果可以的话,优先使用数组而不是列表,例如,在这种情况下,组合是静态序列化数据,您永远不会在运行时调整其大小,因此数组效率更高。

尽可能内联字段声明以提高可读性(例如 public List<string> data = new List<string>(); 就可以)。

不要初始化已序列化的 arrays/lists,因为它们的默认值会被反序列化覆盖,从而导致分配浪费。