I have been trying to figure out why Unity resets any variables sitting in a class to the default at runtime. What I am doing is enclosing some values in classes to aid in keeping my code clean, but this is killing it. By the way, I have no idea how to make classes serializable even when adding [System.Serializable] before the class declaration. So in order to expose it, I am using an editor extension.
I have written two demo scripts to demonstrate this. In the scripts I test to see what values persist, and what values reset from a value in the actual object, a value in the object’s editor file, a value in a class and a value in a class whose declaration sets the value. The only value that retains after running the application is the one inside of the actual object.
TheObject.cs
using UnityEngine;
using System.Collections;
public class TheObject : MonoBehaviour {
public ClassTest test1 = new ClassTest();
public ClassTest test2 = new ClassTest(3.21f);
public float aFloatNumber = 1.5f;
public class ClassTest{
public float classFloat = 1.23f;
public ClassTest(){}
public ClassTest(float _newVal){
classFloat = 1.23f;
}
}
}
TheObjectEditor.cs
NOTE: If you are testing this yourself, remember that this file needs to be placed in the Editor folder that exists in the root of the project.
using UnityEngine;
using UnityEditor;
using System.Collections;
[CustomEditor(typeof(TheObject))]
public class TheObjectEditor : Editor {
float editorFloat = 2.5f;
public override void OnInspectorGUI(){
TheObject mTarget = (TheObject)target;
editorFloat = EditorGUILayout.FloatField("Editor Float", editorFloat);
mTarget.aFloatNumber = EditorGUILayout.FloatField("A Float Number", mTarget.aFloatNumber);
EditorGUILayout.Space();
mTarget.test1.classFloat = EditorGUILayout.FloatField("Test 1 Value", mTarget.test1.classFloat);
mTarget.test2.classFloat = EditorGUILayout.FloatField("Test 2 Value", mTarget.test2.classFloat);
}
}
So, this is what happens. When I add TheObject to a game object, the values are:
Editor Float: 2.5
A Float Number: 1.5
Test 1 Value: 1.23
Test 2 Value: 1.23
Then I change these default values all to the same value such as 5.55. Once I click the run button, all of them reset to the default value except for ‘A Float Number’ which is the value that is stored inside of the actual object itself.
Does anyone know how or if I can get this to persist at least the variables stored in a class?
Well for one you probably want classFloat = _newVal; here
But AFAIK the reason why that’s happening is because when the game runs TheObject component is getting instantiated and subsequently the ClassTest objects are as well.
All you would need to do to get that code working is to scrap the editor script entirely and add
[System.Serializable]
before declaring ClassTest
But I actually do want to make my own editor script for this particular component because it is quite large and I want it to be organized nicely. I have tried to use [System.Serializable] on classes before with no luck with getting it in the editor. Even adding it to the class, the instance of the class and the variables inside with no luck. Maybe I screwed something up that time though. I’m not sure.
Anywho, I think it’s a shame that it isnt working. I might just submit a bug report and hope that they change it in a future build. For now I guess I am stuck with flooding that one script with all of those variables sans class(y) organization
The System.Serializeable attribute is required for the class like mentioned, but only public fields get serialized by default.
You can try using [UnityEngine.SerializeField] for protected, internal, or private fields though i’m not positive they work outside of UnityEngine.Object.
The other option you have is to inherit UnityEngine.ScriptableObject if you think you’d use things like Destroy. I havn’t used the editor classes much but i would think you could make a custom editor for a class type whether or not it implements UnityEngine.ScriptableObject
Antitheory and BDev, you actually were right. I think what I was doing wrong before is that I was using UnityEngine.Seralizable instead of System.Serializable. BUT for some reason in my dot operator, the exact item is “[System.SerializableAttribute]” I popped it in right before the class and it worked like a charm, and of course works just fine with the custom editor. For anyone wondering, here is the script as it stands in working condition.
using UnityEngine;
using System.Collections;
public class TheObject : MonoBehaviour {
public ClassTest test1 = new ClassTest();
public ClassTest test2 = new ClassTest(3.21f);
public float aFloatNumber = 1.5f;
[System.SerializableAttribute]
public class ClassTest{
public float classFloat = 1.23f;
public ClassTest(){
}
public ClassTest(float _newVal){
classFloat = _newVal;
}
}
}
The only value that does not retain its value is the editor based script, so clearly that is something to avoid. Thanks guys.