如何在不破坏(释放)我要离开的场景的情况下切换场景?

How can I switch between scenes without destroying (freeing) the scene I'm leaving?

嘿,我的游戏里有战斗。目前,战斗是一个单独的场景,当玩家走向 NPC 时,我们有一点过渡,然后离开场景,我们进入战斗场景。一旦战斗场景完成,我想 return 到我们之前的场景,一切都完全一样。我目前有一个名为 scene_switcher 的场景切换单例,当前设置为

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

当我们进入战斗时,我使用

scene_switcher.change_scene("res://battlescene.tcsn", {players_deck, opponents_deck})

原样存储当前场景,并将玩家数据传递给战斗场景。

一旦战斗结束,我会调用 return_to_previous_scene(),当满足其中一个胜利条件时,我会调用

scene_switcher.return_to_previous_scene()

但是我得到了错误:

Attempted to free a locked object (calling or emitting).

我已经尝试根据此代码将调用推迟到空闲时间 on the singleton autoload page of the docs 但是当我这样做时:

 call_deferred("scene_switcher.return_to_previous_scene") 

它永远不会被调用(game_over 函数工作,它打印出结果,我的其他测试让它与下面的代码一起工作,我认为场景永远不会空闲,这意味着代码永远不会有机会开火)

现在我可以使用:

scene_switcher.change_scene("res://map.tcsn", {})

但这会将场景恢复到原始状态并且可扩展性不强(如果我可以在 12 个不同级别与人战斗,我怎么知道要加载哪个场景?)

那么如何停止当前场景。离开,然后return 带着我前一幕的一切离开怎么办呢?谢谢:)

我问这个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

Their answer:

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.

我没有正确使用 call_deferred。

我还对 change_scene 中的场景使用 duplicate() 进行了细微修改,以保留未释放的副本。

所以

global_data.previous_scene = get_tree().get_current_scene()

变成了

global_data.previous_scene = get_tree().get_current_scene().duplicate()

现在可以正常工作了:)