How to create simple save system for android in godot 3.0

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

I have read all the thread existed on this forum as well as the official doc describing the save game mechanism using group.
However after several tries I still fail and cannot fully understand numerous data being stored and read, it just confused me…><
My purpose using save file is just want to store some boolean variable and integer number, nothing more. Pls give me a simple and plain example!
I have used global.gd and it works fine in a one-time game use. Below is the current code in the global script, it cannot be simpler.

extends Node
var Music = true
var BgColor = 0

func _ready():
    pass

Please, if there are any “pathname” or “savename” suggested, just tell me if it can be replaced by any name. Thx for help IN ADCANCE!!!

Similar success posts 1 2 3

:bust_in_silhouette: Reply From: tomandrieu

Hello,

Personnaly i use dictionnary to store data, here an exemple based on your data :

extends Node
var Music = true
var BgColor = 0

var dataToSave = {
"Music" : true,
"BgColor" : 0,
}

#Open the save file if it exist or create it with a call to save_data()
#Then for each data (current_line[key]) in the file it change the 
#sava_data variables to update it
func load_data():
    var save_dataFile = File.new()
    if not save_dataFile .file_exists("user://path_to_the_file.save"):
	   save_data()

    save_dataFile.open("res://path_to_the_file.save", File.READ)
    var current_line = parse_json(save_playerVariablesFile.get_line())
    for key in dataToSave :
	    if dataToSave .has(key):
		    dataToSave [key] = current_line[key] 
    init_data()

#return data of the variable (if key == BgColor, it return 0)
func load_Variables(var key):
    if dataToSave .has(key):
	    return dataToSave [key]

func allVariables():
    return dataToSave

func save_Data():
    var save_DataFile= File.new()
    save_dataFile.open("user://path_to_the_file.save", File.READ)
    var data = allVariables()
    save_DataFile.store_line(to_json(data))
    print("Player Variables save")
    save_DataFile.close()

func init_data():
    BgColor = dataToSave["BgColor"]
    Music = dataToSave["Music"]

With this kind of script you just have to do load_data() when you need to load or update the data, and do save_dataVariables when you need to save your data,
If you have any question tell me !

Edit : “res://” change to “user://” thanks to Calinou, i have never export a project for mobile device thanks for the advice.

Since res:// is not guaranteed to be writable in exported projects (this is especially true on mobile platforms), you should use user:// to load and save user data instead (such as configuration files or game saves).

Calinou | 2018-07-17 19:31

HI, Thank you for your answer!!

I tried your code on Godot to see if it work and there is still something not right.
Since it’s a global script I assume it is loaded at the start of the program, so I made a ready function and put your loaddata() func inside. Then, i put savedata func() in the line where player changed one of the settings by like pressing a button to turn music off.

However, the strangest thing is that, before I use your code, if the player tapped the music button, the global variable Music should change to false or true according to the previous state of the music variable and I initialized the variable music to true by default. If I tapped the music button, there is also a _process() func which will continuously detect music state and change the sprite resource of the Music button. When I use your code, I put the save_data() func below the code which changes music state after press. However, in run test, I tap the button and nothing happen, which is so weird. The variable doesn’t change at all…

zhangyao | 2018-07-18 08:19

Hello,

Did you make global.gd an autoload at first ?

Any errors occurs when you run your test that can help me because here i don’t know what’s wrong with my current code…
Maybe it’s not adapt to mobile devices because i test this code on computer and maybe the file reading/writing is not the same on mobiles.

Maybe write here your global.gd and your Music button script so i can see if it runs on my computer and change the code if i see errors ?

tomandrieu | 2018-07-18 09:29

Ohh sorry, I forgot to check the debugger at that time,
I checked the debugger now it said “Parser Error: Identifier not found: save_playerVariablesFile”
in this line of your code

var current_line = parse_json(save_playerVariablesFile.get_line())

I dont know what it means…

PS: Above that line in your code there is a res:// path, I saw your edit so I changed it to user://

zhangyao | 2018-07-18 11:24

Yeah sorry it was a variable that i change to make it more clear for you but i forget to change in this line, replace this with

save_dataFile.get_line()

tomandrieu | 2018-07-18 11:26

I unified some of the capitalized function and now the whole global.gd looks like this, yeah I autoloaded it.

extends Node
var Music = true
var BgColor = 0

var dataToSave = {
"Music" : true,
"BgColor" : 0,
}

func _ready():
    load_data()
#Open the save file if it exist or create it with a call to save_data()
#Then for each data (current_line[key]) in the file it change the 
#sava_data variables to update it
func load_data():
    var save_datafile = File.new()
    if not save_datafile.file_exists("user://path_to_the_file.save"):
       save_data()

    save_datafile.open("user://path_to_the_file.save", File.READ)
    var current_line = parse_json(save_datafile.get_line())
    for key in dataToSave:
        if dataToSave.has(key):
            dataToSave[key] = current_line[key] 
    init_data()

#return data of the variable (if key == BgColor, it return 0)
func load_Variables(var key):
    if dataToSave.has(key):
        return dataToSave[key]

func allVariables():
    return dataToSave

func save_data():
    var save_datafile= File.new()
    save_datafile.open("user://path_to_the_file.save", File.READ)
    var data = allVariables()
    save_datafile.store_line(to_json(data))
    print("Player Variables save")
    save_datafile.close()

func init_data():
    BgColor = dataToSave["BgColor"]
    Music = dataToSave["Music"]

Whenever I need save, I use exactly this line of code

global.save_data()

Now the button can be normally turn on and off, but whenever I reopen the game, the button state returned to default and does not read from save. It seems the save is still now working ><

Edit: The debugger said this Invalid get index 'Music' (on base: 'Nil'). on this line of code

dataToSave[key] = current_line[key] 

zhangyao | 2018-07-18 11:46

Add some variables and load / save your file manually and check the file to see when it change or what ever so you can see if the problem is that it doesn’t init your variable or doesn’t save the file

The debugger is ok, no problem related to the saving

tomandrieu | 2018-07-18 11:55

Try to dot str(key) maybe or else i don’t know what’s wrong, check if your save file is complete maybe

tomandrieu | 2018-07-18 12:18

So i made some changes, remove the init_data in the load_data() function at the end.

In the save_data() function, remove :

    save_datafile.open("res://path_to_the_file.save", File.READ)

and set :

    save_datafile.open("res://path_to_the_file.save", File.WRITE)

then add the function

func update_data():
    dataToSave["Music"] = Music
    dataToSave["BgColor"] = BgColor
    save_data()

now when you need to save the data you can call the function update_data,
In game when you make change you just have to change the value of Music and BgColor then call update_data().
On the ready function you can call load_data() then init_data() so it initialize the dataToSave Dictionnary based on the .save file and then init your variables with this dictionnary.

I don’t know if this i clear or not English is not my native, i hope i help you but don’t copy what i say, try to understand what i did so you can adapt to your needs.

Have a great day

tomandrieu | 2018-07-18 13:59

Thx, I finally solved it, :slight_smile:
Your help is more than grateful!

zhangyao | 2018-07-19 11:14