- Home /
Turn objects to/from Json for settings. Getting "{}" as output at the moment
I need to be able to save my game's settings to disk, so I'm going to serialize the settings object then save it to disk, and overwrite it at the game's startup. I've already tried Newtonsoft, and that either gives me a recursive loop error or causes the editor to crash when I click play (if I add a flag to serialize that loop). So far, the only output I get from JsonUtility.ToJson()
is "{}", no matter what sort of object I use. I really DON'T want to use PlayerPrefs, as that will
Make it harder for me to fix settings if I can't load the game
Make it impossible for players to edit settings
Make it a real pain in the butt to have to rewrite all of my code
Here's my code (very long, have removed some useless stuff):
[Serializable]
public class SingletonSettings : MonoBehaviour
{
#region This makes sure there aren't any other instances running
public static SingletonSettings Instance;
void Awake()
{
if (Instance == null)
Instance = this;
else
Destroy(gameObject);
}
#endregion
#region Initialise other classes
public static _Sensitivity Sensitivity = new _Sensitivity();
public static _Graphics Graphics = new _Graphics();
public static _Sound Sound = new _Sound();
public static _Input Input = new _Input();
static SingletonSettings test;
#endregion
void Start()
{
test = this;
Gameplay.Functions.HideCursor();
Gameplay.Functions.SetGameSpeed(1);
}
void FixedUpdate()
{
//Increase game time each tick
Gameplay.Functions.SetGameSpeed(Gameplay.Functions.GetGameTime() + 1);
Debug.Log(JsonUtility.ToJson(test));
}
}
[Serializable]
public class _Sensitivity
{
public float vertical = 1;
public float horizontal = 1;
}
[Serializable]
public class _Input
{
#region Keybindings
public KeyCode[] Forward = { KeyCode.W };
public KeyCode[] Back = { KeyCode.S };
public KeyCode[] Left = { KeyCode.A };
public KeyCode[] Right = { KeyCode.D };
public KeyCode[] Jump = { KeyCode.Space };
public KeyCode[] Crouch = { KeyCode.LeftControl };
public KeyCode[] Sprint = { KeyCode.LeftShift };
public KeyCode[] Fire = { KeyCode.Mouse0 };
public KeyCode[] SwapView = { KeyCode.F5 };
public KeyCode[] Menu = { KeyCode.Escape };
#endregion
#region GetKeyDown
private bool _GetKeyDown(KeyCode[] keys)
{
bool pressed = true;
foreach (KeyCode k in keys)
{
pressed = Input.GetKeyDown(k) ? pressed : false;
}
return pressed;
}
public bool GetKeyDown(KeyCode[] keys)
{
return _GetKeyDown(keys);
}
public bool GetKeyDown(KeyCode key)
{
KeyCode[] b = { key };
return _GetKeyDown(b);
}
#endregion
#region GetKeyUp
private bool _GetKeyUp(KeyCode[] keys)
{
foreach (KeyCode k in keys)
{
if (Input.GetKeyUp(k))
return false;
}
return true;
}
public bool GetKeyUp(KeyCode[] keys)
{
return _GetKeyUp(keys);
}
public bool GetKeyUp(KeyCode key)
{
KeyCode[] b = { key };
return _GetKeyUp(b);
}
#endregion
#region GetAxis
[SerializeField]
private Dictionary<KeyCode[], float> positiveLastVal = new Dictionary<KeyCode[], float>();
[SerializeField]
Dictionary<KeyCode[], float> negativeLastVal = new Dictionary<KeyCode[], float>();
private float _GetAxis(KeyCode[] positive, KeyCode[] negative, float smoothing = 10F)
{
smoothing = smoothing != 0 ? 1 / smoothing : 0;
float p = Convert.ToSingle(_GetKey(positive)), n = Convert.ToSingle(_GetKey(negative));
//If values do not exist in dictionary, add them
if (!positiveLastVal.ContainsKey(positive))
positiveLastVal.Add(positive, p);
if (!negativeLastVal.ContainsKey(negative))
negativeLastVal.Add(negative, p);
//If no smoothing, skip it
if (smoothing == 0)
{
positiveLastVal[positive] = p;
negativeLastVal[negative] = n;
}
else
{
positiveLastVal[positive] = Mathf.Lerp(positiveLastVal[positive], p, smoothing);
negativeLastVal[negative] = Mathf.Lerp(negativeLastVal[negative], n, smoothing);
}
//Load values from dictionary to variables
float pos = positiveLastVal[positive];
float neg = negativeLastVal[negative];
return pos - neg;
}
public float GetAxis(KeyCode[] positive, KeyCode[] negative, float smoothing = 10F)
{
return Convert.ToSingle(_GetAxis(positive, negative, smoothing));
}
public float GetAxis(KeyCode positive, KeyCode negative, float smoothing = 10F)
{
KeyCode[] a = { positive };
KeyCode[] b = { negative };
return Convert.ToSingle(_GetAxis(a, b, smoothing));
}
#endregion
#region GetKey
private bool _GetKey(KeyCode[] keys)
{
foreach (KeyCode k in keys)
{
if (!Input.GetKey(k))
return false;
}
return true;
}
public bool GetKey(KeyCode[] keys)
{
return _GetKey(keys);
}
public bool GetKey(KeyCode key)
{
KeyCode[] b = { key };
return _GetKey(b);
}
#endregion
}
If I serialize one of the objects inside, like Input
, then I get an output, but that is not what I would like. I would much prefer if there was a way to serialize Instance
instead
I suggest checking out Binary File Saves, you won't even need to serialize the data then which is an issue with JsonUtility as it is unable to serialize DateTime amoung other things (found out after much debugging and headaches).
I believe you won't be able to serialize SingletonSettings
simply because all the data inside this class is static (which does not make sense by the way since you have implemented the Singleton pattern... You may need to serialize the individual variables (`Sensitivity`, Graphics
, Sound
, Input
, ...) or remove the static
keyword.
Answer by Bunny83 · May 13, 2019 at 11:18 AM
There are several issues with your code. I'll only mention the most important
First of all, like Hellium mentioned already your SingletonSettings class instance doesn't contain any field at all. Static fields are never part of an instance. So if you want to have all the data serialized you have to use instance fields (so non static fields)
The next problem is that your SingletonSettings class is a MonoBehaviour derived class. When you want to deserialize such a class you can't use FromJson since such classes can't be created with new. You would need to use JsonUtility.FromJsonOverwrite on an existing instance. Though it's usually better to use an ordinary serializable class as root object for settings.
Finally you seem to have marked a Dictionary field with the SerializeField attribute. However Unity's JsonUtility doesn't support dictionaries as it has the same restrictions as Unity's normal serialization system. For more information see script serialization
I just tested some other stuff, and it turns out that I can serialize the Input
, Graphics
etc objects successfully. It's a bit of a hassle, but I can make it work. Thanks for the help anyway :)
Your answer
Follow this Question
Related Questions
Testing MonoBehaviours in a Package 0 Answers
onFilterAudioRead Problems 0 Answers
Parse JSON with LitJSON 2 Answers
how to integrate json rpc into unity? 1 Answer
Parsing Facebook graph JSON 1 Answer