问题
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?
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?
回答1:
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
回答2:
You can build a CustomEditor script for your class, and then display your multidimensional array using GUI, just like you code normal OnGUI event.
Here's a simple pseudo code
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
Here are some links that will help you get started
https://docs.unity3d.com/Manual/editor-CustomEditors.html
https://unity3d.com/learn/tutorials/topics/interface-essentials/building-custom-inspector
回答3:
Thanks to all the answers provided I have come up with this solution:
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?
回答4:
Thanks to all the excellent answers above.
For anyone having trouble persisting their custom arrays, one issue is that multidimensional arrays are not serializable. Possible workarounds include implementing your 2D array as a jagged array (an array whose elements are arrays) or creating a wrapper class that is serializable itself.
As endrik exe suggested, you'll also want to prompt Unity to save changes to your object using EditorUtility.SetDirty()
. Adding the following to the end of OnInspectorGUI()
should do the trick:
if (GUI.changed) {
Undo.RecordObject(levels, "Edit levels");
EditorUtility.SetDirty(levels);
}
来源:https://stackoverflow.com/questions/49353971/how-to-create-multidimensional-array-in-unity-inspector