0 votes

So I created two scenes named scene_a and scene_b Scene_a had a continue button which I just connected to a main scene_a script with just a simple code like this..... func oncontinuebuttonpressed():
gettree.changescene("res://Scenes/scene_b.tscn")

This made it so when I clicked the ContinueButton it changed to scene_b.

In scene_b I have a control node with a script, I added a player (KinematicBody2D) then I followed the Godot docs Saving tutorial, which I then got this code into my Control Node Script this is what the code looked like in the Control Node (Btw there are correct spacing it just didn't load)


extends Control

func _ready():

    set_process(true)

    var savenodes = get_tree().get_nodes_in_group("Persist")
    for i in savenodes:
        pass

func _process(delta):
    if Input.is_action_pressed("ui_left"):
        get_node("player").move(Vector2(-5, 0))

func save():
    var savedict = {
        filename=get_filename(),
        parent=get_parent(),
        posx=get_pos().x,
        posy=get_pos().y
    }
    return savedict

func save_game():
    var savegame = File.new()
    savegame.open("user://savegame.save", File.WRITE)
    var savenodes = get_tree().get_nodes_in_group("Persist")
    for i in savenodes:
        var nodedata = i.save()
        savegame.store_line(nodedata.to_json())
    savegame.close()

func load_game():
    var savegame = File.new()
    if !savegame.file_exists("user://savegame.save"):
        return

    var savenodes = get_tree().get_nodes_in_group("Persist")
    for i in savenodes:
        i.queue_free()

    var currentline = {} # dict.parse_json() requires a declared dict.
    savegame.open("user://savegame.save", File.READ)
    while (!savegame.eof_reached()):
        currentline.parse_json(savegame.get_line())
                # First we need to create the object and add it to the tree and set its position.
        var newobject = load(currentline["filename"]).instance()
        get_node(currentline["parent"]).add_child(newobject)
        newobject.set_pos(Vector2(currentline["posx"],currentline["posy"]))
        # Now we set the remaining variables.
        for i in currentline.keys():
            if (i == "filename" or i == "parent" or i == "posx" or i == "posy"):
                continue
                newobject.set(i, currentline[i])
                savegame.close()

func _on_MenuButton_pressed():
    get_tree().change_scene("res://Scenes/scene_a.tscn")

Then I wanted to make it so I could go back to the menu screen ( Just above )
then when I click on the continue button again I should reload my KinematicBody2D's position right? ( I added a move function so I could see if it would reload it's current pos ) But nothing happens. I don't get any errors, just nothing. I've read the Docs many times and they explain it in a way that I can''t really understand...

Well rip, anyone have any ideas?

in Engine by (20 points)
edited by

1 Answer

0 votes

Where do you have the save() function declared? It should be on your player script (the KinematicBody?) The save_game() and load_game() functions should be on the Control node.

The idea is, your "game manager" object (your Control node in this case I assume) will, in save_game(), go through each object in the "persists" group (which you added the player KinematicBody to) and calls a method on them called save(). Every persistent object in your scene should also have a save() function:

var savenodes = get_tree().get_nodes_in_group("Persist")
for i in savenodes:
    var nodedata = i.save()
    savegame.store_line(nodedata.to_json())

Every persistent object in your scene should also have a save() function.
NOTE: You can highlight the code blocks you paste into your posts and hit ctrl+k to put it into code formatting.

by (1,330 points)

Thank you for your reply, just two questions, how would I call the save() function in the KinematicBody2D? Also if I created a global script, could I use all of this save script of in the globalscript and if I did how would I call it? (1 more thing, the code you showed, was that something I should switch out in the code I used?)

-InStG

how would I call the save() function in the KinematicBody2D?

Your save_game function is calling the save() function on your player. The code snippet I posted shows the part of the code that's doing that. Maybe we'll break down the lines and see what's happening:

var savenodes = get_tree().get_nodes_in_group("Persist") 

-Here we create the variable 'savenodes' and have it become an array containing all the nodes that have been added to the "Persists" group. if you followed this line with print(savenodes), you should see an output that looks like [KinematicBody@241]

for i in savenodes:

-Here we iterate through each item in our list called savenodes, and call the code indented below it for each item, calling that item "i"

    var nodedata = i.save()  

-This is where we're getting the actual data to save from the player. if "player" = "i", than "i.save()" can translate into "call save() on the player object". When you have more objects in your Persists group, this line will be called on each one. Each time, it will create this variable nodedata which contains a dictionary of that node's data (everything that's returned from the save() function).

savegame.store_line(nodedata.to_json())  

-This takes that nodedata and writes it to your save file

could I use all of this save script of in the globalscript and if I did how would I call it?

Yes, absolutely! If your save_game() code exists in a singleton you call "Data", you just call it (from anywhere!) with Data.save_game()

Hopefully the first answer answers your third question :)

Thanks for the reply, I just have a little problem, I created a global.gd script, and in the global script I get two errors, it doesn't let me use get_pos and it says Invaild get index 'filename' (on base: 'Dictionary'). When in my savedict I have filename=get_filename()

func save():
    var savedict = {
        filename=get_filename(),
        parent=get_parent().get_path(),
        posx=get_pos().x,
        posy=get_pos().y
    }
    return savedict

As above, what would I use in the global script if it doesn't let me use get_pos? Is it possible to save the position of the actor in the global script?

Edit: In my Level1 Scene I have a control node with a script, this is what I did,

extends Control

func _ready():
    set_process_input(true)
    global.load_game()
    pass

When I delete global.loadgame() Everything works, when I add it back, I get the errors as shown above.
Am I doing this part wrong, or the part above? :P

I'm close to getting this, thank you for all the help so far :)

any ideas?

Again.
Where do you have the save() function declared? It should be on your player script (the KinematicBody, which has the methods set_pos() and get_pos()) The savegame() and loadgame() functions should be in the global script.

This really isn't that complex a concept. Don't take this the wrong way, but how have you managed to make the game that goes around this save/load system?

I don't need help anymore, I found out another way. Thanks for all the help, sorry im pretty new to coding (moved Contruct 2 and stencyl) I don't know why I struggled on this a lot, again

thanks

helped me further more understand the engine :3/

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.