Simple Save System in Unity with JSON Serialization
Forget painstakingly recreating game progress! There’s a far simpler way. This guide tackles creating a basic save system in Unity. We’ll use JSON serialization to store player position and score, allowing you to persist data between game sessions effortlessly. No more lost progress!
Understanding the Core Principle: JSON Serialization
The most-downloaded assets on Wayline this month — sorted by what real developers actually use.
JSON (JavaScript Object Notation) is a lightweight data-interchange format. Think of it as a universal language for data. Unity can easily convert your game data (like player position and score) into JSON format for saving to a file, and then convert it back when loading. This is called serialization (converting to JSON) and deserialization (converting from JSON).
Creating the SaveData Class
First, we need a class to hold the data we want to save. This is the SaveData class. It will contain player position and score.
using UnityEngine;
[System.Serializable]
public class SaveData
{
public Vector3 playerPosition;
public int playerScore;
}
[System.Serializable] is crucial. It tells Unity that this class can be converted to JSON. Without it, the serialization process will fail. Make sure to include using UnityEngine; to use Vector3.
The SaveSystem Script: Saving Data
This script handles the actual saving and loading. Create a new C# script called SaveSystem. We’ll start with the saving function.
using UnityEngine;
using System.IO;
public class SaveSystem : MonoBehaviour
{
public static void SavePlayer(SaveData data)
{
string path = Application.persistentDataPath + "/player.json";
string json = JsonUtility.ToJson(data);
File.WriteAllText(path, json);
}
}
Let’s break this down:
Application.persistentDataPath: This gives you a reliable path on the user’s device where you can save data.JsonUtility.ToJson(data): This converts ourSaveDataobject into a JSON string.File.WriteAllText(path, json): This writes the JSON string to a file at the specified path.
Common Pitfall: Forgetting to check if the directory exists before writing the file! While Application.persistentDataPath usually exists, it’s good practice to ensure the directory structure is in place, especially if you are saving data in subdirectories.
The SaveSystem Script: Loading Data
Now, let’s implement the loading function. Add this to your SaveSystem script:
public static SaveData LoadPlayer()
{
string path = Application.persistentDataPath + "/player.json";
if (File.Exists(path))
{
string json = File.ReadAllText(path);
SaveData data = JsonUtility.FromJson<SaveData>(json);
return data;
}
else
{
Debug.LogWarning("Save file not found in " + path);
return null; // Or return a new SaveData object with default values
}
}
This function does the following:
File.Exists(path): Checks if the save file exists.File.ReadAllText(path): Reads the JSON string from the file.JsonUtility.FromJson<SaveData>(json): Converts the JSON string back into aSaveDataobject.- Handles the case where the save file doesn’t exist. Returning
nullis valid but might require null checks in your game logic. Consider returning a newSaveDataobject initialized with default values to avoid potential errors.
Implementing Save/Load in your Player Script
Create (or modify) your player script to use the SaveSystem. For example:
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public int score = 0;
void Update()
{
// Player movement and score logic here...
}
public void SaveGame()
{
SaveData data = new SaveData();
data.playerPosition = transform.position;
data.playerScore = score;
SaveSystem.SavePlayer(data);
Debug.Log("Game Saved!");
}
public void LoadGame()
{
SaveData data = SaveSystem.LoadPlayer();
if (data != null)
{
transform.position = data.playerPosition;
score = data.playerScore;
Debug.Log("Game Loaded!");
}
else
{
Debug.LogWarning("No save data found!");
}
}
}
Remember to attach this script to your player GameObject.
Creating UI Buttons to Trigger Save/Load
- In your Unity scene, create two buttons: one for “Save” and one for "Load".
- Attach the
PlayerControllerscript to your player GameObject. - In the Inspector for each button, add an
OnClick()event. - Drag your player GameObject into the object field of the
OnClick()event. - Select the function to call: For the “Save” button, choose
PlayerController.SaveGame(). For the “Load” button, choosePlayerController.LoadGame().
Now, clicking the buttons will trigger the SaveGame() and LoadGame() functions in your player script.
Challenges and Considerations
- Data Security: JSON is plain text, so don’t store sensitive information like passwords directly. Consider encrypting the data if security is a concern.
- Save File Corruption: If the save file gets corrupted, your game might crash or load incorrect data. Implement error handling to gracefully handle corrupted save files (e.g., load a backup or start a new game).
- Game Updates: If you change the structure of your
SaveDataclass in a future update, older save files might become incompatible. You’ll need to implement a migration strategy to handle older save formats. This can involve creating a separate class to represent the older save format and writing code to convert it to the new format.
Beyond Position and Score
This example saves player position and score. You can extend this system to save any data you want: inventory, game settings, character stats, etc. Just add the corresponding fields to your SaveData class. Remember to update your save and load functions accordingly.
This simple save system provides a foundation for persistent game data. By understanding the principles of JSON serialization, you can create robust and reliable save systems for your Unity games.