Save and Load System for Godot 4 – Tutorial

Last modified date

Saving and loading game data is a crucial feature for any game, as it allows players to continue their progress even after closing the game. A save and load system for Godot 4 is relatively straightforward, but it requires some knowledge of how to work with files and data structures.

In this tutorial, we’ll be creating a simple save and load system. We’ll start by creating a very basic scene. Keep in mind, that with this flexible technique, you can save any object, and also any data of that object. We’ll also learn how to write this data to a file on disk and how to read it back in when the game is loaded.

By the end of this tutorial, you’ll have a fully functioning save and load system for your Godot game, allowing players to save their progress and continue playing from where they left off. So, let’s get started!

Dear reader, please consider supporting my game ❤


Step by step to a save and load system for Godot 4

  • Create a new scene in Godot by clicking on Scene > New Scene in the top menu.
  • Add a Control node to your scene by clicking on “User Interface”. Call it “SaveLoad”.
  • Add a LineEdit node to your SaveLoad node by clicking on the plus sign or Ctrl+A, then search for LineEdit.
  • Next, add a SpinBox to the scene.
  • And do the same for 3x Button (call one “Save”, one “Load”, and the last one “Delete”).

Now we’ll add some code to our scene to handle saving and loading.

  • In the editor, click on the SaveLoad node and add a Script by clicking “Attach new script”.
  • Give your script a name, such as “SaveLoad.gd”.
  • Click on the “Save” button, then on the right side of the editor, go to Node > Signals.
  • Double click pressed() and connect it with the script in the SaveLoad node.
  • Repeat this for the “Load” and the “Delete” button.
  • Open the script, and replace the code with this code:
extends Control

func _on_save_pressed() -> void:
	_save()
	$LineEdit.clear() # clear the LineEdit after saving
	$SpinBox.value = 0 # set SpinBox back to Zero
	
func _on_load_pressed() -> void:
	_load()
	
func _on_delete_pressed() -> void:
	DirAccess.remove_absolute("saveFile")
	print("GAME DELETED")

func _save() -> void:
	var save_file = FileAccess.open("saveFile", FileAccess.WRITE) # Open File
	
	# Go through every object in the Sagroup
	var save_nodes = get_tree().get_nodes_in_group("SaveLoad")
	for node in save_nodes:
		# Check if the node has a save function.
		if !node.has_method("saveObject"):
			print("Node '%s' is missing a save function, skipped" % node.name)
			continue
			
		# Call the node's save function.
		var node_data = node.call("saveObject")
		
		# Store the save dictionary as a new line in the save file.
		save_file.store_line(JSON.stringify(node_data))
	
	save_file.close() # Close File
	print("GAME SAVED")

func _load() -> void:
	# Check if the SaveFile exists
	if !FileAccess.file_exists("saveFile"):
		print("Error, no Save File to load.")
		return
		
	var save_file = FileAccess.open("saveFile", FileAccess.READ) # Open File
	
	while save_file.get_position() < save_file.get_length():
		# Get the saved dictionary from the next line in the save file
		var json = JSON.new()
		json.parse(save_file.get_line())
		
		# Get the Data
		var node_data = json.get_data()
		if has_node(node_data["filepath"]):
			get_node(node_data["filepath"]).loadObject(node_data)
			
	save_file.close() # Close File
	print("GAME LOADED")
  • Next, add a script to the LineEdit and add this code to it:
extends LineEdit

func saveObject() -> Dictionary:
	var dict := {
		"filepath": get_path(),
		"savedText": text
	}
	return dict
	
func loadObject(loadedDict: Dictionary) -> void:
	text = loadedDict.savedText
  • Click on LineEdit. On the right side, go to Node > Groups and add “SaveLoad”.

As you can see, the way to save an object is to first add it to the “SaveLoad” group and then add the save and the load function to the script of that object. When saving, every object will save the variables specified in the saveObject() function. And when you are loading, every object will do with those variables as you say in the loadObject() function.

How to save variables in Godot 4

So far, we only save a string. But of course you can save all kinds of variables. The easiest way is to first convert them into a string, and when loading, convert them back into the variable again.

  • To demonstrate this, add a script to the SpinBox.
  • Next, click on the SpinBox. Again, go to Node > Groups and add “SaveLoad”.
  • Also, add the following code to the script:
extends SpinBox

func saveObject() -> Dictionary:
	var dict := {
		"filepath": get_path(),
		"savedInt": var_to_str(value)
	}
	return dict
	
func loadObject(loadedDict: Dictionary) -> void:
	value = str_to_var(loadedDict.savedInt)
  • You can now arrange the different objects like so:
Add the object, that should be saved, to the "SaveLoad" group - Save and Load System for Godot 4
  • Save the scene and run it. Type some text into the LineEdit, change the SpinBox and click “Save”. It should automatically delete the text and if you click “Load”, the text should be loaded back into the LineEdit and SpinBox. You can also delete the save file by clicking the “Delete” button. Have a look at the system in action:

Now we have a save and load system for Godot 4

That’s it! With this tutorial, you should be able to implement a basic save and load system for Godot that allows players to save and load their progress in the game. By adding objects to the group “SaveLoad” and add a save / load function to that object, you can extend it to save any other game object you need and also any relevant data of that object.

For more information about Godot 4 check the official documentation.

Download the source files

If already subscribed, you can find all project files here. Otherwise, you can subscribe to the mailing list to get access to this and other project files for free and get notified, when a new tutorial is posted.