【问题标题】:How to create multidimensional array in Unity Inspector?如何在 Unity Inspector 中创建多维数组?
【发布时间】:2018-03-18 23:42:02
【问题描述】:

如何在 Unity Inspector 中创建一个枚举多维数组并使其可序列化,以便我可以从不同的脚本调用它?

public enum colors {red, blue, green, yellow, cyan, white, purple};
public int rows = 7;
public int column = 4;
public colors[,] blockColors;

private void Awake() {
    blockColors = new colors[rows, column];
}

对我来说,在脚本中手动输入所有 28 种颜色非常耗时,尤其是当我必须为数百个级别执行此操作时。有没有办法在 Inspector 中创建表格以加快工作流程?

我尝试将blockColors 设为[Serializefield],但它不起作用。 我以前从未尝试过为检查员编写图表。有人可以指导我看一个可以帮助我理解如何编写如图所示图表的教程吗?

【问题讨论】:

    标签: c# unity3d serialization multidimensional-array inspector


    【解决方案1】:

    感谢所有提供的答案,我想出了这个解决方案:

    Levels.cs

    using UnityEngine;
    
    public enum BlockColors {blank, red, blue, green, yellow, cyan, white, purple};
    
    [System.Serializable] public class level {
        #if UNITY_EDITOR
        [HideInInspector] public bool showBoard;
        #endif
        public int rows = 9;
        public int column = 9;
        public BlockColors [,] board = new BlockColors [columns, rows];
    }
    
    
    public class Levels : MonoBehaviour {
    
        public Level[] allLevels;
    
    }
    

    Editor/LevelEditor.cs

    using UnityEngine;
    using UnityEditor;
    
    
    [CustomEditor(typeof(Levels))]
    public class LevelEditor : Editor {
    
        public bool showLevels = true;
    
        public override void OnInspectorGUI() {
            Levels levels = (Levels)target;
            EditorGUILayout.Space ();
    
            showLevels = EditorGUILayout.Foldout (showLevels, "Levels ("+levels.allLevels.Length+")");
            if (showLevels) {
                EditorGUI.indentLevel++;
                for (ushort i = 0; i < levels.allLevels.Length; i++) {
    
                    levels.allLevels[i].showBoard = EditorGUILayout.Foldout(levels.allLevels[i].showBoard, "Board");
                    if (levels.allLevels [i].showBoard) {
    
                        EditorGUI.indentLevel = 0;
    
                        GUIStyle tableStyle = new GUIStyle ("box");
                        tableStyle.padding = new RectOffset (10, 10, 10, 10);
                        tableStyle.margin.left = 32;
    
                        GUIStyle headerColumnStyle = new GUIStyle ();
                        headerColumnStyle.fixedWidth = 35;
    
                        GUIStyle columnStyle = new GUIStyle ();
                        columnStyle.fixedWidth = 65;
    
                        GUIStyle rowStyle = new GUIStyle ();
                        rowStyle.fixedHeight = 25;
    
                        GUIStyle rowHeaderStyle = new GUIStyle ();
                        rowHeaderStyle.fixedWidth = columnStyle.fixedWidth - 1;
    
                        GUIStyle columnHeaderStyle = new GUIStyle ();
                        columnHeaderStyle.fixedWidth = 30;
                        columnHeaderStyle.fixedHeight = 25.5f;
    
                        GUIStyle columnLabelStyle = new GUIStyle ();
                        columnLabelStyle.fixedWidth = rowHeaderStyle.fixedWidth - 6;
                        columnLabelStyle.alignment = TextAnchor.MiddleCenter;
                        columnLabelStyle.fontStyle = FontStyle.Bold;
    
                        GUIStyle cornerLabelStyle = new GUIStyle ();
                        cornerLabelStyle.fixedWidth = 42;
                        cornerLabelStyle.alignment = TextAnchor.MiddleRight;
                        cornerLabelStyle.fontStyle = FontStyle.BoldAndItalic;
                        cornerLabelStyle.fontSize = 14;
                        cornerLabelStyle.padding.top = -5;
    
                        GUIStyle rowLabelStyle = new GUIStyle ();
                        rowLabelStyle.fixedWidth = 25;
                        rowLabelStyle.alignment = TextAnchor.MiddleRight;
                        rowLabelStyle.fontStyle = FontStyle.Bold;
    
                        GUIStyle enumStyle = new GUIStyle ("popup");
                        rowStyle.fixedWidth = 65;
    
                        EditorGUILayout.BeginHorizontal (tableStyle);
                        for (int x = -1; x < levels.allLevels [i].columns; x++) {
                            EditorGUILayout.BeginVertical ((x == -1) ? headerColumnStyle : columnStyle);
                            for (int y = -1; y < levels.allLevels [i].rows; y++) {
                                if (x == -1 && y == -1) {
                                    EditorGUILayout.BeginVertical (rowHeaderStyle);
                                    EditorGUILayout.LabelField ("[X,Y]", cornerLabelStyle);
                                    EditorGUILayout.EndHorizontal ();
                                } else if (x == -1) {
                                    EditorGUILayout.BeginVertical (columnHeaderStyle);
                                    EditorGUILayout.LabelField (y.ToString (), rowLabelStyle);
                                    EditorGUILayout.EndHorizontal ();
                                } else if (y == -1) {
                                    EditorGUILayout.BeginVertical (rowHeaderStyle);
                                    EditorGUILayout.LabelField (x.ToString (), columnLabelStyle);
                                    EditorGUILayout.EndHorizontal ();
                                }
    
                                if (x >= 0 && y >= 0) {
                                    EditorGUILayout.BeginHorizontal (rowStyle);
                                    levels.allLevels [i].board [x, y] = (BlockColors)EditorGUILayout.EnumPopup (levels.allLevels [i].board [x, y], enumStyle);
                                    EditorGUILayout.EndHorizontal ();
                                }
                            }
                            EditorGUILayout.EndVertical ();
                        }
                        EditorGUILayout.EndHorizontal ();
    
                    }
    
                }
            }
        }
    }
    

    我现在的主要问题是它不会序列化。我对关卡所做的任何更改都会在 Play 上自动重置。如何从 Inspector 序列化自定义数组设置?

    【讨论】:

    • 你试过用SetDirty()这个Levels Component吗?,SetDirty表示对象已经改变,会提示unity保存,否则你会看到(*)未保存的标志。我不知道unity是否支持序列化多维数组,但值得一试,你缺少SetDirty(),继续尝试。 docs.unity3d.com/ScriptReference/EditorUtility.SetDirty.html 每次更改时,调用 SetDirty。
    【解决方案2】:

    您需要创建一个自定义编辑器(或者更具体地说是 CustomPropertDrawer,如果您想将其重新用于其他组件

    创建这样的表格所需的唯一不明显的部分是强制元素按照您想要的方式布局。一种方法是手动处理 Unity 为您提供的位置 Rect,但有一种非常简单(尽管不太灵活)的方法,只需将元素包装在水平/垂直布局组合中即可。 直观的方法是将元素包装在

    GUILayout.BeginHorizontal();
    {
      // your elements line 1
    }
    GUILayout.EndHorizontal(); 
    GUILayout.BeginHorizontal();
    {
      // your elements line 2 and so on
    }
    GUILayout.EndHorizontal(); 
    

    但它有一个缺点 - 自动布局只会占用当前行中的元素宽度,但如果元素大小发生变化,这将破坏垂直对齐。一个解决方案是先将每一列包裹在一个布局中,而不是使用水平布局来组合垂直条,它是这样的

    GUILayout.BeginHorizontal();
    {
      GUILayout.BeginVertical();
      {
       // your elements column 1
      }
     GUILayout.EndVertical();
     GUILayout.BeginVertical();
     { 
       // your elements column 2
     }  
     GUILayout.EndVertical();
    }
    GUILayout.EndHorizontal(); 
    

    括号只是为了清楚起见,它们什么都不做。 我希望这会有所帮助

    【讨论】:

      【解决方案3】:

      您可以为您的类构建一个 CustomEditor 脚本,然后使用 GUI 显示您的多维数组,就像您编写普通 OnGUI 事件一样。

      这是一个简单的伪代码

      Loop for every Rows
         Divide inspector width with columns length;
         Loop for every Columns
             Render Custom Field with dividen width;
         End Loop
         Incrase posY for new rows ++;
      End Loop
      

      这里有一些链接可以帮助您入门

      https://docs.unity3d.com/Manual/editor-CustomEditors.html

      https://unity3d.com/learn/tutorials/topics/interface-essentials/building-custom-inspector

      【讨论】:

        【解决方案4】:

        感谢以上所有出色的答案。

        对于任何难以持久化自定义数组的人来说,一个问题是多维数组不可序列化。可能的解决方法包括将二维数组实现为锯齿状数组(元素为数组的数组)或创建一个本身可序列化的包装类。

        正如 endrik exe 所建议的,您还需要提示 Unity 使用 EditorUtility.SetDirty() 保存对对象的更改。将以下内容添加到 OnInspectorGUI() 的末尾应该可以解决问题:

        if (GUI.changed) {
            Undo.RecordObject(levels, "Edit levels");
            EditorUtility.SetDirty(levels);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-09-23
          • 2014-02-26
          • 2012-05-14
          • 1970-01-01
          • 1970-01-01
          • 2011-11-24
          相关资源
          最近更新 更多