Reputation: 151
you know how in games, it saves your data(progress). How do you do that in the godot4 engine? The only way I know how to store data is using variables, but it gets reset when you re-launch the game.
Does anyone know anything about this that can help?
Upvotes: 2
Views: 392
Reputation: 40295
First and foremost, you want to keep everything you want to save/load in the same place.
If you have the data scattered across multiple nodes, you will have a harder time.
So we will have an object that will expose the data so that the code that needs it can read it and write it and you can put signals there too, and is also responsible for saving and loading it.
So where do we do that? We do it in an autoload (singleton), as Godot makes them available from anywhere in the scene tree.
So create an autoload (singleton) and give it a name. There you will have all the variables you want to save or load. And you can have signals too.
Then you need some code to load and save them. Something like this would be an start:
const save_file := "user://saved.dat"
func reload() -> void:
var file := ConfigFile.new()
var err := file.load(save_file)
if err != OK:
push_error("error loading score " + str(err))
return
score = int(file.get_value("Player", "score"))
func save() -> void:
var file := ConfigFile.new()
file.set_value("Player", "score", score)
var err := file.save(save_file)
if err != OK:
push_error("error saving score " + str(err))
This example is based on the one I wrote as part of the answer to the question Increment score when player touches a coin's Area2D.
The code uses ConfigFile
which will make a human readable file (basically an INI file). And it supports encoding all basic Godot types.
Then it is a matter of including the variables you need in these methods.
You can, of course, call reload
from _ready
.
You might even try a bit of reflection. For example:
extends Node
const save_file := "user://saved.dat"
func reload() -> void:
var file := ConfigFile.new()
var err := file.load(save_file)
if err != OK:
push_error("Error loading: " + str(err))
return
for property in get_property_list():
if property.type == TYPE_NIL:
continue
set(property.name, file.get_value("Progress", property.name))
func save() -> void:
var file := ConfigFile.new()
for property in get_property_list():
if property.type == TYPE_NIL:
continue
file.set_value("Progress", property.name, get(property.name))
var err := file.save(save_file)
if err != OK:
push_error("Error saving: " + str(err))
Here I'm using get_property_list
to get the list of properties exposed by this object, and either save them or load them from the file. This way you don't have to hard code the variables in these methods. Just add the var
s and use them.
This is not the only way to go about this. Yet, the approach I present should be both easy and flexible enough for most cases.
Some people prefer JSON for example. Other prefer to use a binary format.
I'm not advising to use Resource
unless you know what you are doing, because Godot will load resource files without validation, and this might allow to inject code into the game. Granted, that this precaution is more on protecting the player from some shady person who shared a save file with them.
Upvotes: 3