Shortest posible example for saving multiple variables

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Godot_Starter

As a result of another question I got this code for a saving system with one variable:

https://forum.godotengine.org/70471/shortest-posible-example-for-saving-one-variable

var level = 1

func _ready():
    load_level()

func load_level():
    var save_file = File.new()
    if not save_file.file_exists("user://savefile.save"):
        return

    save_file.open("user://savefile.save", File.READ)
    level = save_file.get_line()
    save_file.close()


func save_level():
    var save_file = File.new()
    save_file.open("user://savefile.save", File.WRITE)
    save_file.store_line(level)
    save_file.close()

Now I tried to make a saving system with two variables(level,leben) and I changed two things:

var level = 1
var leben = 1

func _ready():
    load_level()

func load_level():
    var save_file = File.new()
    if not save_file.file_exists("user://savefile.save"):
        return
    save_file.open("user://savefile.save", File.READ)
        #Here is the first change 
    level = int(save_file.get_line())
    leben = int(save_file.get_line()) #I think the problem is here

    save_file.close()

func save_level():
        #Here is the second change
    var data = { 
	    "level" : level,
	    "leben" : leben
    }
    var save_file = File.new()
    save_file.open("user://savefile.save", File.WRITE)
    save_file.store_line(to_json(data)) 
    save_file.close()

But it doesnt work. If level was 5 and health was 1 after saving and loading level was 15 and health 0, I think. How can I fix that?

:bust_in_silhouette: Reply From: njamster

Calling to_json(data) will generate only one line of text:

{"leben":"1","level":"5"}

Your load_level-method reads the first two lines of text:

level = int(save_file.get_line())
leben = int(save_file.get_line())

The first line is your json-data. The integer type-cast will strip every character from it that is not an integer. So level will be set to 15. The second line is empty. The integer type-cast will turn the empty string into a 0. So leben will be set to 0.

Knowing that, there are two routes to fix your issue:

  1. keep the load_level()-method and change the save_level-method
  2. keep the save_level()-method and change the load_level-method

The first option is easier to explain, so let’s start with that:

func save_level():
    var save_file = File.new()
    save_file.open("user://savefile.save", File.WRITE)
    save_file.store_line(str(level))
    save_file.store_line(str(leben))
    save_file.close()

This is simply writing each variable into it’s own line. However, there are no labels added to the values, so you have to remember (or look up) what each value means.

The second option (following the documentation) would look like this :

func load_level():
	var save_file = File.new()
	if not save_file.file_exists("user://savefile.save"):
		return

	save_file.open("user://savefile.save", File.READ)
	var data = parse_json(save_file.get_line())
	level = int(data["level"])
	leben = int(data["leben"])
	save_file.close()

We get the entire first (and now: only) line, which is containing the complete json-data as a string. We then parse that string using the built-in parse_json-method to turn it back into a dictionary looking exactly like the one we used to create the string. That’s what’s called “serialization”: save_level turns a dictionary-object into a string that one can write to a file. And load_level turns that string back into a dictionary.

Danke, das war sehr hilfreich

Godot_Starter | 2020-05-13 09:56

This might make your life much easiert while saving stuff:

Godot: How to save Game Progress in a Single Resource File
(Youtube-Video from Gonkee)

whiteshampoo | 2020-05-13 10:13