0 votes

I followed the tutorial for saving in Godot 3, and implemented it in my game with only minor changes (the official Godot saving docs tutorial had some errors) but otherwise I implemented it with no changes. I set a door to be a persistent object, and I save a handful of variables including the rotation of the door. However, when I load the door I am unable to refer to the door via get_node or via signals. The door otherwise behaves as expected, and my signals work if I do not load the game.

Interestingly, when I save the game with the door and then delete the door before running the game, it works perfectly - loading only one copy of the door, from the save. To check my theory, I print(name) in the ready of the door and it prints two names - Door, and @Door@6 - I assume this is the name it is was given after loading, but I am not sure why.

I have attached the appropriate code, hopefully someone can indicate what the problem is and how I should resolve it.

Thanks a pile.

Loading code:

func load_game():
    var save_game = File.new()
    if not save_game.file_exists("res://savegame.save"):
        return # Error! We don't have a save to load.

    # We need to revert the game state so we're not cloning objects during loading. This will vary wildly depending on the needs of a project, so take care with this step.
    # For our example, we will accomplish this by deleting savable objects.
    var save_nodes = get_tree().get_nodes_in_group("Persist")
    for i in save_nodes:
        i.queue_free()

    # Load the file line by line and process that dictionary to restore the object it represents
    save_game.open("res://savegame.save", File.READ)
    var current_line = parse_json(save_game.get_as_text())
        # First we need to create the object and add it to the tree and set its position.
    var new_object = load(current_line["filename"]).instance()
    get_node(current_line["parent"]).add_child(new_object)
    new_object.position = Vector2(current_line["pos_x"], current_line["pos_y"])
        # Now we set the remaining variables.
    for i in current_line.keys():
        if i == "filename" or i == "parent" or i == "pos_x" or i == "pos_y":
            continue
        new_object.set(i, current_line[i])
    save_game.close()

Saving Code:

func save_game():
    var save_game = File.new()
    save_game.open("res://savegame.save", File.WRITE)
    var save_nodes = get_tree().get_nodes_in_group("Persist")
    for i in save_nodes:
        var node_data = i.save();
        save_game.store_line(to_json(node_data))
    save_game.close()

Save file contents: {"doorstop":false,"filename":"res://Maps/Door.tscn","name":"Door","parent":"/root/TestMap","posx":24.874701,"pos_y":233.261993,"rotation":0}

in Engine by (14 points)

1 Answer

0 votes

To see if you are saving and referencing it correctly, check the remote tree when running, and look at the debugger, add breakpoints, etc.

You may need to reconnect some signals too when loaded.


About saving, do not save on res:// because it won't work on export, that is the game's virtual filesystem, save it on user:// which is the game's data folder.

And please report any error or inconsistency you do see in the docs at the documentation repository (check first on "latest" docs to see if it is not already fixed for the next version).

by (7,860 points)

Thanks for the note on :res// will change that.

I actually had no idea that the remote tree existed! Super useful debug tool. Anyhow, I checked out the remote tree during runtime and saw that the node "Door" did not exist (My loader queue_free's that, so not surprising) but that in it's place was "@Door@7"

In another part of my code, I call

connect("room_clear", get_parent().get_node("Door"), "perma_open")

I imagine it isn't working because "Door" no longer exists and has become "@Door@7" I replaced "Door" with "@Door@7" in the connect and it worked, however I do not understand why it was being switched to something other than simply "Door" when I load it - should it not queue_free the door and replace it with an identically named scene?

I looked into it further, and it seems to be an issue when I instance the object, it gets instanced with a name of @nodename@7. I am passing the correct node name.

EDIT: The problem line is specifically

get_node(current_line["parent"]).add_child(new_object)

Try to not depend on names on dynamic objects, because the tree will rename them if these are repeated, try instead to store a reference when creating and use it for restoring connections with other nodes.

I currently connect the code by calling

connect("room_entered", get_parent().get_node("Fog"), "_reveal")

How should I reference the code if not by name? How do I go about storing a reference to it when I create it?

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.