Изменение сцен вручную

Иногда полезно иметь больше контроля над переключением сцен. Дочерние узлы Viewport будут визуализироваться в сгенерированном им изображении. Это справедливо даже для узлов за пределами "текущей" сцены. К этой категории относятся автозагрузки, а также сцены, которые вы создаете и добавляете в дерево во время выполнения:

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

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

Чтобы завершить цикл и заменить старую сцену новой, вам нужно сделать выбор. Существует множество стратегий удаления сцены из области видимости Viewport. Компромиссы включают баланс скорости работы и потребления памяти, а также баланс доступа к данным и их целостности.

  1. Удаление существующей сцены. SceneTree.change_scene_to_file() и SceneTree.change_scene_to_packed() немедленно удалят текущую сцену. Вы также можете удалить главную сцену вручную. Предполагая, что корневой узел называется "Main", используйте get_node("/root/Main").free() для полного удаления сцены.

    • Освобождение памяти.

      • За: в RAM памяти больше нет мёртвого груза.

      • Против: Возврат в эту сцену теперь более затратный так как мы должны снова загрузить её назад в память (занимает время и память). Не проблема если скорый возврат не требуется.

      • Против: Больше нет доступа к данным сцены. Не проблема, если эти данные потребуются не скоро.

      • Примечание: Может быть полезно сохранить данные из сцены, которая скоро будет удалена, повторно прикрепив один или несколько её узлов к другой сцене или даже напрямую к SceneTree.

    • Обработка остановок.

      • Преимущество: Отсутствие узлов означает отсутствие обработки, физических расчётов и обработки ввода. ЦПУ освобождается для работы с содержимым новой сцены.

      • Недостаток: Обработка и ввод для этих узлов больше не работают. Не проблема, если использование обновленных данных не требуется.

  2. Hide the existing scene. By changing the visibility or collision detection of the nodes, you can hide the entire node sub-tree from the player's perspective. Use CanvasItem.hide() to hide a scene and CanvasItem.show() to show it again.

    • Память всё ещё существует.

      • Преимущество: при необходимости вы по-прежнему сможете получить доступ к данным.

      • За: Вам больше не нужно перемещать узлы для сохранения данных.

      • Недостаток: больше данных хранится в памяти, что может стать проблемой на чувствительных к памяти платформах, таких как веб-сайты или мобильные устройства.

    • Обработка продолжений.

      • Плюс: данные продолжают получать обновления обработки, поэтому сцена будет сохранять все данные, зависящие от обновленных данных о времени дельты или кадрах.

      • За: Узлы сохраняются как члены групп (так как группы принадлежат SceneTree).

      • Минусы: теперь нагрузка на процессор распределяется между обеими сценами. Слишком большая нагрузка может привести к низкой частоте кадров. Обязательно проверяйте производительность в процессе разработки, чтобы убедиться, что целевая платформа выдержит нагрузку, возникающую при таком подходе.

  3. 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. To attach it later, use Node.add_child(Node).

    • Память все еще существует (те же плюсы/минусы, что и при ее сокрытии от глаз).

    • Обработка останавливается (плюсы/минусы такие же, как и при полном удалении).

    • Плюс: Этот вариант "скрытия" гораздо проще отображать/скрывать. Вместо того, чтобы отслеживать множество изменений в сцене, достаточно вызывать только методы add/remove_child. Это похоже на отключение игровых объектов в других движках.

    • Против: В отличие от скрытия только от взгляда, данные содержащиеся на сцене станут недоступными если они зависимы от дельты времени, ввода, групп, или других данных которые наследуются от SceneTree.

Также бывают случаи, когда может потребоваться одновременное присутствие нескольких сцен, например, добавление собственного синглтона во время выполнения или сохранение данных сцены между сменой сцен (путём добавления сцены к корневому узлу).

get_tree().root.add_child(scene)

Другим вариантом может быть одновременное отображение нескольких сцен с помощью SubViewportContainers. Это оптимально для отображения разного контента в разных частях экрана (например, мини-карт, многопользовательской игры на разделённом экране).

Каждый вариант будет наиболее уместен в определенных ситуациях, поэтому вам следует изучить последствия каждого подхода и определить, какой путь лучше всего соответствует вашей уникальной ситуации.