手动更改场景

Sometimes it helps to have more control over how one swaps scenes around. A Viewport‘s child nodes will render to the image it generates, this holds true even for nodes outside of the “current” scene. Autoloads fall into this category, but so do scenes which one instances and adds to the tree at runtime:

GDScriptC#

  1. var simultaneous_scene = preload("res://levels/level2.tscn").instantiate()
  2. func _add_a_scene_manually():
  3. # This is like autoloading the scene, only
  4. # it happens after already loading the main scene.
  5. get_tree().root.add_child(simultaneous_scene)
  1. public Node simultaneousScene;
  2. public MyClass()
  3. {
  4. simultaneousScene = ResourceLoader.Load<PackedScene>("res://levels/level2.tscn").Instantiate();
  5. }
  6. public void _AddASceneManually()
  7. {
  8. // This is like autoloading the scene, only
  9. // it happens after already loading the main scene.
  10. GetTree().Root.AddChild(simultaneousScene);
  11. }

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

  1. 我们可以删除现有的场景。SceneTree.change_scene_to_file()SceneTree.change_scene_to_packed() 都会立即删除当前场景。当然开发者也可以删除主场景。比如根节点的名称为“Main”的话,get_node("/root/Main").free() 就可以删除整个场景。

    • 卸载内存.

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

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

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

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

    • 处理停止.

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

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

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

    • 记忆仍然存在.

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

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

      • 坏处:内存中需要保留更多的数据,在 Web、移动设备等内存比较紧张的平台上可能会造成一些问题。

    • 处理继续.

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

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

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

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

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

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

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

    • 坏处:与仅从视图中隐藏它不同,如果场景中包含的数据依赖于时间增量、输入、分组或其他通过访问 SceneTree 才能得到的数据,则它将变为陈旧。

有些情况下,也会有人想要同时显示多个场景。比如需要在运行时添加单例场景,或者是需要在场景切换后保持某个场景的数据(将这个场景添加到根节点)。

GDScriptC#

  1. get_tree().root.add_child(scene)
  1. GetTree().Root.AddChild(scene);

也有可能是想要使用 SubViewportContainer 来同时显示多个场景。如果你想要的就是在屏幕上的不同区域渲染不同的内容的话,这确实不失为一种最优解。比如小地图和分屏形式的多人游戏里就会用到这种做法。

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