- Home /
OnInspectorGUI changes reset when played in editor or building
I've created a custom inspector for a tile-based system I'm working on. The target's layout (the number and orientation of the tiles it takes up) is represented as a 2D list of boolean values (eg List<List<bool>>
). The new inspector appears to work fine, adding and removing columns and rows as expected. If I go between an prefab with a MyClass MonoBehaviour and some other object, the layout values remain as expected. Pressing play or initiating a build, however, causes the values to get reset to the default. Am I wrong in believing that EditorUtility.SetDirty (target)
should cause these values to be set in the target MonoBehaviour. Why does playing the scene cause the values to be reset?
using UnityEditor; using UnityEngine; using System.Collections.Generic;
[CustomEditor (typeof(MyClass))] public class FurnitureEditor : Editor {
public override void OnInspectorGUI ()
{
MyClass tile = target as MyClass;
DrawDefaultInspector ();
EditorGUILayout.Separator ();
GUILayout.Label ("Layout");
EditorGUILayout.BeginHorizontal ();
if (GUILayout.Button ("Add Row"))
{
tile.layout.Add (new List<bool> ());
for (int i = 0; i < tile.layout[0].Count; i++)
{
tile.layout[tile.layout.Count - 1].Add (false);
}
}
if (GUILayout.Button ("Add Column"))
{
foreach (List<bool> boolList in tile.layout)
{
boolList.Add (false);
}
}
EditorGUILayout.EndHorizontal ();
EditorGUILayout.BeginHorizontal ();
if (tile.layout.Count == 1)
{
GUI.enabled = false;
}
if (GUILayout.Button ("Remove Row"))
{
tile.layout.Remove (tile.layout[tile.layout.Count - 1]);
}
GUI.enabled = true;
if (tile.layout[0].Count == 1)
{
GUI.enabled = false;
}
if (GUILayout.Button ("Remove Column"))
{
foreach (List<bool> boolList in tile.layout) {
boolList.Remove (boolList[boolList.Count - 1]);
}
}
GUI.enabled = true;
EditorGUILayout.EndHorizontal ();
for (int row = 0; row < tile.layout.Count; row++)
{
EditorGUILayout.BeginHorizontal ();
for (int col = 0; col < tile.layout[row].Count; col++)
{
if (row == 0 && col == 0)
{
//Must always take up at least one square.
tile.layout[row][col] = EditorGUILayout.Toggle (true);
}
else
{
tile.layout[row][col] = EditorGUILayout.Toggle (tile.layout[row][col]);
}
}
EditorGUILayout.EndHorizontal ();
}
if (GUI.changed)
{
EditorUtility.SetDirty (target);
}
}
}
As it seems no one has an answer, I've filed a bug on this issue. If there turns out to be a workaround or it's confirmed to work in a future version of Unity, I'll update with an answer.
"Why does playing the scene cause the values to be reset?" I'm having the same problem, but not using an editor GUI script. $$anonymous$$y script takes the gameObject and resizes it. Works perfectly in the editor, but then when I run the game (from the editor) it calls that routine again, and changes the size. There's nothing in the Awake or Start functions. I even tried storing a variable that tells whether or not the resizing routine was called, and not calling it (again) if it already was, but it seems like that's getting reset as well.
Anyone know why variables are reset or routines are run twice when creating an object and then running the app?
Answer by edwood_grant · Jul 28, 2010 at 11:03 PM
I think EditorUtility.SetDirty(target)
only sets changes of attributes that are being serialized.
A possible answer to this is that you have to set the [SerializeFiled]
tag in each field of the class (Myclass in this case) you want to serialize in the inspector.
In this case I suppose it would be
[SerializeField]
private List<List<bool>> layout = new List<List<bool>>();
If you are using DrawDefautlInspector()
and don't want the private item to show, you can add HideInInspector
to hide it.
[SerializeField, HideInInspector]
private List<List<bool>> layout;
Putting it this way make Unity understand that this attribute must be serialized, and not shown in the inspector (altough that double list is not standard for unity, so probably it wont be shown either).
Another possible problem is that you may be making some "reintialization" of the code somewhere in your MyClass script, try to check that out (Maybe in Start()
or Awake()
).
A third possible solution is to enable the tag [ExecuteInEditMode()]
in Myclass, to guarantee that the first true intialization takes place in the editor, and not when you play the game.
[ExecuteInEditMode()]
public class MyClass : MonoBehaviour
{
...
}
I hope this will help you. Italo F. Capasso B. AKA "Edwood Grant"
EDIT
Upong checking it further, it seems that List<List<bool>>
cannot be serialized. So you must create another type of structure. For example a serialized class that contains a serialized list. (Usgin either public varsiables, or setting [SerializeField]
on private variables.
[System.Serializable] public class Row { public List<Bool> value = new List<Value>(); }
public class MyClass : MonoBehaviour { public List<Row> columns = new List<Row>(); }
This should definetly work, and it wil even be shown in the default inspector with DrawDefautlInspector()
Italo F. Capasso B. AKA "Edwood Grant"
Thanks for your suggestions. SerializeField and ExecuteInEdit$$anonymous$$ode didn't seem to work, sadly. I don't think it's a problem in Start/Awake, because the reset happens even to prefabs in the project pane as soon as I hit play (even if it's an empty scene).
Well I've been cheking by myself, and it looks like List cannot be serialized, you will have to use another kind of construct to make that work... I managed to do it by creating a serializable class that contains bool list, and then create another list in $$anonymous$$yClass that contains the list of that class
Huh. That's an onerous way of having to go about it, but thanks! If you'd care to type that up in an answer, I'd like to mark it as answered appropriately.
I was having a similar issue. SetDirty worked for me. Thanks edwood.
After trying multiple solutions from SetDirty() to EndChangeCheck() to System.Serializable, this is finally the solution that fixed it. Thanks!
Answer by Lucas Meijer 1 · Sep 11, 2010 at 08:51 PM
I'll bite :), List> cannot be serialized.
I'd need to check, but I think we fixed this for Unity3.
[SerializeField, HideInInspector] Dude you save me..... Genius
Your answer
Follow this Question
Related Questions
Script to create instance from in inspector 2 Answers
How can i get SerializedProperty from UnityEvent which in List. Sorry for my Eng. 2 Answers
How can I recreate the Array Inspector element for a custom Inspector GUI? 7 Answers
How to record hideFlags for Undo/Redo 0 Answers
Custom Inspector (Editor) - override just one field control 1 Answer