Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create multidimensional array in Unity Inspector?

Tags:

How does one create an enum multidimensional array in Unity Inspector and make it serializable so I can call it from a different script?

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];
}

For me to manually type all 28 colors in the script is time consuming, especially, when I have to do this for hundreds of levels. Is there a way to create a table in the Inspector to make workflow faster?

enter image description here

I tried making blockColors a [Serializefield] but it doesn't work. I've never tried coding a chart for the inspector before. Can someone please direct me to a tutorial that can help me understand how to code a chart like in the picture?

like image 437
user1105430 Avatar asked Mar 18 '18 23:03

user1105430


2 Answers

Thanks to all the answers provided I have come up with this solution:

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;

}

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 ();

                }

            }
        }
    }
}

My main problem now is it won't serialize. Any change I made to the level will automatically reset on Play. How can I serialize the custom array setup from the Inspector?

like image 154
user1105430 Avatar answered Sep 19 '22 12:09

user1105430


You need to create a custom editor (or more specifically CustomPropertDrawer if you want to re-use it for other components

The only non-obvious part required to create a table like that is forcing the elements to lay out the way you want. One way is manually handling position Rect's given you by Unity, but there is a much simple (albeit a bit less flexible) way, just wrap your elements in horizontal/vertical layout combos. The intuitive approach would be to wrap your elements in

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

but it has a downside - autolayout will only take widts of elements in a current line, but if element size varies this will break vertical alingment. A solution is to wrap each column in a layout first, and than use the horizontal layout to combine vertical strips, it goes like this

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

Brackets are just for clarity, they do nothing. I hope this helps

like image 33
zambari Avatar answered Sep 23 '22 12:09

zambari