手动更改场景

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

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

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");
}

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

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

  1. We can delete the existing scene. SceneTree.change_scene() and SceneTree.change_scene_to() will delete the current scene immediately. Developers can also delete the main scene though. Assuming the root node's name is "Main", one could do get_node("/root/Main").free() to delete the whole scene.

    • 卸载内存。

      • 好处: RAM不再拖累自重。
      • 坏处:回到那个场景现在更加昂贵,因为它必须再次加载回内存(需要时间和内存)。如果不久就回来是不必要的。
      • 坏处:无法再访问该场景的数据。如果不久就使用这些数据就不成问题了。
      • 注意:通过将一个或多个节点重新附加到不同的场景,甚至直接将其重新附加到 SceneTree,可以将数据保存在即将删除的场景中。
    • 处理停止。

      • 好处:没有节点意味着没有进程,物理过程或输入处理。 CPU可用于处理新场景的内容。
      • 坏处:这些节点的处理和输入处理不再运行。如果不需要使用更新的数据,则不成问题。
  2. **我们可以隐藏现有场景。**通过更改节点的可见性或碰撞检测,我们可以从游戏角色的角度隐藏整个节点子树。

    • 记忆仍然存在。

      • 好处:如果需要,仍然可以访问数据。
      • 好处:无需再移动任何节点来保存数据。
      • 坏处:更多数据被保存在内存中,这将成为对内存敏感平台(如Web或移动设备)的问题。
    • 处理继续。

      • 好处:数据继续接收处理更新,因此场景将不断更新其中依赖于增量时间或帧数据的任何数据。
      • Pro:节点仍然是组的成员(因为组属于 SceneTree)。
      • 坏处:现在CPU的注意力分散在两个场景之间。负载过大可能导致帧速率降低。应该确保测试性能,以确保目标平台能够支持它们提供的负载。
  3. We can remove the existing scene from the tree. Assign a variable to the existing scene's root node. Then use Node.remove_child(Node) to detach the entire scene from the tree.

    • 记忆仍然存在(与从视图中隐藏它相似的优点/缺点)。
    • 处理停止(类似于完全删除它的优点/缺点)。
    • 亲:这种“隐藏”的变化更容易显示/隐藏。人们必须只调用一个方法add / remove_child方法,而不是潜在地跟踪场景的多个变化。它类似于在其他引擎中禁用游戏对象。
    • 坏处:与仅从视图中隐藏它不同,如果场景中包含的数据依赖于delta时间,输入,组或其他派生自 SceneTree access的数据,则它将变为陈旧。

在某些情况下,人们可能希望同时出现许多场景。也许一个是在运行时添加自己的单例,或者在场景更改之间保留场景的数据(将场景添加到根节点)。

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

也许他们希望使用 ViewportContainers 同时显示多个场景。在目的是在屏幕的不同部分呈现不同内容的情况下,这是最佳的。迷您地图和分屏多人游戏就是很好的示例。

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