0 votes

OK so, I am trying to create a saving mechanism for my game where as soon as the game is over, if the score is a new high score, the score is automatically saved to a file. I am creating for Android and testing it on an Android device

I have a global script

var highscore #highscore will be loaded in this variable

var save_data = {"score": score} # data that will be saved
var loaded_data # variable to store loaded data

func _ready(): #ready
    save_play_data("user://play.data", save_data)
    loaded_data = load_play_data("user://play.data")
    set_data(loaded_data)

func save(score): #function that can be called from the game scene whenever there is a new highscore
    save_data = {"coins": score }
    save_play_data("user://play.data", save_data)

func save_play_data(path, data): #function to save data to file
    var f = File.new()
    f.open(path, File.WRITE)
    f.store_var(data)
    f.close()

func load_play_data(path): # function to load file
    var f = File.new()
    if f.file_exists(path):
        f.open(path, File.READ)
        var data = f.get_var()
        f.close()
        return data
    return null

func set_data(data): # function to assign data["score"] to score variable
    highscore = data["score"]

Now whenever I transfer it to an Android phone it doesn't work. What am I doing wrong?

While debugging there seems to be no error
Any help is appreciated

By the way I am following this post

asked 6 days ago in Engine by SingingApple (31 points)
edited 5 days ago by SingingApple
  • What did not work exactly?
  • loading a saved data after restarting game?
  • did you run on android by pressing "run" button on editor everytime instead of touching app icon on device?

Your initializing code is a bit strange:

var save_data = {"score": score} # data that will be saved

--> this initializes the value of "score" to the unknown value of score (that variable doesn't exist)

perhaps better:

var save_data = {"score": 0} # data that will be saved

here you always overwrite your play data before loading it. But perhaps that is only for test reasons:

func _ready(): #ready
    save_play_data("user://play.data", save_data)
    loaded_data = load_play_data("user://play.data")
    set_data(loaded_data)

Generally, saving should work on android in the user:// path.

Here's the code which I use. (It is a bit more complicated because I use a backup-file for fallback in case the last write got corrupted.). No guarantee its error free:

var status

var status_init = { "version": 1, 
                        "score": 1000
        }

const SAVE_GAME = "user://save_game.dat"
const SAVE_BAK = "user://save_game.bak"

func load_status():
    var file = File.new()
    var data = ""
    if file.file_exists(SAVE_GAME):
        file.open(SAVE_GAME, file.READ)
        data = file.get_as_text()
        file.close()
        print("Status loaded from "+SAVE_GAME)
    if data == "":
        if file.file_exists(SAVE_BAK):
            file.open(SAVE_BAK, file.READ)
            data = file.get_as_text()
            file.close()
            print("Status backup loaded from "+SAVE_BAK)

    if (data == "") or (data == null):
        status = status_init
        print("Status new? -> Init")
    else:
        status = {}
        status.parse_json(data)
        if (status!=null) and (status.has("version")):
            print("Status parsed ok")
            save_status(SAVE_BAK)


func save_status(file_name = SAVE_GAME):
    var file = File.new()
    file.open(file_name, file.WRITE)
    file.store_string(status.to_json())
    file.close()
    print("Status saved to: "+file_name)

There seems to be an error in the code you provided @wombatstampede, in the save_status() functions, it gives me an error in the line,

file.store_string(status.to_json())

Nonexistent function to_json in base nil.
How do I fix it?

Do a loadstatus() on app/game start. It will initialize the variable status with the contents of the variable statusinit when no savegame is found.

The error occurs because status has no value (is nil=null). So either do a load_status() before or assign a value to status on your own.

@wombatstampede It is not working, but can you tell me whether this works in Android. Because I am testing this is in Android.

I am using this code in my game on Android as well and confirm that it works there. (as well as on other Platforms like MacOS or Windows)
The key to working savefiles on android is just saving to the user:// space which you did before and I did as well.

"Not working" is very unspecific. Try to connect your android device via USB and start the android app from the IDE with remote-debugging (options available from the little "antenna" in the upper screen center). It should show all output of "print" in the output tab.

Also you can check what is actually written to the androids user directory. (Depends on android version. I.e.: "/data/data/org.godotengine./files"). If your device is not rooted then you might install an android emulator (those are typically rooted or easy to root) and run/debug it there. (I sometimes use Genymotion but Andy or Nox should work as well.

Or you simply use the "Directory" Class in your game/app to list what actually exists in the user:// directory: http://docs.godotengine.org/en/2.1/classes/class_directory.html?highlight=directory

Hurrah, problem solved.
I don't really know how the problem got solved I was just fiddling around with the code a bit. I exported it to Windows just to test it and surprisingly there were no problems and it worked fine.
I then exported it to Android and tested it, there were a few strange problems in the start and then I realized the previous test exports that I had been doing had changed the 'user://save_game.dat' file. So I uninstalled the app from the device and then reinstalled the apk that I had transferred to the device through bluetooth. And then it worked fine.

Thanks everyone for taking your time to solve my problem!

Please log in or register to answer this question.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.