Custom Editor Properties Revert to Defaults on Play

EDIT: I’ve more clearly figured out the problem, and made the code simpler to read.

I’m trying to create a manager class for flocking AI, so I can make one change and update every single member of the flock at once, rather than having to change the properties of every single member individually.

So I’ve got TestPropertyManager, which has an internal class called TestProperties. TestProperties is an internal class so that other internal classes can inherit from it in a way that mirrors the inheritance of the objects whose properties I’m managing.

using UnityEngine;
using System.Collections;

public class TestPropertyManager : MonoBehaviour
{
	public TestProperties TestManager = new TestProperties();
	
	public float TestA;
	public float TestB {get; set;}

            [System.Serializable]
	public class TestProperties
	{
		public float TestC;
		public float TestD {get;set;}
	}
}

Then I’ve got the custom inspector script, TestPropertyEditor, which just exposes the floats to the editor:

using UnityEditor;
using UnityEngine;

[CustomEditor (typeof(TestPropertyManager))]
public class TestPropertyEditor : Editor
{
	public override void OnInspectorGUI()
	{
		TestPropertyManager temp =	target as TestPropertyManager;
		
		temp.TestA = EditorGUILayout.FloatField("Test A", temp.TestA);
		temp.TestB = EditorGUILayout.FloatField("Test B", temp.TestB);
		
		temp.TestManager.TestC = EditorGUILayout.FloatField("Test C", temp.TestManager.TestC);
		temp.TestManager.TestD = EditorGUILayout.FloatField("Test D", temp.TestManager.TestD);
		
	}
}

The problem that I’m having with this system is that whenever I Play/Stop the game, the properties (TestB & TestD) revert to 0. The fields (TestA & TestC) retain the values they had in the editor. However, if I change TestA or TestC at runtime, then press Stop, they still revert to the values they had before pressing Play.

I also tried using SerializedProperty, but it had problems with the fact that Test belongs to TestManager, so I can’t access Test with serializedObject.FindProperty(string propertyPath). I also can’t get SerializedProperty to accept TestProperties, because it’s not a type that it recognizes.

So basically I need the floats to persist when I press Play/Stop.

Add this code at the end of OnInspectorGUI() in your editor class:

if(GUI.changed)
{
     EditorUtility.SetDirty( target );
}

Reference: EditorUtility.SetDirty

This is a better answer than my other one, because it retains the private accessibility of the fields using [SerializeField].

Here’s the updated version of TestPropertyManager that allows the property fields to persist on Play (although not on Stop):

using UnityEngine;
using System.Collections;

public class TestPropertyManager : MonoBehaviour
{
	public TestProperties TestManager = new TestProperties();
	public float TestA;
	
	[SerializeField]
	float _testb;
	
	public float TestB
	{
		get {return _testb;} 
		set {_testb = value;}
	}
	
	[System.Serializable]
	public class TestProperties
	{
		public float TestC;
		
		[SerializeField]
		float _testd;
		
		public float TestD
		{
			get{return _testd;}
			set
			{
				_testd = Mathf.Clamp(value, 0, UnityEngine.Mathf.Infinity);
			}
		}
	}
}

Notice the [SerializeField] attribute on the _testb and _testd fields. This allows Unity to retain their values while maintaining their private accessibility. I’m still using the same custom inspector script from the question.

Also, I’ve cast all my 3 votes for this feature request and would like to spread the word: If you also have this problem, go there and cast some votes.

Now the only problem is how to get those fields to persist on Stop. However, since this is a solution for one piece of the problem, I’m going to mark this question answered and start a new question.

Okay, half-success. Here’s the updated version of TestPropertyManager that allows the property fields to persist on Play (although not on Stop):

using UnityEngine;
using System.Collections;

public class TestPropertyManager : MonoBehaviour
{
	public TestProperties TestManager = new TestProperties();
	
	public float TestA;
            
	public float _testb;
	public float TestB
	{
		get {return _testb;} 
		set {_testb = value;}
	}
	
	[System.Serializable]
	public class TestProperties
	{
		public float TestC;
		
		public float _testd;
		public float TestD
		{
			get{return _testd;}
			set{_testd = value;}
		}
	}
}

Notice that TestB and TestD are accessing public fields _testb and _testd. This appears to be the only way to get Unity to not reset these fields when play is pressed. It’s not ideal, because I’d like those fields to be private, but since I’m using a custom inspector, I can hide them from the inspector, which will do for now. No-one else will be using this code for the moment.

Also, I’ve cast all my 3 votes for this feature request and would like to spread the word: If you also have this problem, go there and cast some votes.

Now the only problem is how to get those fields to persist on Stop. However, since this is a solution for one piece of the problem, I’m going to mark this question answered and start a new question.

After allot of trouble with that sort of problem this morning, I saw all I needed was to call serializedObject.Update and serializedObject.ApplyModifiedProperties at the start and end of OnInspectorGUI. It works on both Play/Stop.