godotengine / godotengine/godot-docs

Teach how to work with `change_scene_to_packed` and `change_scene_to_file`

Open
#8,868 2 comments 5 reactions 0 assignees View on GitHub
enhancement
Dominant language
reStructuredText
Stars
5.7k
Forks
3.8k
Avg merge
1d 20h
Merged PRs (30d)
25

Description

## Your Godot version:
4.2.1

## Game context:
1. Player leaves level
2. Screen fades to black
3. Scene is switched
4. Black fades away to reveal the new scene

## Issue description:
I just upgraded Godot and now **logic executed directly after scene switching** (via change_scene_to_packed) is broken. I assume due to the following ([docs](https://docs.godotengine.org/en/stable/classes/class_scenetree.html#class-scenetree-method-change-scene-to-packed)):
> 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.

I generally like that the behaviour is now more predictable ... but I couldn't find any information on how to work with it.

**What didn't work:**
- `await get_tree().process_frame` -> Doesn't work due to `get_tree()` being null
- `await get_tree().create_timer(duration).timeout` -> Doesn't work due to `get_tree()` being null
- `await Engine.get_main_loop().process_frame` didn't work ([idea source](https://www.reddit.com/r/godot/comments/12z75k4/how_to_await_1_frame_without_get_tree/))
- `call_deferred()` -> Never got triggered (I assume because scene didn't exist anymore)
- No signal exists like `tree_created()`

**What would have worked:**
- I assume the new scene's `_ready` function would have triggered correctly but as the transitions should happen in each level switch I didn't want to add code to each level's `_ready`-function

## My current workaround
In one scene – e.g. `level_1` – I now call the autoload singleton `LevelSwitcher.switch_to("res://level_2.tscn")` instead of executing the code directly. This works, but my approach to detect the new scene is really dirty (see below).

### `level_switcher.gd`

```gdscript
extends Node

var current_scene
signal scene_changed

func _process(delta):
# Feels dirty
if current_scene != get_tree().get_current_scene():
emit_signal("scene_changed")
current_scene = get_tree().get_current_scene()

func switch_to(scene_file_path):
# 1. Trigger "leaving level"-transition and await its end

# 2. Switch scene
var scene = ResourceLoader.load_threaded_get(scene_file_path) # This was loaded before somewhere else
get_tree().change_scene_to_packed(scene)

# 3. Await switch
await scene_changed

# 4. Spawn player and trigger "entering level"-transition
```

## URL to the documentation page (if already existing):
- [Scenetree > change_scene_to_file()](https://docs.godotengine.org/en/stable/classes/class_scenetree.html#class-scenetree-method-change-scene-to-file)
- ["Change scenes manually"](https://docs.godotengine.org/en/stable/tutorials/scripting/change_scenes_manually.html)

## Proposal
Change the "Change scenes manually"-page to "How to change scenes" with the following content:
- **Automatic scene switching:** Most basic example for `change_scene_to_file`
- **Automatic scene switching (advanced):** Loading scene in the background using `change_scene_to_packed` and trigger something right after the scene switch (I still don't know how to do this correctly)
- **Manual scene switching:** The content the page currently is focussed on

This probably relates to #8846

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.