How do I save and load the game?
What to save
Section titled “What to save”The script sits on Main and holds the values worth keeping:
MainNode2D
the script goes here
Gather those values into a Dictionary of plain types: numbers, strings, booleans and arrays of them. Save values, not nodes.
extends Node2D
var coins := 0var level := 1
func get_save_data() -> Dictionary: return { "coins": coins, "level": level, "position": [position.x, position.y], }Save to a file
Section titled “Save to a file”Open a file for writing, turn the dictionary into a JSON string, and store it. The file closes on its own when the variable goes out of scope:
func save_game() -> void: var data := get_save_data() var file := FileAccess.open("user://save.json", FileAccess.WRITE) file.store_string(JSON.stringify(data))using Godot;using Godot.Collections;
public partial class Main : Node2D{ private int _coins = 0; private int _level = 1;
private Dictionary GetSaveData() { return new Dictionary { { "coins", _coins }, { "level", _level }, { "position", new Array { Position.X, Position.Y } }, }; }
private void SaveGame() { using var file = FileAccess.Open("user://save.json", FileAccess.ModeFlags.Write); file.StoreString(Json.Stringify(GetSaveData())); }}user:// is a folder Godot owns for your game, writable on every platform; open it from the editor with Project → Open User Data Folder to see save.json appear. The extension is up to you: .json is a hint to people reading the folder, but .save, .dat or no extension at all works exactly the same, because Godot only cares about the text inside.
Load it back
Section titled “Load it back”Check the file exists first, so the very first run doesn’t crash. Then open it for reading, parse the text, and copy the values back:
func load_game() -> void: if not FileAccess.file_exists("user://save.json"): return var file := FileAccess.open("user://save.json", FileAccess.READ) var data = JSON.parse_string(file.get_as_text()) if data == null: return coins = int(data["coins"]) level = int(data["level"]) position = Vector2(data["position"][0], data["position"][1])private void LoadGame(){ if (!FileAccess.FileExists("user://save.json")) { return; } using var file = FileAccess.Open("user://save.json", FileAccess.ModeFlags.Read); var data = Json.ParseString(file.GetAsText()).AsGodotDictionary(); if (data == null) { return; } _coins = (int)data["coins"]; _level = (int)data["level"]; var pos = data["position"].AsGodotArray(); Position = new Vector2((float)pos[0], (float)pos[1]);}JSON.parse_string() returns null when the text isn’t valid JSON, which is why there is a second check. JSON has no integer type, so every number comes back as a float: data["coins"] is 12.0, not 12, and int() turns it back.