手动更改场景

有时候,有必要更好地控制如何交换场景.如上所述,一个 Viewport 的子节点将呈现给它生成的图像.即使对于"当前"场景之外的节点,这也适用. Autoloads属于这一类,但是一个实例在运行时添加到树中的场景也是如此:

var simultaneous_scene = preload("res://levels/level2.tscn").instance()

func _add_a_scene_manually():
    # This is like autoloading the scene, only
    # it happens after already loading the main scene.
    get_tree().get_root().add_child(simultaneous_scene)
public PackedScene simultaneousScene;

public MyClass()
{
    simultaneousScene = (PackedScene)ResourceLoader.Load("res://levels/level2.tscn").instance();
}

public void _AddASceneManually()
{
    // This is like autoloading the scene, only
    // it happens after already loading the main scene.
    GetTree().GetRoot().AddChild(simultaneousScene);
}

要完成循环并将旧场景替换为旧场景,开发人员可以选择制作.从视图中删除场景有很多策略 Viewport.权衡涉及平衡操作速度和内存消耗以及平衡数据访问和完整性.

  1. 我们可以删除现有场景. SceneTree.change_scene()SceneTree.change_scene_to() 会立即删除当前场景.不过开发者也可以删除主场景.假设根节点的名字是 "Main",可以执行 get_node("/root/Main").free() 来删除整个场景.

    • 卸载内存.

      • 好处: RAM不再拖累自重.

      • 坏处:回到那个场景现在更加昂贵,因为它必须再次加载回内存(需要时间和内存).如果不久就回来是不必要的.

      • 坏处:无法再访问该场景的数据.如果不久就使用这些数据就不成问题了.

      • 注意:通过将一个或多个节点重新附加到不同的场景,甚至直接将其重新附加到 SceneTree,可以将数据保存在即将删除的场景中.

    • 处理停止.

      • 好处:没有节点意味着没有进程,物理过程或输入处理. CPU可用于处理新场景的内容.

      • 坏处:这些节点的处理和输入处理不再运行.如果不需要使用更新的数据,则不成问题.

  2. **我们可以隐藏现有场景.**通过更改节点的可见性或碰撞检测,我们可以从游戏角色的角度隐藏整个节点子树.

    • 记忆仍然存在.

      • 好处:如果需要,仍然可以访问数据.

      • 好处:无需再移动任何节点来保存数据.

      • 坏处:更多数据被保存在内存中,这将成为对内存敏感平台(如Web或移动设备)的问题.

    • 处理继续.

      • 好处:数据继续接收处理更新,因此场景将不断更新其中依赖于增量时间或帧数据的任何数据.

      • Pro:节点仍然是组的成员(因为组属于 SceneTree).

      • 坏处:现在CPU的注意力分散在两个场景之间.负载过大可能导致帧速率降低.应该确保测试性能,以确保目标平台能够支持它们提供的负载.

  3. 我们可以从树上删除现有的场景. 给现有场景的根节点分配一个变量.然后使用 :ref:`Node.remove_child(Node) <class_Node_method_remove_child>`来将整个场景从树上分离.

    • 记忆仍然存在(与从视图中隐藏它相似的优点/缺点).

    • 处理停止(类似于完全删除它的优点/缺点).

    • 亲:这种"隐藏"的变化更容易显示/隐藏.人们必须只调用一个方法add / remove_child方法,而不是潜在地跟踪场景的多个变化.它类似于在其他引擎中禁用游戏对象.

    • 坏处:与仅从视图中隐藏它不同,如果场景中包含的数据依赖于delta时间,输入,组或其他派生自 SceneTree access的数据,则它将变为陈旧.

在有些情况下,人们可能希望有许多场景同时存在.也许人们在运行时添加他们自己的单例,或者在场景变化之间保留一个场景的数据(将场景添加到根节点).

get_tree().get_root().add_child(scene)
GetTree().GetRoot().AddChild(scene);

Perhaps instead they wish to display multiple scenes at the same time using ViewportContainers. This is optimal in cases where the intent is to render different content in different parts of the screen. Minimaps and split-screen multiplayer are good examples.

每个选项都有最合适的情况,因此必须检查每个选项的效果并确定最适合其独特情况的路径.