Background loading doesn't work? Loading bar updates correctly but then freezes when adding child anyway

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Cahoots

In my game I have a menu where I select different levels which are each different scenes. Going to the scenes causes the game to freeze while it loads though, so I followed the documentation’s tutorial for the background loader (Background loading — Godot Engine (stable) documentation in English).

I have a loading bar that updates with the background loading progress and that works correctly, but it still freezes before the scene actually changes and I can’t figure out why.

Here is the relevant code I’m using:

To start the loading:

func goto_level(path):
 score = 0
 call_deferred("_deferred_goto_level", path)

func _deferred_goto_level(path):
 if use_loader == true:
	loader = ResourceLoader.load_interactive(path)
	if loader == null:
		print("error happened")
	wait_frames = 1

To process the loading:

func _process(delta):
 if loader == null:
 if wait_frames > 0:
	wait_frames -= 1
 var err = loader.poll()
 if err == ERR_FILE_EOF:
	var resource = loader.get_resource()
	loader = null
 elif err == OK:
	var progress = round(float(loader.get_stage()) / loader.get_stage_count() * 30)
	loading_bar.value = progress
	print("error while loading")
	loader = null

Then to set the scene after it’s loaded:

func set_new_level(scene_resource):
 current_level = scene_resource.instance()
 call_deferred("add_child", current_level)

The tutorial had a while loop in the process function but that was even worse and resulted in the game freezing for the entire loading and the loading bar not updating, not just when the scene is added.

I have created my own module for similar tasks. You can have a look or even use it AppDelegate. It works for any version of Godot

P.S. For a solution to your problem, look towards Threads

kurtsev0103 | 2021-10-27 08:56

:bust_in_silhouette: Reply From: gnumaru

kurtsev0103 comment is right. You should use a Thread:

The thing is that the ResourceInteractiveLoader returned from ResourceLoader.load_interactive() is not a background loader, it is just interactive, that is, it can break up loading in steps instead of doing all steps at once, but each step is synchronous and on the same thread as the caller. If you have one resource that has only one load step, but that load step takes 5 seconds, then using the interactive loader has no difference from just using the built in load() function.

If you just use a load() call but on another thread, the game should not freeze.