+1 vote

For my first project, I've started making a Flappy Bird-type game, following the excellent tutorials by Edward (AngegaStudios on Youtube). I've worked ahead a little bit though because I'm eager to get this project finished, and I've got everything working as intended now... except saving the best score in a savegame, so it's still there after closing the game.

The two relevant files:

First, game.gd, which is a global script:

#script: game

extends Node

const GROUP_PIPES = "pipes"
const GROUP_GROUNDS = "grounds"
const GROUP_BIRDS = "birds"

var score_best = 0 setget _set_score_best
var score_current = 0 setget _set_score_current

var savegame = File.new() #file
var save_path = "user://savegame.save" #place of the file
var save_data = {"highscore": 0} #variable to store data. Should it be 0, or should it be score_best?

signal score_best_changed
signal score_current_changed

func _ready():
    if not savegame.file_exists(save_path): #if the save game doesn't exist...
        create_save() #...create it! Function down below...
    read_savegame() #load (read) the savegame when the game starts
    stage_manager.connect("stage_changed", self, "_on_stage_changed")
    pass

func create_save(): #The function to create the savegame
    savegame.open(save_path, File.WRITE) #open file to write
    savegame.store_var(save_data) #store the content of the save_data variable
    savegame.close() #close the savegame

func save(score_best): #The function to save the game; I want it to save the score_best variable contents
    save_data["highscore"] = score_best #data to save 
    savegame.open(save_path, File.WRITE) #open file to write
    savegame.store_var(save_data) #store the data
    savegame.close() #close the file

func read_savegame(): #The function to load the game
    savegame.open(save_path, File.READ) #open the file
    save_data = savegame.get_var() #get the value
    savegame.close() #close the file
    return save_data["highscore"] #return the value

func _on_stage_changed():
    score_current = 0
    pass

func _set_score_best(new_value):
    if new_value > score_best:
        score_best = new_value
        emit_signal("score_best_changed")
    pass

func _set_score_current(new_value):
    score_current = new_value
    emit_signal("score_current_changed")
    pass

Next, a snippet from hboxscorebest, where I try to save the game whenever the best score has changed:

func _on_score_best_changed(): #when the best score has changed...
    set_number(game.score_best) #...first change the score_best variable in game.gd...
    game.save(game.score_best) #...and then save the game

I'm honestly not sure if that last line is even correct. I followed this post which is the only way I've found to save that doesn't crash my game... as long as I pass an argument in that last function call, which I just can't really figure out why. If I don't pass an argument, I receive the following error:
"Invalid call to function 'save' in base 'Node (game.gd)'. Expected 1 arguments."
And if I do pass an argument, the game runs fine, but it doesn't get saved. At all.

So... yeah. I need a bit of help here ^_^ I'm so close to finishing my project, but this has been frustrating me for a while now!

in Engine by (16 points)

1 Answer

+2 votes
Best answer

I fiddled with this code a bit and it's definitely saving.

I noticed that you don't appear to be setting score_best after loading the data. In read_savegame, you return save_data["highscore"], but you don't appear to catch/use the returned value anywhere. Perhaps that's the problem?

func read_savegame():
    savegame.open(save_path, File.READ)
    save_data = savegame.get_var()
    savegame.close()
    return save_data["highscore"] ## here

Also, save is giving an error if you don't pass it an argument because:

func save(score_best): ## you are asking for one when you define the function
    ...

If you want to use score_best, which already exists as a member variable, you don't need to declare it as an argument.

func save(): ## this will work
    save_data["highscore"] = score_best
    ...

One small suggestion...
The create_save function is unnecessary. You can simply check if a save exists and only call read_savegame if it does.

func _ready():
    if savegame.file_exists(save_path):
        read_savegame()

Or check for it in read_savegame like so:

func read_savegame():
    if savegame.file_exists(save_path):
        savegame.open(save_path, File.READ)
        save_data = savegame.get_var()
        savegame.close()
    return save_data["highscore"]
by (464 points)
edited by

Thank you very much! My problem is solved now :)

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.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.