Cannot change scene after implementing transition animation

Hello - I’m trying to code a door function that can be used to code both doors that require toggles and doors you can automatically walk through, but whenever I try to implement the transition animation (a simple fade to black and out) the code does not work.

The error listed states Cannot call method 'change_scene_to_file' on a null value., but taking out the transition allows the code to work again. Even more, this error only seems to apply to the bottom statement. Does anyone know why this is?

func _physics_process(_delta: float) -> void:
# Enter door on key input- works both with and without transition
	if entered==true and autoEnter ==false:
		if Input.is_action_just_pressed("ui_accept"):
			transFade.play('dissolveIN')
			await transFade.animation_finished
			transFade.play('dissolveOUT')
			get_tree().change_scene_to_file(GoToScene)
#enter door on input - works without transition only
	if entered==true and autoEnter==true:
		transFade.play('dissolveIN')
		await transFade.animation_finished
		transFade.play('dissolveOUT')
		get_tree().change_scene_to_file(GoToScene)

This error means that in your get_tree().change_scene_to_file(GoToScene) line, the get_tree() part returns null, so you’re calling change_scene_to_file() on a null value, which is something you shouldn’t be doing, hence the error.

In general, this means that the node you’re calling this code from, is not part of the tree yet/anymore. It’s hard to tell what is the best solution for this without knowing the rest of the logic, but simply adding get_tree() != null check will at least solve the error.

	if entered==true and autoEnter==true and get_tree() != null:
		transFade.play('dissolveIN')
		await transFade.animation_finished
		transFade.play('dissolveOUT')
		get_tree().change_scene_to_file(GoToScene)

You can try if this will fix your problem entirely, or if anything else will come up afterwards.

Hi,
Thank you for your input! I tried implementing the code you provided, but it still provides the same error. if it helps, here’s the rest of my code below. I understand what the error is telling me, however what confuses me is that it works just fine - the transition animation playing is what seems to be what’s causing issues.

Rest of the code
var entered :=false
@export_file var GoToScene
@export var autoEnter :=false

@onready var doorSound = $doorSound
@onready var transFade = $transition/fade

func _physics_process(_delta: float) -> void:
	if entered==true and autoEnter ==false:
		if Input.is_action_just_pressed("ui_accept"):
			doorSound.play()
			doorSound.pitch_scale=randf_range(1,1.2)
			#function wont work so scuffed "transition ->changescene
			transFade.play('dissolveIN')
			await transFade.animation_finished
			transFade.play('dissolveOUT')
			get_tree().change_scene_to_file(GoToScene)
	if entered==true and autoEnter==true:
		transFade.play('dissolveIN')
		await transFade.animation_finished
		transFade.play('dissolveOUT')
		get_tree().change_scene_to_file(GoToScene)
		

func _on_body_entered(_body:CharacterBody2D ) -> void:
	entered=true
func _on_body_exited(_body: CharacterBody2D) -> void:
	entered=false

Since this is in _physics_process(), you’ll most likely have multiple function calls stacking up on the await. And when the animation is finished, all of those waiting _physics_process() calls will continue and try to change the scene; but only the first will be successful.
(I would assume the first if-statement will also cause the error if “ui_accept” is pressed multiple times.)

Checking if get_tree() is still valid could work, but that probably needs to happen after the await:

		#...
		await transFade.animation_finished
		transFade.play('dissolveOUT')
		if get_tree() != null:
			get_tree().change_scene_to_file(GoToScene)

A better fix would be to make sure the whole transition procedure can only start once (by using an additional bool or so).

2 Likes

This ended up working, thank you so much!