Honkbark studios menu logo

Saving data in unity

Saving data in unity

Please share this post with your friends

This tutorial will cover how to save data to disk or device that can be loaded again after the game has been shutdown and restarted again.  You can download or clone this tutorial from this repository on Github.

This technique is used in Friendsheep.

1. Let’s begin with setting up the scene.
Start by adding a new Panel to the scene by Right clicking in the hierarchy and selecting UI -> Panel.

And in that panel lets create one Input field, one Text and one Button.
The scene will now look something like this:
Persistence-01

Github commit from step 1

 

2. Create an Empty Game object by right clicking in the Hierarchy and select Create Empty.
Name this new game object PersistenceManager
Select PersistenceManager and click on Add Component in the inspector.
Click on New Script and call it PersistenceManager, and use c sharp as language.

This is how the Hierarchy will look now:
Persistence-02

Github commit from step 2

 

3. Open the script that was just created in your editor. Mono develop is used by this tutorial.
This technique uses serialization to save a class to disk, so start by adding these using statements at the top of the PersistenceManager.cs class:


using System;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
Next add a static reference to a PerstenceManager called instance.

public class PersistenceManager : MonoBehaviour {

	public static PersistenceManager Instance;
}

Now lets add the Awake method from the unity lifecycle. And in this method we will first set an environment variable called MONO_REFLECTION_SERIALIZER, and then we will assign our Instance property to this

The MONO_REFLECTION_SERIALIZER is being set to make this work on iOS devices. The explanation can be found in this unity thread.

We set instance to this so that we will not get a null-reference when communicating with the PersistenceManager (more about this later on)

void Awake() {
    Environment.SetEnvironmentVariable("MONO_REFLECTION_SERIALIZER","yes");
    Instance = this;
}

Add a public method called Save that looks like this:

public void Save(IPersistence objectToSave) {
    BinaryFormatter formatter = new BinaryFormatter();
    FileStream file = File.Open(Application.persistentDataPath + "/" + objectToSave.FileName, FileMode.OpenOrCreate);
    formatter.Serialize(file, objectToSave);
    file.Close();
}

And another method for loading file:

public System.Object Load(string nameOfFile) {
    var serializedObject = new System.Object();
    if(File.Exists(Application.persistentDataPath + "/" + nameOfFile)) {
        BinaryFormatter formatter = new BinaryFormatter();
        FileStream file = File.Open(Application.persistentDataPath + "/" + nameOfFile, FileMode.Open);
        serializedObject = formatter.Deserialize(file);
        file.Close();
    }
    return serializedObject;
}

The full code in this class looks like this:

using UnityEngine;
using System.Collections;
using System;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

public class PersistenceManager : MonoBehaviour {
	
	public static PersistenceManager Instance;
	
	void Awake() {
		Environment.SetEnvironmentVariable("MONO_REFLECTION_SERIALIZER","yes");
		Instance = this;
	}
	
	public void Save(IPersistence objectToSave) {
		BinaryFormatter formatter = new BinaryFormatter();
		FileStream file = File.Open(Application.persistentDataPath + "/" + objectToSave.FileName, FileMode.OpenOrCreate);
		formatter.Serialize(file, objectToSave);
		file.Close();
	}
	
	public System.Object Load(string nameOfFile) {
		var serializedObject = new System.Object();
		if(File.Exists(Application.persistentDataPath + "/" + nameOfFile)) {
			BinaryFormatter formatter = new BinaryFormatter();
			FileStream file = File.Open(Application.persistentDataPath + "/" + nameOfFile, FileMode.Open);
			serializedObject = formatter.Deserialize(file);
			file.Close();
		}
		return serializedObject;
	}
}

However, this code won’t build yet, we need to add the another class. Let’s do that in step 4.

 

4. Add a file called IPersistence.cs anywhere in your project. Do not connect it to a Game Object.
Persistence-03

This is a rather small interface that we will use with the classes that we will save later. It should look like this:

public interface IPersistence  {
	string FileName {get;}
}

At this time the project builds and we can move on.

Github commit from step 3 and step 4

 

5. Add an empty GameObject to the hiearchy and call it PersistenceSceneController or any other name of your choice. It will take care of the button click and communicating with the PersistenceManager. Also connect a script to this new Game object (have a look at step 2 if you need assistance in doing this) and name this PersistenceSceneController also.Persistence-04

 

Open the file in your editor and start by adding a using statement:

using UnityEngine.UI;

Then continue by adding two public properties of the types Text and InputField and add an empty method called SaveInputFieldValue(); The class now looks like this:

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class PersistenceSceneController : MonoBehaviour {
	public Text Text;
	public InputField InputField;

	public void SaveInputFieldValue() {

	}
}

Now go back to unity and connect the InputField Game Object to the Input Field property and the Text Game Object to the Text property of the new script by dragging them from the hierarchy window to the Inspector when having PersistenceSceneController selected, resulting in this:
Persistence-05

Now select the Button in the hierarchy window and click on the plus sign in the On Click () tab.
Then drag the PersistenceSceneController from the hierarchy to where it says None (Object).
Now you get a dropdown that says no Function, select PersistenceController->SaveInputFieldValue();Persistence-06

Github commit from step 5

 

6. Now it’s time to create a class that will hold the data to save. Create a new C# script and call it HighScore. Then open it in an editor and make it look like this:

using System;

[Serializable]
public class HighScore : IPersistence {
	public int score;
	public const string NameOfFile = "highscore.dat";
	public string FileName {
		get {
			return NameOfFile;
		}
	}
}

We want this class to be Serializable, and to implement the IPersistence interface.
We’ve added a public int score to hold… the score.. and a NameOfFile property with the value highscore.dat so the persistence manager will know what to call the file on disc.
We also implement the interface by adding the FileName property.

Git commit from step 6

 

7.  Open PersistenceSceneController.cs in an editor. Lets begin with saving a value.
In the SaveInputFieldValye() method that was created earlier add the following:

public void SaveInputFieldValue() {
    var inputFieldValue = 0;
    if(int.TryParse(this.InputField.text, out inputFieldValue)) {
        this.SaveToDisc();
    }
}

This code checks so that a number has been entered in the InputField, if so call the method SaveToDisc(); which looks like this:

private void SaveToDisc() {
    var highScore = this.GetHighScoreFromField();
    PersistenceManager.Instance.Save(highScore);
}

the first line in this method calls the method GetHighScoreFromField() that returns an object of the HighScore class. That object is then sent into the Save() method of our PersistenceManager instance.

This is what GetHighscoreFromField looks like:

private HighScore GetHighScoreFromField() {
    var scoreFromInput = int.Parse(this.InputField.text);
    var highScore = new HighScore();
    highScore.score = scoreFromInput;
    return highScore;
}

It looks at the text property of the InputField, then instantiates a new HighScore();.
on the next line it sets the score property of highScore, and on the last line returning the highscore, giving us a class that looks like this:

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class PersistenceSceneController : MonoBehaviour {
	public Text Text;
	public InputField InputField;

	public void SaveInputFieldValue() {
		var inputFieldValue = 0;
		if(int.TryParse(this.InputField.text, out inputFieldValue)) {
			this.SaveToDisc();
		}
	}

	private void SaveToDisc() {
		var highScore = this.GetHighScoreFromField();
		PersistenceManager.Instance.Save(highScore);
	}

	private HighScore GetHighScoreFromField() {
		var scoreFromInput = int.Parse(this.InputField.text);
		var highScore = new HighScore();
		highScore.score = scoreFromInput;
		return highScore;
	}
}

Git commit from step 7

 

8. But what about loading that file when the game starts? Lets have a look at that now.
Fire up the editor once again (if you’ve closed it after finishing step 7) and add the Start() method from the unity monobehaviour lifecycle.

In start call a method that is called LoadHighScore()

in LoadHighscore() we call PersistenceManager.Instance.Load(Highscore.NameOfFile) to get a highscore object.

on the next line we check that it’s not null, which it would have been if we had no highscore file saved, and sets the text property of Text to the highscore.score property.

void Start() {
    this.LoadHighScore();
}

private void LoadHighScore() {
    var highscore = PersistenceManager.Instance.Load(HighScore.NameOfFile) as HighScore;
    if(highscore != null) {
        this.Text.text = highscore.score.ToString();
    }
}

Now the full class looks like this:

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class PersistenceSceneController : MonoBehaviour {
	public Text Text;
	public InputField InputField;

	public void SaveInputFieldValue() {
		var inputFieldValue = 0;
		if(int.TryParse(this.InputField.text, out inputFieldValue)) {
			this.SaveToDisc();
		}
	}

	private void SaveToDisc() {
		var highScore = this.GetHighScoreFromField();
		PersistenceManager.Instance.Save(highScore);
	}

	private HighScore GetHighScoreFromField() {
		var scoreFromInput = int.Parse(this.InputField.text);
		var highScore = new HighScore();
		highScore.score = scoreFromInput;
		return highScore;
	}

	void Start() {
		this.LoadHighScore();
	}

	private void LoadHighScore() {
		var highscore = PersistenceManager.Instance.Load(HighScore.NameOfFile) as HighScore;
		if(highscore != null) {
			this.Text.text = highscore.score.ToString();
		}
	}
}

Git commit from step 8

Categories: C#,Tutorial,Unity3D