Coding_Guy
Coding_Guy

Reputation: 151

How to load game data when restarting a godot4 game?

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

Answers (1)

Theraot
Theraot

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 vars 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

Related Questions