Looking for the best way to handle multiple scenes.

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

Hi,

Is there a better way to handle multiple scenes?

Currently using this:

export(String, FILE, "*.tscn") var world_scene

func _physics_process(delta):
    var bodies = get_overlapping_bodies()
    for body in bodies:
        if body.name == "Player":
                get_tree().change_scene(world_scene)

Hi folks,

I just noticed ChangeScenesHelper on the AssitLib in Godot.

GitHub - PedroSTVeras/AssetChangeScenes: Godot Asset to help with scene transitions, using triggers and itens in the scene

Too bad the asset has a 404 error during download.
At least the Github version is there.

GodotUser | 2019-07-31 22:54

:bust_in_silhouette: Reply From: BraindeadBZH

In my own opinion, managing multiple scene is easier with a main scene that never change and the others scene preloaded using the preload function. Then to simply instantiate them and add them as a child of the main scene. Don’t forget to call queue_free on the scene instances no longer needed.

Thanks for the input.

GodotUser | 2019-08-01 21:20

:bust_in_silhouette: Reply From: Dlean Jeans

Better scene export variable:

export(PackedScene) var world_scene

Thanks for the input.

I identified the problem in my code.

The Player script carries over into World2 but the WorldComplete script does not work.

I have been trying to implement the later as a Global script but have not got it to work yet.

GodotUser | 2019-08-01 21:24

:bust_in_silhouette: Reply From: SvapoManiac

Yes, there is.
I’m currently working on a singleton class “LoadManager” which will load the scene/scenes needed in one main scene using an InteractiveLoader that works in parallel with a loading scene i’ll release it soon as a Platformer Game Starter Kit in the AssetLib

With this class, there’s a function like change_scene_to but called goto_scene
it has some more arguments
and it works like this

gotoscene("res::pathToScene", string array scenes to destroy, bool destroy all scenes)

there are also basic functions like addScene(string path)
and freeScene(string path) which only works if the scene is found

The last 2 you can use for your multiple scenes, like, if you need an overlay panel like a Pause menu you just do

onready var loadmanager = get_tree().get_root().get_node("Loadmanager")

loadmanager.add_scene("path to scene")

Here’s the loadmanager singleton script, it may help you but you will need to tweak it for your needs because i can’t post here also the loading screen scene

at least it’s a good example for the Loader and InteractiveLoader classes

extends Node

var root
var mainscn
var scenes
var loader
var loadscreen
var animated_val
var processtimer
var label
var tween
var progressbar
onready var time_max = 1000 #msec

func _ready():
	root = get_tree().get_root()
	mainscn = root.get_node("MainScn")
	set_process_internal(true)
	set_process(false)

func show_error(err : String) -> void:
	var errDiag = root.get_node("errDiag")
	if(errDiag == null):
		errDiag = ConfirmationDialog.new()
		errDiag.set_name("errDiag")
		errDiag.set_title("Runtime Error!")
		root.add_child(errDiag)
	
	errDiag.set_text("Error Code: " + err)
	errDiag.popup_centered(errDiag.get_minimum_size())
	
func getActiveScenes() -> Array:
	scenes = mainscn.get_children()
	return scenes
	
func free_scene(name : String):
	return call_deferred("def_free_scene", name)
	
func goto_scene(path : String, scenes_to_destroy, freeAll : bool): #remvoe all other scenes
	return call_deferred("def_goto_scene", path, scenes_to_destroy, freeAll)

func _add_scene(path : String):
	var tmp = ResourceLoader.exists(path)
	var scene
	if( tmp ):
		var rl = ResourceLoader.load(path)
		scene = rl.instance()
		mainscn.add_child(scene)
	else:
		show_error("ResourceLoader.exists(" + path as String + ")" + " returned: " + tmp as String)
		return false
	return scene
	
func def_free_scene(name : String) -> bool:
	getActiveScenes()
	var count = scenes.size()
	var found = false
	
	while (count != 0):
		if(scenes[count].get_name() == name):
			found = true
			break;
		count -= 1
	if(!found):
		show_error("def_free_scene(name : String), could not find the scene (" + name + ") to free")
		return false
		
	scenes[count].queue_free()
	return true

func def_goto_scene(path : String, scenes_to_destroy, freeAll : bool) -> void:
	
	#FREE SCENES
	if (!freeAll and scenes_to_destroy != null):
		var count = scenes_to_destroy.size()
		while (count != 0):
			scenes_to_destroy[count-1].queue_free()
			count -=1
	elif (freeAll):
		var count = getActiveScenes().size()
		while (count != 0):
			scenes[count-1].queue_free()
			count -=1
	
	loader = ResourceLoader.load_interactive(path)
	if loader == null: # check for errors
		show_error("ResourceLoader.load_interactive(" + path as String + ")")
		return
		
	loadscreen = ResourceLoader.load("res://LoadingScn.tscn")
	loadscreen = loadscreen.instance()
	mainscn.add_child(loadscreen)
	
	label = root.get_node("MainScn/LoadingScn/loadbg/CenterContainer/VBoxContainer/LoadLabel")
	tween = root.get_node("MainScn/LoadingScn/loadbg/CenterContainer/VBoxContainer/tween")
	progressbar = root.get_node("MainScn/LoadingScn/loadbg/CenterContainer/VBoxContainer/progressbar")
	processtimer = root.get_node("MainScn/LoadingScn/Timer")
	processtimer.connect("timeout", self, "_processing")
	processtimer.start()
	#set_process(true)

func _processing() -> void:
	var err
	var resource
	
	if(loader == null):
		show_error("while pooling resource")
		return
	
	#while(OS.get_ticks_msec() < (t + time_max)):
	err = loader.poll()
	if(err == ERR_FILE_EOF):
		resource = loader.get_resource()
		resource = resource.instance()
		mainscn.add_child(resource)
		loader = null
		loadscreen.queue_free()
		return
	elif(err == OK):
		update_progress()
		return
	else:
		loader = null
		show_error("while pooling resource")
		return 

func update_progress() -> void:
	var progress = float(loader.get_stage()) / loader.get_stage_count()
	
	label.set_text("Loading.. " + loader.get_stage() as String + " / " + loader.get_stage_count() as String)
	
	tween.interpolate_property( loadscreen, 'animated_val',
								progressbar.get_value(), (progress*100),
								0.4, Tween.TRANS_QUAD, Tween.EASE_IN_OUT)
	if (!tween.is_active()):
    	tween.start()

Thanks for the detailed answer.

I’ll look it over and try to figure out what works for me.

GodotUser | 2019-07-31 22:26

Thank you very much for putting this answer as the best one! Enjoy the singleton Hahah
if you need any help you can contact me on telegram/discord as PrometeoPrime

SvapoManiac | 2019-08-01 09:17