Change scene and call functions when scene is ready

Godot version 4.1

In general I’m looking for the best way to change to a new scene, and be able to know when that scene is ready before calling other functions. (maybe by accessing that scene’s signals so I know when it’s ready/entered_tree/etc.)

Specifically, I’m trying to do a transition animation when changing scenes that I want to start playing as soon as the scene I’m changing to is ready. I have an autoload with a TextureRect/AnimationPlayer, and a script with a function transition_scene(new_scene_path), which is supposed to change the scene, and afterwards calls a function which animates the TextureRect.

The issue is that if I call:

get_tree().change_scene(new_scene_path)

or

get_tree().change_scene_to_packed(new_scene_packed),

and then call:

animation_player.play(“transition”),

The animation plays fine for smaller scenes, but seems to get cut off/doesn’t play for larger ones (with more nodes). It seems like the animation starts playing while the scene is still being changed/loaded, so if it takes longer for the scene to change than the animation, it gets cut off.

What I want is to await the new scene’s ready signal (or any similar signal or any other way of waiting until the scene has actually finished changing) before starting the animation. It doesn’t look like I can do that if I use the change_scene.
functions, since I don’t actually have access to the new scene (just the path/packed scene args), and there doesn’t appear to be any signals emitted by change_scene to let you know when it’s done changing. I also can’t just access get_tree().current_scene after calling change_scene(), since it doesn’t change until the next frame, which is written in the the change_scene function descriptions in the SceneTree docs.

I tried looking at the ‘Change scenes manually’ page in the docs:
(Change scenes manually — Godot Engine (stable) documentation in English)
It looks like to get the same effect as the change_scene functions, you have to do a bunch of stuff with queue_free()s and waiting frames. I could probably do this but wanted to know if there is a simpler way, or a more detailed example than the descriptions given.

I also tried the ResourceLoader.load_threaded_request() way of loading based on the docs/a few tutorials, and it doesn’t make a difference as long as I’m still using the change_scene functions without waiting before calling the start_animation function.

Again, the main thing I’m looking for is a way to change to a new scene and then call functions when that scene’s ready signal is emitted (or some similar signal/way of knowing when the scene is done changing). If I’m way off on the way I’m doing transition animations/autoloads/if you need to see my code, let me know, but I’d still like to know in general how to only call functions after a changing to a scene. Thanks.

1 Like

it’s actually quite surprisingly easy to change scene without the built-in screen tree’s change to scene method

this following answer shows the code snippet how to change scene:

You can connect to the signal child_entered_tree on the root node using a one-shot callback (so it runs only once). You can even directly access the new scene’s node instance with type-safety.

func load_next_scene() -> void:
  var tree: SceneTree = get_tree()
  tree.change_scene_to_packed(my_game_scene)
  tree.root.child_entered_tree.connect(
    (func (scene: MyGameSceneNode) -> void:
      assert(scene == tree.current_scene) # at this point it's set
      scene.level_data = next_level_data # pass custom data or whatever
    ),
    CONNECT_ONE_SHOT
  )

The change_scene_to_packed method does not re-add auto-load nodes, so we know the only node added as a direct child of root is our desired scene.

This runs after tree_entered, but before @onready. So child nodes might not be available yet, I think, but at least you can pass data between scenes, or set up other callbacks from there.