- Home /
Custom Editor losing settings on Play
I think the behavior I'm seeing is a bug, but I thought I'd ask it here first in case I'm just missing something. When writing my custom editors, all of my changes are being discarded when I hit the "play" button for any object I need 'type' I need to instantiate. I'll keep the code simple:
First, I have a class called HiddenObject:
using UnityEngine;
using System.Collections;
public class HiddenObject {
public GameObject hiddenObj { get; set; }
}
Next, here's the script I'll attach to an object in my Scene:
using UnityEngine;
using System.Collections;
public class Inventory : MonoBehaviour {
public HiddenObject hiddenObject = new HiddenObject();
}
Finally, here's my custom editor script:
using UnityEngine;
using UnityEditor;
using System.Collections;
[CustomEditor(typeof(Inventory))]
public class InventoryEditor : Editor {
private Inventory _inv;
void Awake()
{
_inv = (Inventory)target;
}
public override void OnInspectorGUI()
{
_inv.hiddenObject.hiddenObj = (GameObject)EditorGUILayout.ObjectField("Hidden Object", _inv.hiddenObject.hiddenObj, typeof(GameObject), true);
if(GUI.changed)
EditorUtility.SetDirty(_inv);
}
}
When I click on my Object in the Scene Hierarchy I can see the Custom Inspector displaying properly and I can click on the Game Object Field and select something or drag a game object to it. This all works correctly.
The moment I click the "Play" button, it's all nulled out though. Clicking stop doesn't bring back my changes, everything has been nulled out.
I'm certain this has to do with the fact that I'm having to instantiate the HiddenObject (new HiddenObject()) but not exactly sure how else I'm supposed to do it. Am I missing something, or is this a bug?
Answer by Joshua Falkner · Apr 06, 2012 at 02:27 AM
Ok, I figured this out - it was a combination of two things. First (as Adamcbrz pointed out) I was missing [System.Serializable] in my custom class. The second thing I had wrong is that I didn't need to get; set; any of the variables in my class. Here's the final code that works. Hopefully this will help some of you:
Custom class:
using UnityEngine;
using System.Collections;
[System.Serializable]
public class HiddenObject {
public GameObject hiddenObj;
}
The Inventory Script:
using UnityEngine;
using System.Collections;
public class Inventory : MonoBehaviour {
public HiddenObject hiddenObject;
}
Custom Editor Script
using UnityEngine;
using UnityEditor;
using System.Collections;
[CustomEditor(typeof(Inventory))]
public class InventoryEditor : Editor {
private Inventory _inv;
void Awake()
{
_inv = (Inventory)target;
}
public override void OnInspectorGUI()
{
_inv.hiddenObject.hiddenObj = (GameObject)EditorGUILayout.ObjectField("Hidden Object", _inv.hiddenObject.hiddenObj, typeof(GameObject), true);
if(GUI.changed)
EditorUtility.SetDirty(_inv);
}
}
Answer by Adamcbrz · Apr 05, 2012 at 03:51 AM
Tim,
Look into http://unity3d.com/support/documentation/ScriptReference/Serializable.html For custom class you need to add this. I am not sure if you need this for both classes.
Hope this helps
Thanks for the tip, but adding this didn't change the behavior. I can also reproduce this behavior if I use a 2D array, so ins$$anonymous$$d of my custom class it would be:
public GameObject[,] myGO = new GameObject[4,4];
Figured out the issue and posted it as an answer. Thanks for helping guide me to it. Cheers!
Answer by Enderlook · Jun 05, 2019 at 10:49 AM
I know this is a very old post but I would like to share what it worked for me.
I made this method (you should put this inside the class you want to use it):
private void ChangeCheck<T>(Func<T> function, ref T field, string reason)
{
// https://docs.unity3d.com/ScriptReference/Undo.RecordObject.html
EditorGUI.BeginChangeCheck();
T value = function();
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, reason);
field = value;
}
}
Whenever the code (custom field) executed in func
is changed the values are stored. In the link inside the method, explains why I did that.
So, you could use this as:
ChangeCheck(() => (GameObject)EditorGUILayout.ObjectField("Hidden Object", _inv.hiddenObject.hiddenObj, typeof(GameObject), true), ref _inv.hiddenObject.hiddenObj, "Change Hidden Object");
Answer by keenanwoodall · Oct 11, 2014 at 04:02 AM
I've been working on an editor script and am coming up on the same issues. I've thoroughly looked through the formums and unityanswers but haven't figured it out. I've tried all of the Serializable stuff on just every variable in the problem but no luck.
DESTRUCTIONOBJECT.js
@SerializeField
var destroyedVersion : GameObject;
var destroyOn : DestroyMode;
enum DestroyMode{Collision, Play, Custom};
var collisionForce : float;
var nonRigidBodyCollision : boolean;
var impactForceMagnitude : float;
function Start ()
{
if(destroyOn == DestroyMode.Play)
Destroy();
}
function OnCollisionStay(col : Collision)
{
impactForceMagnitude = col.impactForceSum.sqrMagnitude;
if(destroyOn == DestroyMode.Collision)
if(nonRigidBodyCollision)
Destroy();
else if(!nonRigidBodyCollision)
if(col.rigidbody != null)
if(impactForceMagnitude > collisionForce)
Destroy();
}
function Destroy ()
{
Instantiate(destroyedVersion, transform.position, this.transform.rotation);
}
DESTRUCTIONOBJECTINSPECTOR.js
@CustomEditor(DestructionObject)
class DestructionEditor extends Editor
{
var shatterObject : GameObject;
var destroyMode : DestroyMode = DestroyMode.Collision;
var collisionForce : float;
var nonRigidBodyCollision : boolean;
function OnEnable ()
{
//shatterObject = target.shatterObject;
destroyMode = target.destroyOn;
collisionForce = target.collisionForce;
nonRigidBodyCollision = target.nonRigidBodyCollision;
}
function OnInspectorGUI ()
{
EditorGUILayout.BeginVertical();
EditorGUILayout.BeginHorizontal();
shatterObject = EditorGUILayout.ObjectField("Shattered Version: ", shatterObject, GameObject);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
destroyMode = EditorGUILayout.EnumPopup("Destroy On:", destroyMode);
EditorGUILayout.EndHorizontal();
if(destroyMode == DestroyMode.Collision)
{
EditorGUILayout.BeginHorizontal();
collisionForce = EditorGUILayout.FloatField("Minimum Collision Force", collisionForce);
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
nonRigidBodyCollision= EditorGUILayout.Toggle("Non-Rigidbody Collision?", nonRigidBodyCollision);
EditorGUILayout.EndHorizontal();
EditorGUILayout.LabelField("Impact Force: ", target.impactForceMagnitude.ToString());
}
else if(destroyMode == DestroyMode.Custom)
{
EditorGUILayout.LabelField("Call the 'Destroy' function to shatter this object.");
EditorGUILayout.LabelField("Example: ");
EditorGUILayout.LabelField("var destructionObject : DestructionObject; ");
EditorGUILayout.LabelField("function Start()");
EditorGUILayout.LabelField("destructionObject.Destroy();");
}
EditorGUILayout.EndVertical();
target.destroyedVersion = shatterObject;
target.destroyOn = destroyMode;
target.collisionForce = collisionForce;
target.nonRigidBodyCollision = nonRigidBodyCollision;
if(GUI.changed)
EditorUtility.SetDirty(target);
}
}
Answer by Alverik · Sep 01, 2016 at 05:14 AM
I was having the exact same issue, but it was happening on strings, floats, and well, everything. I fixed it by removing the script from the object and then putting it back in. My best guess is somehow the data saved went all wrong when I added the custom editor to my script, but who knows...
Your answer
Follow this Question
Related Questions
Instantiating and displaying enum objects using custom inspector 1 Answer
Show texture (image box) in inspector with custom editor [C#]? 3 Answers
Calling a custom inspector from an editor window of an instance of a class 1 Answer
Trying to create Custom Inspector Labels and I get erros 0 Answers
Multiple Cars not working 1 Answer