Hey there in my game there are battles. Currently the battle is a separate scene and when a player walks up to an NPC we have a little transition and then leave the scene and we go to the battle scene. Once the battle scene is completed I want to return to the previous scene we were at with everything exactly the same. I currently have a scene switching singleton called scene_switcher with the current setup
extends Node
var _params = null
func change_scene(next_scene, params = null):
_params = params
# global_data is another singleton I use for storing state and other global data
global_data.previous_scene = get_tree().get_current_scene()
get_tree().change_scene(next_scene)
func return_to_previous_scene(params = null):
_params = params
get_tree().get_current_scene().free()
get_tree().get_root().add_child(global_data.previous_scene)
get_tree().set_current_scene(global_data.previous_scene)
func get_param(name):
if _params != null and _params.has(name):
return _params[name]
return null
when we're going into the battle I use
scene_switcher.change_scene("res://battlescene.tcsn", {players_deck, opponents_deck})
which stores the current scene exactly as it is and passes over player data to the battle scene.
once the battle is over I call return_to_previous_scene()
which I call when one of the victory conditions is met like so
scene_switcher.return_to_previous_scene()
however I get the error:
Attempted to free a locked object (calling or emitting).
I've tried deferring the call to idle time based off of this code on the singleton autoload page of the docs however when I do:
call_deferred("scene_switcher.return_to_previous_scene")
it never gets called (the game_over function works, it prints out the result and my other tests have it working with the code below, I think the scene never idles which mean the code never gets a chance to fire)
Now I can use:
scene_switcher.change_scene("res://map.tcsn", {})
but that reverts the scene back to it's original state and is not very scalable (how will I know which scene to load if I can battle people in 12 different levels?)
So how can I halt the current scene. leave, and then return to the previous scene with everything how I left it? Thanks :)
I asked this same question on reddit and got an answer that solved my problem. Copying over here for anyone who might find this question in the future. All credit to /u/thomastc
call_deferred takes a method name only, so:
scene_switcher.call_deferred("return_to_previous_scene")
Alternatively, just use queue_free instead of free, to defer only the freeing.
I was not using call_deferred correctly.
I also made the slight modification of using duplicate()
on the scene in change_scene
to keep a copy that isn't freed.
so
global_data.previous_scene = get_tree().get_current_scene()
became
global_data.previous_scene = get_tree().get_current_scene().duplicate()
which now works as expected :)