Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Saving/loading data in Unity

I have been messing around with saving and loading in Unity in which I save a serialized class to a file. I have a Serializable class :

[Serializable]
class Save
{
    public List<int> ID = new List<int>();
    public List<int> Amounts = new List<int>();
}

and save it to a file A-OK. I can load it with no errors but if I wanted to add later :

[Serializable]
class Save
{
    public List<int> ID = new List<int>();
    public List<int> Amounts = new List<int>();
    public int extra = 0;
}

and I run my scripts it gives me a deserialization error which I completely understand as when I cast the deserialized file to my new class 'Saved' the new variable I added doesn't exist and it gives me the error.

I found this error when I was fixing an Asset in the store and I know one fix can be just change the filename so a new file is created but I don't just want to wipe the contents of what was saved before.

So my question is, if I wanted to add more variables to my serialized class how would I catch and adjust to old versions of it if people were to update the asset?

Thanks!

like image 380
JoeyL Avatar asked Oct 17 '16 04:10

JoeyL


People also ask

Where do Unity games save game data?

Where Are the Unity Save Files Located? While there is no universal save file location, the unofficial locations for Unity save games are all located by default in 'persistantDataPath,' in the application. If you are only using Unity PlayerPrefs, then the data will simply be in the registry.

How do you save Unity settings?

Unity categorises most save information into Scene changes and Project-wide changes. To save all Scene changes and Project-wide changes, go to File > Save (or Save as). This is the fastest way to save everything at once. To save Project-wide changes, but not Scene changes, go to File > Save Project.

How do you save a Prefs player?

In order to avoid this, PlayerPrefs has a handy method called “Save”. PlayerPrefs. Save(); does exactly what you think. It will save the PlayerPrefs to the disk without the need to quit the game.


1 Answers

This problem is known when using C# serializer. Convert the data to Json with JsonUtility then save it with the PlayerPrefs. When loading, load with the PlayerPrefs then convert the json back to class with JsonUtility.

Example class to Save:

[Serializable]
public class Save
{
    public List<int> ID = new List<int>();
    public List<int> Amounts = new List<int>();
    public int extra = 0;
    public float highScore = 0;
}

Save Data:

void Save()
{
    Save saveData = new Save();
    saveData.extra = 99;
    saveData.highScore = 40;

    //Convert to Json
    string jsonData = JsonUtility.ToJson(saveData);
    //Save Json string
    PlayerPrefs.SetString("MySettings", jsonData);
    PlayerPrefs.Save();
}

Load Data:

void Load()
{
    //Load saved Json
    string jsonData = PlayerPrefs.GetString("MySettings");
    //Convert to Class
    Save loadedData = JsonUtility.FromJson<Save>(jsonData);

    //Display saved data
    Debug.Log("Extra: " + loadedData.extra);
    Debug.Log("High Score: " + loadedData.highScore);

    for (int i = 0; i < loadedData.ID.Count; i++)
    {
        Debug.Log("ID: " + loadedData.ID[i]);
    }
    for (int i = 0; i < loadedData.Amounts.Count; i++)
    {
        Debug.Log("Amounts: " + loadedData.Amounts[i]);
    }
}

Difference between JsonUtility.FromJson and JsonUtility.FromJsonOverwrite:

A.JsonUtility.FromJson creates new Object from Json and returns it. It allocates memory.

string jsonData = PlayerPrefs.GetString("MySettings");
//Convert to Class. FromJson creates new Save instance
Save loadedData = JsonUtility.FromJson<Save>(jsonData);

B.JsonUtility.FromJsonOverwrite does not create new Object. It has nothing to do with adding more datatype to your class. It just overwrite the data that is passed in it. It's good for memory conservation and less GC. The only time it will allocate memory if when you have fields such as array, string and List.

Example of where JsonUtility.FromJsonOverwrite should be used is when performing constant data transfer with Json. It will improve performance.

//Create Save instance **once** in the Start or Awake function
Save loadedData = null;
void Start()
{
    //loadedData instance is created once
    loadedData = new Save();
}

void Load()
{
    string jsonData = PlayerPrefs.GetString("MySettings");
    //Convert to Class but don't create new Save Object. Re-use loadedData and overwrite old data in it
    JsonUtility.FromJsonOverwrite(jsonData, loadedData);
    Debug.Log("High Score: " + loadedData.highScore);
}
like image 199
Programmer Avatar answered Sep 28 '22 00:09

Programmer