Home
FAQ
Contact
About us
Blog
Home FAQ Contact About us Blog Pixel
Save player data in Unity - 22.08.2019
blog post cover

Do you want to save and load player data in your Unity project? There are several ways to implement this type of functionality, fx PlayerPrefs or by using a SQL database and access it via an API. This tutorial will focus on explaining how to get started using the persistence data system.

Let's jump right into it! 
Create a script called DataManager.cs:

public class DataManager : MonoBehaviour
{

}

Declare another class below called PlayerData which doesn't derive from MonoBehaviour.

[System.Serializable]
public class PlayerData
{

}

It's important to remember the [System.Serializable] tag on our PlayerData class because we are going to serialize an instance of it later. As an example, let's say our player can gather some points in our game and we want to save that. Declare a public float inside the PlayerData class called points.

[System.Serializable]
public class PlayerData
{
    public float points;
}

It's important the variable is public in order to access it from another class and since we are going to use it in our DataManager, this is necessary. Move back to the top of DataManager.cs and include these two needed namespaces below "Using UnityEngine;"

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

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

public class DataManager : MonoBehaviour
{

}

We are going to need some functions within these namespaces. But before we do that, let's declare 2 new variables inside DataManager.cs and declare the location of our data file inside a Start() function:

public class DataManager : MonoBehaviour
{
private string fileName = "/profileData.dat";
    private string fullPath;

void Start () {
        fullPath = Application.persistentDataPath + fileName;
}
}

Application.persistentDataPath contains a path to a persistent data directory and we need it to tell our script where to save and load our data. Now let's create two new functions called Save() and Load() below our Start() function and run the Load() function within Start():

public class DataManager : MonoBehaviour
{
private string fileName = "/profileData.dat";
    private string fullPath;

void Start ()
{
        fullPath = Application.persistentDataPath + fileName;
Load();
}

public void Save ()

    }

    private void Load ()
{

    }
}

We declare Save() as public so we can save data whenever we need it and we declare Load() as private since we most likely only are going to use it whenever we load the scene containing our DataManager's GameObject. Before we write the code for Save() and Load(), we need to declare a PlayerData variable inside our DataManager which will contain our data after loading it. Let's call it data.

public class DataManager : MonoBehaviour
{
private string fileName = "/profileData.dat";
    private string fullPath;

    public PlayerData data; // Access this variable to modify and read player data after loading it.

void Start ()
{
        fullPath = Application.persistentDataPath + fileName;
Load();
}

public void Save ()
{

    }

    private void Load ()
{

    }
}

We are now ready to write our Save() and Load() functions. Add these 4 lines to our Save() function:

public void Save ()
{
    FileStream file = File.Create(fullPath);
    BinaryFormatter bf = new BinaryFormatter();

    bf.Serialize(file, data);
    file.Close();
}  

In the first line above, we create or overwrites a file in the given path(fullPath) and save an instance of it to the local variable "file". We declare an instance of the BinaryFormatter afterward, serialize the data to the file and close it again. Want to know more about FileStream or BinaryFormatter?

This is really everything we need to save data. Let's move on to Load() and add the following:

private void Load ()
{
if (!File.Exists(fullPath)) {
return;
}

    FileStream file = File.Open(fullPath, FileMode.Open);
    BinaryFormatter bf = new BinaryFormatter();
    data = (PlayerData)bf.Deserialize(file);
    file.Close();
}

First, we return at the beginning of the function if the file doesn't exist, since there would be no file to write the data inside and therefore no reason to run the following code. As within our Save() function, we use FileStream to access a file, but in this case, we use File.Open instead of File.Create, we deserialize the file as PlayerData to our data variable and close the file.

That's it! We now have everything we need to save and load data. Just add DataManager as a component to an empty gameObject inside your Unity scene and add a reference to it somewhere in your code where you like to modify the data. 

I like to declare it as a Singleton to easy access it everywhere, but this particular step isn't needed to use the manager. To declare it as a singleton add a public static variable inside DataManager.cs called instance and declare it inside an Awake() function:

public class DataManager : MonoBehaviour
{
    
private string fileName = "/profileData.dat";
    private string fullPath;

    public PlayerData data; // Use this variable to modify and read player data after loading it.

public static DataManager instance;

    void Awake()
{
        instance = this;
}

void Start ()
{
        fullPath = Application.persistentDataPath + fileName;
Load();
}

// ...

}

With our DataManager as a singleton is it now possible to access it without adding a reference first.
Let's say we have a PlayerController.cs script with a function that is being called every time the player is collecting points. We can modify that function to use our DataManager to save the points with the following code:

public class PlayerController : MonoBehaviour {
    
    void AddPoints(float points)
{
DataManager.instance.data.points += points;
DataManager.instance.Save();
}
}

We hope you liked the tutorial and do not hesitate to ask if you have any questions.
Find the full DataManager.cs script below:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

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

public class DataManager : MonoBehaviour
{
    
private string fileName = "/profileData.dat";
    private string fullPath;

    public PlayerData data; // Use this variable to modify and read player data after loading it.

public static DataManager instance;

    void Awake()
{
        instance = this;
}

void Start ()
{
        fullPath = Application.persistentDataPath + fileName;
Load();
}

public void Save ()
{
     FileStream file = File.Create(fullPath);
     BinaryFormatter bf = new BinaryFormatter();

     bf.Serialize(file, data);
     file.Close();
}

private void Load ()
{
if (!File.Exists(fullPath)) {
return;
}

     FileStream file = File.Open(fullPath, FileMode.Open);
     BinaryFormatter bf = new BinaryFormatter();
     data = (PlayerData)bf.Deserialize(file);
     file.Close();
}
}

[System.Serializable]
public class PlayerData
{
    public float points;
}


Author:
Nicolai B. Andersen

First person shooting in Unity using raycast - Published about 2 months ago
blog post cover

Have you ever wanted to build your own first-person shooter game?
You got the character and movement setup in Unity but need some kind of shooting functionality?
This can easily be accomplished using raycasts.


Game Development Devlog Unity tutorial
READ
Robot Invasion Wars App Icon Robot Invasion Wars - Shooter
Release date: May 7, 2018 - Last update: Nov 29, 2018 - Version number: 1.7

Intense skill-based gameplay
The robots are waiting for you! Enter a world where the robots try to take over. Many have tried and failed. But you can be the one that stops the invasion.

Save civilians while crushing angry robots who want to hurt you. Improve your game by scoring accelerated movement, quicker reloading, extra health and more with killstreaks.



App Store badge US-UK Get it on Google Play



- The game is not supported in your browser - HOW TO JUMP: USE THE W KEY / CLICK INSIDE THE GAME AREA