- Home /
Why aren't my editor values saving when I press play?
I've read a lot of things online about how to fix this, but so far nothing has helped.
I'm trying to create a class that I do not want to inherit from MonoBehaviour since it should not be placed on a game object, but I still want to see and edit its values in the inspector. Here's a basic example:
using UnityEngine;
using System;
[Serializable]
public class Stats
{
public int health = 3;
public float speed = 5;
}
I've then created an instance of this Stats class in my "Character" class that is attached to the player's game object in Unity, serializing it so that it's shown in the inspector:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Character : MonoBehaviour
{
[SerializeField]
private Stats stats;
private void Start()
{
stats = new Stats();
}
}
This configuration successfully shows my Stats values in the inspector as part of the Character script. However, if I try to change a value in the inspector it is not saved on play, but rather reverts back to its default value ("3" for health, and "5" for speed). If I remove these default values in the Stats script then the values become "0" when pressing play.
Why is this happening, and how can I fix it? I am using a fresh install of Unity, but earlier this year I was working on another project with the same setup and did not have this issue at all, even though many of my scripts were configured this way.
If it helps, creating a variable in a Class that directly inherits from MonoBehaviour and marking it as serializable does not produce this problem. For example, this variable will be updated on play when changed in the inspector:
public class TestClass: MonoBehaviour
{
[SerializeField]
private string myName = "John";
}
After looking at this some more, it appears that the line
stats = new Stats();
may be the culprit. I'm not sure why this happens, though, so I would still appreciate if someone could help explain this to me.
You're creating a new Stats object in that line, using the default constructor. What would you expect its values to be, if not those that are set by the default constructor?
Changing the values in the Inspector before hitting play does work, it's just that you are explicitly throwing those values away!
Answer by MisteryJ · Nov 22, 2018 at 12:56 PM
Unity deserializes the field before Start().Then in Start(), you set the stats to a new Stats, so the value is reset.
Start() is not constructor. If you put the code "stats = new Stats()" into constructor, or in the declaration "private Stats stats = new Stats();", the problem is not going to occur. After all, it is unnecessary to new a Stats. Unity's deserialization does this for you.
Answer by Nazirzadeh · Nov 22, 2018 at 05:01 AM
Try this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Character : MonoBehaviour
{
[SerializeField]
private Stats stats;
[SerializeField]
private int Health;
[SerializeField]
private int Speed;
private void Start()
{
stats = new Stats(Health,Speed);
}
}
and
using UnityEngine;
using System;
[Serializable]
public class Stats
{
private int _health;
private float _speed;
public Stats(int health,int speed)
{
_health = health;
_speed = speed;
}
}
Answer by austinsun102 · Nov 22, 2018 at 04:53 AM
You can try to inheritance the class to ScriptableObject and create a ScriptableObject. Try looking into ScriptableObjects. I hope that helped.