In general, .saving and loading data in Unity is no different than in other C# applications. You’ll need:
- A serializable class to hold the data you want to save – anything
[System.Serializable]
- A serializer/deserializer, such as .NET’s
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
- A stream to (de)serialize – most likely a
FileStream
I’ll provide a simple, but complete, example that demonstrates saving and loading a custom inventory class below. First, a preview:

To test, you’ll need to add the Player
component to a GameObject in your scene, then enter play mode. Pressing 1
adds to the inventory, 2
removes a random item, 3
prints the inventory to the console, 4
saves the current inventory, and 5
loads the saved inventory.
An inventory is just a list of items – this is what we’ll be serializing as our save data.
Assets/Inventory.cs
using System.Collections.Generic;
[System.Serializable]
public class Inventory
{
public List<Item> items;
public Inventory() { items = new List<Item>(); }
}
An item has a few simple properties. Note that it also has the Serializable
attribute.
Assets/Item.cs
[System.Serializable]
public class Item
{
public string description;
public int value;
public Item(string description_, int value_)
{
description = description_;
value = value_;
}
public override string ToString() { return $"{description} -- {value}"; }
}
The player class holds the save/load logic, and some code to help test. The SaveInventory
and LoadInventory
functions are what’s most important.
Assets/Player.cs
using System.IO;
using UnityEngine;
public class Player : MonoBehaviour
{
public Inventory inventory = new Inventory();
string InventorySavePath => Application.persistentDataPath + "/inventory.save";
void Update()
{
if (Input.GetKeyDown(KeyCode.Alpha1)) { AddItemToInventory(); }
if (Input.GetKeyDown(KeyCode.Alpha2))
{
if (inventory.items.Count > 0) { RemoveItemFromInventory(); }
}
if (Input.GetKeyDown(KeyCode.Alpha3)) { DebugInventory(); }
if (Input.GetKeyDown(KeyCode.Alpha4)) { SaveInventory(); }
if (Input.GetKeyDown(KeyCode.Alpha5)) { LoadInventory(); }
}
void DebugInventory()
{
foreach (var item in inventory.items)
{
Debug.Log(item);
}
}
void AddItemToInventory()
{
var item = new Item(System.Guid.NewGuid().ToString(), Random.Range(1, 100));
Debug.Log($"Adding item: {item}");
inventory.items.Add(item);
}
void RemoveItemFromInventory()
{
var randomIdx = Random.Range(0, inventory.items.Count);
var item = inventory.items[randomIdx];
Debug.Log($"Removing item: {item}");
inventory.items.RemoveAt(randomIdx);
}
void SaveInventory()
{
Debug.Log($"Saving inventory to file @ {InventorySavePath}");
var stream = new FileStream(InventorySavePath, FileMode.Create, FileAccess.Write);
var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
formatter.Serialize(stream, inventory);
stream.Close();
}
void LoadInventory()
{
Debug.Log($"Loading inventory from file @ {InventorySavePath}");
if (File.Exists(InventorySavePath))
{
var stream = new FileStream(InventorySavePath, FileMode.Open, FileAccess.Read);
var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
inventory = (Inventory)formatter.Deserialize(stream);
stream.Close();
}
else { Debug.LogError("Save file does not exist!"); }
}
}
Hope this helps!