Save System in Unity For Mobile Games
- santosh nalla
- Jan 18, 2021
- 7 min read
Updated: Jun 16, 2021
Save system work in different ways.
There are auto save system, when a game saves itself when you reach a certain check point and there are manual saves where you manually click on save button which saves the progress of your game.
Save system works different for different games.
Some save your data locally on your device. Here the progress is saved locally. What does this mean? This is device specific. You cannot install your game on some other device and expect to continue your game with the same progress.
Some save your data with cloud system. Cloud save allows you to continue progress of your game across multiple devices and is safer when compared to local save.
Some games are online only. Game is playable/Save system works online only. They have their own servers - You create your own account - save your progress there on their servers.
Ok now lets try to understand different save systems in Unity:
PLAYER PREFS:
It is build into Unity. Using Player Prefs to save your data is absolutely NOT SECURE. Unity doesn't recommend storing any important data in Player Prefs because user can easily edit those. So only the data with witch you are ok with tampering can be saved using Player Pref. For example: Screen Brightness, Volume, Sensitivity etc can be saved using Player Pref.
CUSTOM SAVES:
It is like reading/Writing files yourself on to a disk. This is what playerpref does but here in custom save, you have flexibility to choose your own format and structure(JSON,XML,BINARY... etc).
Before moving on to JSON, XML, BINARY formats to save data, lets talk about simplest file saving method.
Lets say i have a string "Santosh" and i need to save this on to a file.
//Including .IO is must
using System.IO;
public class SimplestFileSaving : MonoBehaviour
{
string _simplestToBeSavedData = "Santosh";
void Start()
{
//Writing text on a file
WriteIntoFile();
//Reading From Already Written File
ReadSavedDatFromFile();
}
void WriteIntoFile()
{
File.WriteAllText(Application.persistentDataPath + "/SimpleSaveText.txt", _simplestToBeSavedData);
}
void ReadSavedDatFromFile()
{
string _readData = File.ReadAllText(Application.persistentDataPath + "/SimpleSaveText.txt");
Debug.Log(_readData);
}
}
Application.PersistentDataPath = C:\Users\[user]\AppData\LocalLow\[company name] in windows
This is how we put a simple data on to a file.
In the above example i have just saved a string "Santosh" on to a file and read it. Thing are not always this simple right?
In a game there is huge structure of data which needs to be saved on to a file. Its not as simple as saving "Santosh" string. We need data to be structured and saved on to a file in a format which we want. This structured data must be saved on to a file in such a way that retrieving also becomes easy.
So now there there are many ways where we can structure our data store it on to a file.
JSON:
JSON is JavaScript Object Notification is a lightweight data interchange format.
It is easier for human to read/write and easier for machines to parse and generate.
Unity has some functions to quickly generate JSON and read it back.
JSON FORMAT:
{
string : value
}
Ex: {
name: "John",
age: 31,
city: "New York"
};lets suppose i created in the save data in the format:
public class DataToSave
{
public string Name;
public int Age;
public int YearOfBirth;
public string Note;
}My save data is in this structure.
Now to convert this/Save this in JASON format, and generate a JSON save file we need to follow the below steps:
Firstly convert the following data to string(JSONformatted string) - using the function ToJason()
[SerializeField] DataToSave _dataToSave; //Fill data in the inspector
string jsonString;
.
.
.
jsonString = JsonUtility.ToJson(_dataToSave);2. Now you have all the data you wanna store in the json string format(actual string datatype). Here it is time to generate json file(at above mentioned location)
File.WriteAllText(Application.persistentDataPath + "/JSONFormatSaveText.json", jsonString);Steps 1 and 2 generates a json file in that location.

We can use fromJason Function to retrive data from json string/File.
void ReadFromFileJSONFormat()
{
DataToSave _temp_DataToSave = JsonUtility.FromJson<DataToSave>(jsonString);
Debug.Log("Name:" + _temp_DataToSave.Name);
Debug.Log("Age:" + _temp_DataToSave.Age);
Debug.Log("YearOfBirth:" + _temp_DataToSave.YearOfBirth);
Debug.Log("Note:" + _temp_DataToSave.Note);
}
And lastly, instead of reading directly from jason string, lets first read a json file into jason string and then Debug those values using fromJason().
void ReadFromJSONFile()
{
//Reading json formated file into a string
string _readData = File.ReadAllText(Application.persistentDataPath + "/JSONFormatSaveText.json");
//Coverting that from json formated sting to class data
DataToSave _temp_DataToSave = JsonUtility.FromJson<DataToSave>(jsonString);
Debug.Log("Name:" + _temp_DataToSave.Name);
Debug.Log("Age:" + _temp_DataToSave.Age);
Debug.Log("YearOfBirth:" + _temp_DataToSave.YearOfBirth);
Debug.Log("Note:" + _temp_DataToSave.Note);
}
Here all we did was SERIALIZATION - Translating data objects into a format that can be stored and later reconstructed(Here in this case JASON).
Pros of using JSON format:
-> Readable
-> Flexible
-> Small File Size
Will explain the term Flexible later.
XML and Binary are other 2 we are going to discuss along with JSON.
XML:
-> Readable
-> Flexible
-> Large File size
XML:
XML is another formatting data structure we store and retrieve in files.
So here i am gonna explain data storing and reading to and from xml file.
Xml is software/Hardware independent tool for storing and transporting data. XML was designed to store and transport data and it was designed to be self-descriptive.
XML literally does nothing, it is just an information wrapped in tags.
And one most important thing to remember is XML doesn't have predefined tags.
Example of xml:
<Game category="Open World">
<title>Horizon Zero Dawn</title>
<company>Gorilla Games</company>
<year>2017</year>
<price>4000</price>
</Game>If i had to discuss what each line in an XML means, let me do that with an example:
<bookstore>
<book category="cooking">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="children">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="web">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore> bookstore is - ROOT ELEMENT
book, title, year, price, author are all - ELEMENTS
(An XML Element(book store, title, year, price)can contain text, attribute, other elements or mixtures of above)
"Everyday Italian", "Giada De", "2005" are all - TEXT which describes ELEMENT
category, lang are - ATTRIBUTES
(Attribute are designed to contain data related to specific element. Attribute values must be quoted)
Just remember there are no rules when to use attribute or when to use element. It all about you deciding how you structure your data.
Generic Structure:
<root>
<child>
<subchild>.....</subchild>
</child>
</root>Now that you have understood about XML, lets discuss this in terms of unity.
I have
[System.Serializable]
public class DataToSave_XML
{
public string Name;
public int Age;
public int YearOfBirth;
public string Note;
}to save.
Now to generate the xml file for this data, follow this steps.
[SerializeField] DataToSave_XML _dataToSave; //Fill up your data in the inspector
You need to first serialize the class
XmlSerializer serializer = new XmlSerializer(typeof(DataToSave_XML));2. Then create a StreamWriter classs object and mention the path where you wanna create XML file. This object is used to write on to an XML file.
StreamWriter _streamWriter = new StreamWriter(Application.persistentDataPath + "/XMLFileFormatSacer.xml");
3. Then you serialize the data on to the xml file.
serializer.Serialize(_streamWriter.BaseStream, _dataToSave);using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System.Xml.Serialization;
[System.Serializable]
public class DataToSave_XML
{
public string Name;
public int Age;
public int YearOfBirth;
public string Note;
}
public class XMLFormatFileSaving : MonoBehaviour
{
[SerializeField] DataToSave_XML _dataToSave;
void Start()
{
XmlSerializer serializer = new XmlSerializer(typeof(DataToSave_XML));
StreamWriter _streamWriter = new StreamWriter(Application.persistentDataPath + "/XMLFileFormatSacer.xml");
serializer.Serialize(_streamWriter.BaseStream, _dataToSave);
}
}O/P:
XMLFileFormatSacer.xml
<?xml version="1.0"?>
-<DataToSave_XML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Santosh</Name>
<Age>25</Age>
<YearOfBirth>1995</YearOfBirth>
<Note>Hello Beautiful People</Note>
</DataToSave_XML>
Now that you have learnt about structuring xml data, you can have more control over xml data with XML attributes.
[XmlElement]
[XmlAttribute]
[XmlIgnore]
[XmlRoot]
[XmlArray]
[XmlArrayItem]
These are self explanatory which can be easy understood by below example and output.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System.Xml.Serialization;
[System.Serializable]
[XmlRoot("BookStore")]
public class BookStore
{
[XmlElement("Book")]
public Book Book;
}
[System.Serializable]
public class Book
{
[XmlAttribute("Category")]
public string BookCategory;
[XmlAttribute("Language")]
public string BookLanguage;
[XmlElement("Title")]
public string TitleOfBook;
[XmlElement("Author")]
public string BookAuthor;
[XmlElement("Year")]
public int YearOfPub;
[XmlElement("Price")]
public int BookPrice;
}
public class XMLFormatFileSaving : MonoBehaviour
{
[SerializeField] BookStore _dataToSave;
void Start()
{
XmlSerializer serializer = new XmlSerializer(typeof(BookStore));
StreamWriter _streamWriter = new StreamWriter(Application.persistentDataPath + "/XMLFileFormatSacer.xml");
serializer.Serialize(_streamWriter.BaseStream, _dataToSave);
}
}
O/P:
<?xml version="1.0"?>
-<BookStore xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <Book Language="English" Category="Horror">
<Title>Pet Sematary</Title>
<Author>Stephen King</Author>
<Year>1986</Year>
<Price>216</Price>
</Book>
</BookStore>BINARY FORMATTING:
Now that we have discussed about json and xml in detail - the last one we are going to talk about in this blog is saving data in the form of Binary file format.
The serialization and deserialization parts are very similar to xml. I will directly put the code which is self explanatory.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System;
[System.Serializable]
public class PlayerStats
{
public string PlayerName;
public int PlayerLevel;
public string PlayerHealth;
public string PlayerDamage;
public string PlayerLives;
}
public class BinaryFormating : MonoBehaviour
{
[SerializeField] PlayerStats _dataToSave;
[SerializeField] public string _fileName;
[HideInInspector]
public string consoleException;
public bool WriteIntoBinaryFile_Serialize()
{
try
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
FileStream stream = new FileStream(Application.persistentDataPath + "/" + _fileName + ".lol", FileMode.Create);
binaryFormatter.Serialize(stream, _dataToSave);
stream.Close();
return true;
}
catch(Exception e)
{
consoleException ="SAVE FAILED" + "\n" + "\n" + "REASON: " + e.Message;
return false;
}
}
public string ReadFromBinaryFile_Deserialize()
{
try
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
FileStream stream = new FileStream(Application.persistentDataPath + "/" + _fileName + ".lol", FileMode.Open);
PlayerStats _data = (PlayerStats)binaryFormatter.Deserialize(stream);
string returnString = "PlayerName: " + _data.PlayerName + "\n" + "PlayerLevel: " + _data.PlayerLevel + "\n" + "PlayerHealth: " + _data.PlayerHealth + "\n" + "PlayerDamage: " + _data.PlayerDamage + "\n" + "PlayerLives: " + _data.PlayerLives + "\n" + "\n" + "\n" + "PATH: " + Application.persistentDataPath + "/" + _fileName + ".lol";
stream.Close();
return returnString;
}
catch(Exception e)
{
consoleException = "LOAD FAILED" + "\n" + "\n" + "REASON: " + e.Message;
return consoleException;
}
}
}Now that we have learnt xml, json, Binary and Playerprefs - lets see pros and cons of each type so that you can decide what suits better for your needs.
JSON - Readable, Flexible(you can add fields/remove fields at will for your updates and doesn't break,if you remove a variable and deserialize to the same class it works ) , Small FileSize(least among 3)
XML - Readable, Flexible, Large File Size
Binary - NOT Readable, NOT Flexible(if you remove a variable and deserialize to the same class it wont really work) , Small File Size.
Binary cannot serialize Vector data type but XML and JSON can
Data Security:
Security is the real concern for our saved data. What if our user goes and modifies our saved file??
Lets take this saved json file:
{
name: "John",
age: 31,
city: "New York"
};what if the user goes and modifies the age to 55??
So for this matter security is really important for our data.
One way to protect this by hashing.
Here we add a variable called "hashvalue". This hashvalue is a unique value which is calculated based on all data content.
public class SaveData
{
public string name;
public int age;
public string city;
public string hashValue; (This value is calculated with name, age and city- using some algo)
}
Next time you are getting this name,age and city value to your game, you compare hashvalue. If this hashvalue doesn't match that means user has modified your data.
So why hash?
It is first line of defence
Easy to implement
But yes anyone online can decode your hashvalue aglorithm. so yes just a first line of defence.
Save Frequency:
Reading and writing from disk is an expensive operations. So you can use monobehaviour function like OnApplicationpause/OnApplicationQuit, have checkpoints, have save buttons or timer based save. You can decide for your game the frequency of saving your data.
Remember some basic rules:
Do not save every second. This can cost user data usage(if you are talking about online save (could or custom servers save)
Do not save every frame. because Read/Write operations on to the disk are expensive/slow.




Comments