Skip to main content

Save System for Unity - Technoob Technology


Unity API has a class called ‘PlayerPrefs’ which allows saving basic data types with a string key. But when a game becomes complex ‘PlayerPrefs’ can't save all the data and it's so hard to access them as you have to remember all the keys and call one by one. To avoid this we can create a custom save system which can save a class at once which contains all the data values.


Save system - technoob technology


We need two scripts for this save-system.

            01.SaveSystem class
            02.SaveData class


Save system class will contain all the methods to save and retrieve data and ‘SaveData’ class is used as the base class for the classes we going to create to store data. 

‘SaveData’ class doesn’t contain any methods and not extended by any other classes or interfaces. Make sure to mark this class as ‘[System.Serializable]’ in order to make sure this is serializable.


[System.Serializable]
public class SaveData
{
}


‘SaveSystem’ class contains 3 methods. One for initialization and you can add this to the Awake method. Class is in singleton pattern to make sure this class won't get destroyed when switching scenes. This class saves all the data as binary files and this class doesn’t support unity API data structures and generic data structures.


public class SaveSytem : MonoBehaviour
{
    private static SaveSytem instance;
    
    private List<String> pathList = new List<string>();

    private string extensionType = "technoob";
    
    private void Awake()
    {
        #region SINGLETON

        if (instance == null)
            instance = this;
        else if(instance!= this)
            Destroy(gameObject);
        
        DontDestroyOnLoad(gameObject);

        #endregion

        InitSaveSystem();
    }

    /// <summary>
    /// Saves the class passed to this method
    /// </summary>
    /// <param name="saveData">Class which is extended by SaveData class</param>
    /// <param name="_datapacketId">This should be unique for each class you save</param>
    public static void SaveGame(SaveData saveData , string _datapacketId)
    {
        BinaryFormatter binaryFormatter = new BinaryFormatter();

        string path = Application.persistentDataPath;
        
        if (!instance.pathList.Contains(_datapacketId))
            instance.pathList.Add(_datapacketId);
        
        path = Application.persistentDataPath + "/" + _datapacketId + instance.extensionType;
        
        FileStream stream;
            
        if (File.Exists(path))
            stream= new FileStream(path, FileMode.Open);
        
        else
            stream = new FileStream(path, FileMode.CreateNew);
        
        binaryFormatter.Serialize(stream , saveData);

        stream.Close();
            
        int x = instance.pathList.Count;
        
        String[] paths = new string[x];
        
        for (int i = 0; i < x; i++)
        {
            paths[i] = instance.pathList[i];
        }

        path = Application.persistentDataPath + "/settings.technoob";
        
        if (File.Exists(path))
            stream= new FileStream(path, FileMode.Open);
        
        else
            stream = new FileStream(path, FileMode.CreateNew);
        
        
        binaryFormatter.Serialize(stream , paths);
        
        stream.Close();
     }

    /// <summary>
    /// Returns saved class for the unique string id
    /// </summary>
    /// <param name="_dataPacketId">Unique string id for the saved class</param>
    /// <returns></returns>
    public static SaveData GetSaveData(string _dataPacketId)
    {
        BinaryFormatter binaryFormatter = new BinaryFormatter();

        string path = Application.persistentDataPath + "/" + _dataPacketId + instance.extensionType;
        
        if (File.Exists(path))
        {
            FileStream stream = new FileStream(path, FileMode.Open);
            SaveData _data = binaryFormatter.Deserialize(stream) as SaveData;
            stream.Close();
            return _data;
        }
        else
        {
            Debug.LogError("Data packet " + _dataPacketId + " not found!  - SaveSystem");
            return null;
        }
        
        
    }

    #region INITIALIZATION

    
    public static void InitSaveSystem()
    {
        BinaryFormatter binaryFormatter = new BinaryFormatter();

        string path = Application.persistentDataPath + "/settings.technoob" ;
        
        if (File.Exists(path))
        {
            FileStream stream = new FileStream(path, FileMode.Open);

            String[] paths =  binaryFormatter.Deserialize(stream) as string[];

            for (int i = 0; i < paths.Length; i++)
            {
                instance.pathList.Add(paths[i]);
            }
            stream.Close();
        }
       Debug.Log("Init Save System");
    }
    
    #endregion
}





The class which contains the data you wanna save should be extended from the SaveData class. Make sure to mark that class as [System.Serializable].  After that, you can call the SaveGame method by passing that class and a string key to access that class later. You can simply call the GetSaveData method by passing the string key when you want to retrieve the data again. You don’t need to worry about the extension of the save files as this class saves the data as binary files.

You can create a custom converter class to convert none serializable data types into serializable data types like converting color to a float array. 


All these scripts with a demo scene are available on GitHub.

Related Articles 





Comments

Popular posts from this blog

How to make a first person character controller - Unity

A first-person character controller script is the starting point of any fps shooter game. Even new Unity game developers tend to write their own fps controller script before learning anything else as it is challenging and very exciting. In this article, we gonna create two simple fps controllers from scratch and will guide you step by step on how it works. First, let's understand the basic concept of an fps controller. You should have a rotating camera that rotates in the x-axis to look up and down and the character should rotate on the y-axis to look around. There are two ways to create an fps controller in the Unity Engine.  Using Character controller component Using the RigidBody component Both have different advantages and disadvantages when using them. It depends on your game to select the best fps controller according to your needs.  Character controller based fps controller Pros: Is grounded check is built-in Has its own methods to move the chara

Unity Get Post web requests - Technoob Technology

Web requests in unity are super easy to use. We gonna use the UnityWebRequest class as the WWW class is deprecated now. UnityWebRequest class can be used for both Get and Post methods. The 'UnityEngine.Networking' namespace is required to work with UnityWebRequests.  This tutorial is made with some simple UI elements. First Let's see how the GET method works. 01. UnityWebRequest.GET We use this method to receive data from the server as normal get requests. Using coroutines in web requests is mandatory as we have to wait until the download is complete before showing the results, and the coroutines make this much easier. A simple button calls the method and a text element will show the result. The script contains a reference to the text element and the string URL of your PHP file.  When the button is pressed the button executes the ButtonGetData method and that method simply starts the GetData coroutine. We use the using keyword as this data

How to make an Advanced Audio Manager for Unity - Technoob Technology

Unity engine gives us a good control on audio clips we use, But the problem is when we add several audio sources for several audio clips it's gonna get hard to control them all. And if you want to make some changes to only one audio source you have to find it first.  This will become a mess if you gonna work with more than 10 audio clips. In this case, we can Create an AudioManager and include all the audio clips in it and make some static methods to play, pause the audio from other scripts. This Audio Manager is written in C# and if you use unity-script you have to convert this into unity script first. In this tutorial, we gonna create an audio manager which contains 7 methods. 1.Play 2.Pause 3.Unpause 4.Stop 5.FadeIn 6.FadeOut 7.lower volume for a duration First, we need a Custom class which contains some strings, floats, bools and an audio clip. This class is not derived from unity mono behavior so we should add [System.Serializable] to mak