---
title: Unity ScriptableObjects Save Load System: Easy Game Save
siteUrl: https://logzly.com/gamedevcodecraft
author: gamedevcodecraft (GameDev Codecraft)
date: 2026-07-11T02:01:14.786819
tags: [unity, scriptableobject, gamedev]
url: https://logzly.com/gamedevcodecraft/unity-scriptableobjects-save-load-system-easy-game-save
---


Tired of losing progress when your Unity game crashes or you quit?  
Implement a **Unity ScriptableObjects Save Load System** to reliably persist player data with just a few lines of code.

## How the Unity ScriptableObjects Save Load System Works

The core idea is to store your game state in a **ScriptableObject** asset, then serialize that asset to JSON when you need to save and deserialize it when you load. This eliminates the brittle string‑key mess of PlayerPrefs and lets you add new fields without touching the save/load logic.

### Creating the Data Container

First, define a simple C# class that inherits from `ScriptableObject`. Add fields for everything you want to persist—health, level, inventory, settings, etc.

```csharp
using UnityEngine;
using System.Collections.Generic;

[CreateAssetMenu(fileName = "GameData", menuName = "SaveSystem/GameData")]
public class GameData : ScriptableObject
{
    public int playerHealth = 100;
    public int currentLevel = 1;
    public List<string> inventory = new List<string>();
    // Add more fields as needed
}
```

### Saving to Disk

Next, write a static helper that converts the `GameData` instance to JSON and writes it to `Application.persistentDataPath`.

```csharp
using System.IO;
using UnityEngine;

public static class SaveLoadManager
{
    private const string SaveFileName = "gamedata.json";

    public static void SaveGame(GameData data)
    {
        string json = JsonUtility.ToJson(data, true);
        string path = Path.Combine(Application.persistentDataPath, SaveFileName);
        File.WriteAllText(path, json);
        Debug.Log($"Game saved to {path}");
    }

    public static GameData LoadGame()
    {
        string path = Path.Combine(Application.persistentDataPath, SaveFileName);
        if (!File.Exists(path))
        {
            Debug.LogWarning("Save file not found. Returning fresh data.");
            return CreateInstance<GameData>();
        }

        string json = File.ReadAllText(path);
        GameData data = JsonUtility.FromJson<GameData>(json);
        Debug.Log($"Game loaded from {path}");
        return data;
    }
}
```

### Hooking It Up in Your Scene

1. Create a **GameData** asset via `Assets > Create > SaveSystem > GameData`.  
2. Drag the asset onto a manager GameObject in your scene.  
3. At runtime, fill the asset with current values (e.g., from your player controller).  
4. Call `SaveLoadManager.SaveGame(yourDataAsset)` on pause, exit, or autosave triggers.  
5. Call `SaveLoadManager.LoadGame()` in `Start()` or `Awake()` to restore state.

Because the data lives in an asset, you avoid the fragile string‑key approach of PlayerPrefs. Adding a new field—say, `public bool hasKey`—requires no changes to the save/load methods; Unity’s JSON serializer handles it automatically.

### Benefits Over PlayerPrefs

- **Scalability**: Complex nested objects (lists, custom classes) serialize cleanly.  
- **Safety**: No risk of mismatched keys when you rename variables.  
- **Extensibility**: New save versions work out‑of‑the‑box; old files still load, missing fields get default values.  
- **Debugging**: You can inspect the saved JSON file directly in `Application.persistentDataPath`.

### Quick Checklist for Implementation

- [ ] Create a `ScriptableObject` subclass with all saveable fields.  
- [ ] Add `[CreateAssetMenu]` for easy asset creation.  
- [ ] Implement `SaveGame` and `LoadGame` using `JsonUtility`.  
- [ ] Wire the asset to a persistent manager in your scene.  
- [ ] Call save on appropriate events (pause, exit, level complete).  
- [ ] Call load on game start to restore player progress.

By following these steps, you’ll have a robust **Unity ScriptableObjects Save Load System** that scales with your game’s complexity and saves you countless hours of debugging. Give it a try and watch your development workflow smooth out instantly.