Saving player progress is essential in nearly every game. In this tutorial, you'll learn how to create a basic save system in Godot 4 using JSON—a lightweight and readable data format supported natively by the engine.
We’ll cover:
- 🧩 Structuring your data
- 💾 Writing a save file
- 📂 Loading saved data
- 🔁 Reconstructing data like
Vector2
- ✅ Final tips and best practices
🧩 Why JSON?
JSON (JavaScript Object Notation) is easy to write, read, and parse—making it a great format for saving data like inventory, progress, or settings.
Godot 4 has built-in support for converting dictionaries to and from JSON strings, making it super convenient for game developers.
💾 Saving Data to a File
Here’s a basic function to save some example data:
func save_game():
var save_path = "user://savegame.json"
var file = FileAccess.open(save_path, FileAccess.WRITE)
var save_data = {
"player_position": [100, 200], # Vector2 as array
"inventory": ["sword", "potion"],
"gold": 50
}
var json_string = JSON.stringify(save_data)
file.store_string(json_string)
file.close()
print("Game saved!")
📝 user://
points to your game's internal save folder on any device.
📂 Loading Data from a File
To restore saved data:
func load_game():
var save_path = "user://savegame.json"
if not FileAccess.file_exists(save_path):
print("No save file found.")
return
var file = FileAccess.open(save_path, FileAccess.READ)
var json_string = file.get_as_text()
file.close()
var result = JSON.parse_string(json_string)
if result.error != OK:
print("Failed to parse JSON.")
return
var save_data = result.result
print("Loaded data: ", save_data)
🔁 Reconstructing Non-JSON Types
Since JSON doesn't support Godot-native types like Vector2
, you’ll need to convert manually:
var pos_array = save_data["player_position"]
var player_position = Vector2(pos_array[0], pos_array[1])
This restores the original position.
✅ Tips & Best Practices
- Check file existence before loading.
- Store complex types like
Vector2
,Color
, orTransform2D
as arrays or dictionaries. - Consider encryption with
open_encrypted_with_pass()
for sensitive data. - Use a singleton (
autoload
) likeSaveManager.gd
to centralize save/load logic. - Add versioning in your save data structure in case you need to migrate later.
References
- Basic flow diagram: Steve Grossman - Programming Resources
- Godot 4 Documentation: Godot 4 - Documentation