如何在Unity Inspector中创建多维数组?

时间:2018-03-18 23:42:02

标签: c# unity3d serialization multidimensional-array inspector

如何在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中创建表格以加快工作流程?

enter image description here

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

4 个答案:

答案 0 :(得分:1)

您可以为您的类构建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

答案 1 :(得分:1)

您需要创建一个自定义编辑器(如果您想将其重新用于其他组件,则更具体地说是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(); 

支架只是为了清晰起见,它们什么都不做。 我希望这有帮助

答案 2 :(得分:1)

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

enter image description here

  

<强> 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;

}
  

<强>编辑/ 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序列化自定义阵列设置?

答案 3 :(得分:0)

感谢上面的所有优秀答案。

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

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

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