Thank you very much. I had already come up with that example, but I had made some errors. After trying again, I realized that I had accidentally passed the uninstantiated scene class as a parameter instead of the newly created scene object.
Everything works now.
I would like to share the code with you in case others want to switch levels using a loader as well.
Valid for Godot 4.5.1
Global.sd (enabled in Autoload)
This script contains a function that changes scenes and can be called from anywhere in the game.
signal sigPreLoadNextLevel
func change_scene(next_scene_instance):
var tree = get_tree()
var cur_scene = tree.get_current_scene()
tree.get_root().add_child(next_scene_instance)
tree.get_root().remove_child(cur_scene)
tree.set_current_scene(next_scene_instance)
Level_1.gd
The next level is preloaded in the background as soon as a level starts.
func _ready() -> void:
# Trigger pre-loading
Global.sigPreLoadNextLevel.emit()
LevelLoader.gd
The LevelLoader script responds to the preload signal by assembling the new level name and loading the level scene in the background. Once the scene is loaded, you can switch to it.
const LEVEL_FOLDER = "res://scenes/levels/level_"
var NEXT_SCENE
var next_level_path
var allowProcess = false
func _ready() -> void:
Global.sigPreLoadNextLevel.connect(signalFunc_PreLoadNextLevel)
func signalFunc_PreLoadNextLevel():
# Count up level and create level name (Level_2.tscn, Level_3.tscn,...)
var current_scene_file = get_tree().current_scene.scene_file_path
var next_level_number = current_scene_file.to_int() + 1
next_level_path = LEVEL_FOLDER + str(next_level_number) + ".tscn"
# Preload next level
ResourceLoader.load_threaded_request(next_level_path)
# From here on, check the status permanently.
allowProcess = true
func _process(delta: float):
# Check the preloading status
if allowProcess:
var progress = []
var status = ResourceLoader.load_threaded_get_status(next_level_path, progress)
# Preloading done
if status == ResourceLoader.ThreadLoadStatus.THREAD_LOAD_LOADED:
# Disable this process
allowProcess = false
# Get the new level scene
var loaded_scene = ResourceLoader.load_threaded_get(next_level_path)
# Create an instance
NEXT_SCENE = loaded_scene.instantiate()
# Change the scene here or anywhere else you need to.
Global.change_scene(NEXT_SCENE)
In my case, however, I use a Timeout function to change the preloaded scene because I display an animation beforehand.
I hope this example helps others as well.
Jeff