- Home /
Serialize custom multidimensional array from Inspector
I made this custom script Editor for a multidimensional array but I can't serialize it. Any change I made to the array will automatically reset on Play. How can I serialize the custom array setup from the Inspector?
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 [collumns, 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].collumns; 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 ();
}
}
}
}
}
Answer by savagecodes · Mar 27, 2018 at 05:37 AM
Hi, You could use an array of 1 dimension.
To set or get data in the array you must use the following
//Create the 1-dimensional array that will represent the 2d array
public BlockColors [] board = new BlockColors [collumns * rows];
//Translate the index [x, y] to the index in the 1D array
//Where x and y represent indexes, and width, the width of the matrix
board[x + y * width]
I hope it helps you
I can do that as an alternative but I’m wondering how to serialize arrays via scripts from the editor
Hello, am I missing something? board[x + y * width]
only works for the first row/column after that if falls apart?
example
row: 2 column: 2 width: 5
those above values would return an index of 20 where as the actual index of that item if they're in order would be 12?
pretty sure multiplication is still done before + or - so x + (y * width)
is still 12..?
You seem to confuse your values. If you had an 2 dimensional array with the x dimension having a length (width) of 5 then the value of 12 is correct. However if you have an array with a width of 9 (like in the question above) of course you get 20. Since width is 9 you get 2*9 + 2 == 20. Here are two examples:
// A 9x7 array, so width is 9 and height is 7
// | 0 1 2 3 4 5 6 7 8
// --+----------------------------
// 0 | 0 1 2 3 4 5 6 7 8
// 1 | 9 10 11 12 13 14 15 16 17
// 2 | 18 19 20 21 22 23 24 25 26
// 3 | 27 28 29 30 31 32 33 34 35
// 4 | 36 37 38 39 40 41 42 43 44
// 5 | 45 46 47 48 49 50 51 52 53
// 6 | 54 55 56 57 58 59 60 61 62
// A 5x6 array, so width is 5 and height is 6
// | 0 1 2 3 4
// --+----------------
// 0 | 0 1 2 3 4
// 1 | 5 6 7 8 9
// 2 | 10 11 12 13 14
// 3 | 15 16 17 18 19
// 4 | 20 21 22 23 24
// 5 | 25 26 27 28 29
In your example you have row index 2 and column index 2 (so the 3rd value in the 3rd row) or an array which has a width of 5. Your values 2*5 + 2 come out as 12, just as it should be.
If you're looking for the index of a cell in an array with width 9 (like in the OP) the index of cell [2, 2]
is 20 (== 2*9 + 2)
Thanks, I was doing the addition before the multiplication, brain fart on my end :s
Also, now written in for loops for row and columns and use an index count.
I might rewrite.. it was for this, pretty much the same problem and solution as the OP
Answer by Firas4d · Mar 27, 2018 at 08:15 AM
Unity couldn't by default serialize 2 dimensional arrays. What you have to do is to create your own serializable data structure that represents a 2D array and show it on inspector like you did with your custom editor script. Also keep in mind that MonoBehaviours always reset on play unlike ScriptableObjects.
I'd recommend creating a serializable container class that has a 1-D array that is marked with [SerializeField] attribute and then create another serializable class that contains a one dimensional array of the type you just created and mark it with [SerializeField], so now you have a class that contains an array of a class that contains an array! this way unity knows how to serialize this data structure.
Then all you have to do is to create a class that inherits from ScriptableObject then add the data structure type you created and save that as an asset.
https://unity3d.com/learn/tutorials/modules/beginner/live-training-archive/scriptable-objects
I hope this helped :)
Answer by CaJerry87 · Sep 14, 2019 at 05:45 AM
Have you considered making your changes INGAME and creating a save function? I didn't even look at much of the code but that was just an idea. That looks like a mixer board to me and all I can think of is you trying to change and save the mixer on the back end. That would require merging your editor with unity. Creating a save file would allow you to set those when you hit play, then hit save, and they will bounce back when you hit play no problem.
Your answer
Follow this Question
Related Questions
Saving editor-only variables 0 Answers
Distribute terrain in zones 3 Answers
How do I assign 3 variables to every GameObject in the array "enemy"? 2 Answers
Custom editor for inherited class but is not MonoBehaviour or ScriptableObject 1 Answer
Displaying System.objects not serialized by Unity in a Custom Editor 0 Answers