cannot call method create_timer on a null value

4.3.stable Godot Version Question

Godot seems to freak out when I call a timer every fourth scene.

to grossly oversimplify, every time when I get to the fourth scene and attempt to call the scene change to the fifth scene, Godot freaks out and does not let me do the scene change. It masks the issue as a timer issue.

I know that it is not a timer issue because of this:

both get_tree.await_timer("") and get_tree.change_scene_to_file("")

In GODOT issue 12,888 “What does get_tree() return?” the solution to it is

[1] get_tree() returns an (or better the) instance of this class. The instance itself then has means to access the nodes inside it. SceneTree itself is not a node, but a descendant of MainLoop. Think of it as a manager class that takes care of updating and managing all the nodes in it while running in an infinite loop until the player exits the game (get_tree().quit())

to grossly oversimplify, get_tree is basically

  1. instantiating both the create_timer(n) and change_scene_to_file lines at once

or

  1. calls await values first and then scene changes later to maximize performance and doing this in a timeframe so short that the difference between the beginning and end is so small that it might as well be instantaneous.

Why it does this at the fourth scene specifically I do not know, just because I typed this up like one of my college essays doesn’t mean I know what I am doing. I have only been doing this for nearly a year and a half, I know for a fact I do not know what I am doing.

To answer anyone’s questions in case they have any:

The script uses only a func _ready(): to handle all 2588 lines of code

the errors popped up at the part of the script that handles enemy AI and the part of the script that respawns the eight crystals needed to overpower enemy AI.

(this is the singleplayer part of a fighting game, so the AI is coded to move in a six point matrix within camera view, or to grossly simplify, something like this:)

the part of the script that freaked out was line 702 - line 705 this part of the script was one of the lines that handles enemy ai

702
703			await get_tree().create_timer(0.00900945946).timeout
704			$P2.position = Vector3(0,43.672,27.86767567567568)
705			

where line 703 specifies the delay it takes for the position to be determined
and line 704 determines the position

this was calculated as a jump within 73 points on the line within 8.333 seconds

the other part of the script that freaked out was the part of the script that handles the crystal resizing or line 1359 to line 1384

1359		if $P1_Fight_GUI/Crystals/C1.size == Vector2(0,0) and $P1_Fight_GUI/Crystals/C2.size == Vector2(0,0) and $P1_Fight_GUI/Crystals/C3.size == Vector2(0,0) and $P1_Fight_GUI/Crystals/C4.size == Vector2(0,0) and $P1_Fight_GUI/Crystals/C5.size == Vector2(0,0) and $P1_Fight_GUI/Crystals/C6.size == Vector2(0,0) and $P1_Fight_GUI/Crystals/C7.size == Vector2(0,0) and $P1_Fight_GUI/Crystals/C8.size == Vector2(0,0):
1360	        await get_tree().create_timer(5).timeout
1361	        $P1_Fight_GUI/Crystals/C1.size = Vector2(59,61)
1362	        $P2_Fight_GUI/Crystals/C1.size = Vector2(59,61)
1363	        await get_tree().create_timer(5).timeout
1364		$P1_Fight_GUI/Crystals/C2.size = Vector2(40,45)
1365		$P2_Fight_GUI/Crystals/C2.size = Vector2(40,45)
1366		await get_tree().create_timer(5).timeout
1367		$P1_Fight_GUI/Crystals/C3.size = Vector2(40,45)
1368		$P2_Fight_GUI/Crystals/C3.size = Vector2(40,45)
1369		await get_tree().create_timer(5).timeout
1370		$P1_Fight_GUI/Crystals/C4.size = Vector2(40,45)
1371		$P2_Fight_GUI/Crystals/C4.size = Vector2(40,45)
1372		await get_tree().create_timer(5).timeout
1373		$P1_Fight_GUI/Crystals/C5.size = Vector2(40,45)
1374		$P2_Fight_GUI/Crystals/C5.size = Vector2(40,45)
1375		await get_tree().create_timer(5).timeout
1376		$P1_Fight_GUI/Crystals/C6.size = Vector2(40,45)
1377		$P2_Fight_GUI/Crystals/C6.size = Vector2(40,45)
1378		await get_tree().create_timer(5).timeout
1379		$P1_Fight_GUI/Crystals/C7.size = Vector2(40,45)
1380		$P2_Fight_GUI/Crystals/C7.size = Vector2(40,45)
1381		await get_tree().create_timer(5).timeout
1382		$P1_Fight_GUI/Crystals/C8.size = Vector2(40,45)
1383	        $P2_Fight_GUI/Crystals/C8.size = Vector2(40,45)
1384		

to grossly oversimplify, the script handles this:


and because get_tree is calling create_timer(n) and change_scene_to_file("") simulataneously it means the game is broken for the player because the way GODOT was desgined was to stop the game if get_tree overlaps (for some reason)

the issue I have is that I don’t know how to program in a failsafe to prevent get_tree overlap
(so the player can access the other scene without the game crashing)

and because I don’t know how to code that in, it results in the game crashing at the fourth scene
(for reasons I do not know)

do you have methods to prevent such a crash from happening? if so, please comment them down below

[1] What does get_tree() return?

1 Like

As explained in the SceneTree.change_scene_to_packed() documentation:

Note: Operations happen in the following order when change_scene_to_packed() is called:
The current scene node is immediately removed from the tree. From that point, Node.get_tree() called on the current (outgoing) scene will return null. current_scene will be null, too, because the new scene is not available yet.
At the end of the frame, the formerly current scene, already removed from the tree, will be deleted (freed from memory) and then the new scene will be instantiated and added to the tree. Node.get_tree() and current_scene will be back to working as usual.

So any subsequent call to get_tree() will return null. Make sure that when you are calling SceneTree.change_scene_to_file() you don’t access get_tree() until the scene has changed. Also make sure that you aren’t calling get_tree() in any place awaiting a timeout after you call change_scene_to_file().

You can guard the call like:

if get_tree():
    await get_tree().create_timer(5).timeout
    # do stuff

But, ideally, just use a Timer node if you are going to chain that many timers.

1 Like

this thread on github also goes over the scene change issue in case you need it for reference:

UPDATE: the problem was that the way I was calling scenes causes C# to crash

instead of:

get_tree().change_scene_to_file("res://your_file_location/your_scene.tscn")

its actually

get_tree().call_deferred("change_scene_to_file","res://your_file_location/your_scene.tscn")

yet again my strategy of copying solutions from forum boards saves the day again