Search code examples
nullsaveinstancegodotgdscript

In Reference class - The method "get_tree()" isn't declared in the current class error in Godot


I am currently working on my game's save and load states, and I created a global script to use it. The script extends Reference class and uses the .dat file extension for saving and loading files. But I can't use the method get_tree() in the script. I get the error: The method get_tree() isn't declared in the current class.

I think the problem is that Reference is not connected to the SceneTree. So I tried using a player instance and use get_tree() on that like this:

const PLAYER_CHARACTER = preload("res://Player/Player.tscn")

var player = PLAYER_CHARACTER.instance()

player.get_tree().change_scene("res://Map/" + player_data.scene)

But then I get this error: Attempt to call function 'change_scene' in base 'null_instance' on a null instance.

I am a little confused on how to change the scene from this script when I load a save file. I need this to complete my save and load states. The code is here:

extends Reference

get_tree().change_scene("res://Map/" + player_data.scene)

I appreciate any kind of explanation on why this is the case and any godot docs that can help me better understand this issue.


Solution

  • The method get_tree exists in Node (and derived classes). Notice that Nodes exists in the scene tree.

    However Reference has no relationship with the scene tree.

    Furthermore, news: You can create, from code, multiple SceneTrees (not something you need to do for 99.99% of games, but the option is there).

    Therefore, it is not a concern of Reference to be able to get the SceneTree, and if it were, it won't be clear which one to get.


    The issue with this code:

    const PLAYER_CHARACTER = preload("res://Player/Player.tscn")
    
    var player = PLAYER_CHARACTER.instance()
    
    player.get_tree().change_scene("res://Map/" + player_data.scene)
    

    Is that get_tree() gives you null because the instance player is not in a SceneTree.


    Now, presumably you want the default SceneTree. For that there is a work around:

    var scene_tree := Engine.get_main_loop() as SceneTree
    

    The SceneTree class extends the MainLoop class. And by default, the main loop of Godot uses an instance of SceneTree.

    So the above line of code would work unless you changed the type of the main loop to something else. Which, again, you can (probably not something you would do for a game, but for some utility applications it makes sense - Yes, using Godot for non-game software).


    With that said, I would like to encourage you to look for a different design. For changing the current scene we would often use an Autoload (singleton), which become available from everywhere in the scene tree, plus they persist when the scene changes.

    Keep in mind that extending Reference will make your class reference counted.