Дерево сцены

Введение

В предыдущих уроках все вращалось вокруг концепции узлов. Сцены - это просто набор узлов. Они (узлы) становятся активными, как только заходят в дерево сцены.

"MainLoop"

То, как Godot работает внутри, выглядит следующим образом. Существует класс OS, который является единственным экземпляром, запускаемым в самом начале. После этого загружаются все драйверы, серверы, скриптовые языки, система сцен и т.д.

После завершения инициализации, OS должен быть предоставлен MainLoop для запуска. До этого момента все это работало внутри (вы можете проверить файл main/main.cpp в исходном коде, если вам когда-нибудь будет интересно посмотреть, как это работает внутри).

Игра или программа пользователя , запускается в MainLoop. Данный класс имеет несколько методов инициализации, простой (idle) (покадрово-синхронизированный обратный вызов), фиксированный (fixed) (физико-синхронизированный обратный вызов) и ввод (input). Опять же, это низкий уровень, и при создании игр в Godot, написание собственного MainLoop редко имеет смысл.

Дерево сцены

Один из способов объяснить принцип работы Godot — это сказать, что это высокоуровневый игровой движок, работающий поверх низкоуровневого промежуточного программного обеспечения.

Система сцен — это игровой движок, а OS и серверы — это низкоуровневый API.

В любом случае, система сцен обеспечивает собственный основной цикл к ОС, SceneTree. Это автоматически инстанцируется и настраивается при запуске сцены, нет необходимости тратить время на дополнительную работу.

Важно знать, о существовании этого класса, так как он имеет несколько важных применений:

  • Он содержит корень Viewport, к которому сцена добавляется как дочерняя, когда она впервые открывается то становится частью древа сцен (подробнее об этом ниже).

  • Он содержит информацию о группах и позволяет вызывать все узлы в группе или получать список этих узлов.

  • Он содержит некоторые глобальные функции состояния, такие как режим паузы или выход.

Когда узел является частью дерева сцен, SceneTree синглтон (В следующем уроке будет рассмотрен подробнее.) можно получить, просто вызвав Node.get_tree().

Корневое окно

Корневой Viewport всегда находится в верхней части сцены. Из узла его можно получить двумя разными способами:

get_tree().root # Access via scene main loop.
get_node("/root") # Access via absolute path.

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

В то время как в сцене могут быть созданы другие видовые окна (для эффекта раздельного экрана и т.д.), это единственное окно, которое никогда не создается пользователем. Он создается автоматически внутри SceneTree.

Дерево сцены

Когда узел прямо или косвенно связан с корневым окном, он становится частью дерева сцены.

Это означает, что, как объяснялось в предыдущих руководствах, он получит обратные вызовы _enter_tree() и _ready() (а также _exit_tree()).

../../_images/activescene.webp

Когда узлы входят в Древо Сцен, они становятся активными. Они получают доступ ко всему, что им нужно для обработки, ввода, отображения 2D и 3D, уведомлений, воспроизведения звука, групп и т.д. Когда они удаляются из древа сцен, они теряют этот доступ.

Последовательность в древе

Большинство операций с узлами в Godot, такие как рисование 2D, обработка или получение уведомлений, выполняются в порядке дерева или сверху вниз, как показано в редакторе (также известно как предварительный обход):

../../_images/toptobottom.webp

Например, сначала вызывается функция _process() верхнего узла сцены, затем вызывается функция _process() узла, расположенного ниже, затем узла, расположенного ниже, и так далее.

Важным исключением является функция _ready(): функция _ready() каждого родительского узла вызывается только после того, как все его дочерние узлы вызовут свои функции _ready(), чтобы родительский узел был уверен, что его дочерние узлы полностью готовы к доступу. Это также известно как обход в обратном порядке. На изображении выше NameLabel будет уведомлен первым (но только после своих дочерних узлов, если таковые имеются!), затем Name и т. д., а Panel будет уведомлен последним.

Порядок операций также можно переопределить с помощью свойства узла process_priority. Узлы с меньшим номером вызываются первыми. Например, узлы с приоритетами "0, 1, 2, 3" будут вызываться в этом порядке слева направо.

"Становится активным", войдя в Древо Сцен

  1. Сцена загружается с диска или создается с помощью скрипта.

  2. The root node (Корневой узел) этой сцены (только один корень, помните?) добавляется либо как дочерний элемент "root" (корневого) Viewport (из SceneTree), либо как любой из его потомков.

  3. Каждый узел вновь добавленной сцены получит уведомление "enter_tree" (обратный вызов _enter_tree() в GDScript) в порядке сверху вниз (предварительный обход).

  4. Для удобства каждый узел получит уведомление о готовности (обратный вызов _ready() в GDScript) после того, как все его дочерние узлы получат уведомление о готовности (обратный обход).

  5. При удалении сцены (или ее части) они получают уведомление "exit scene" (обратный вызов _exit_tree() в GDScript) в порядке снизу вверх (в точности наоборот порядку сверху вниз).

Смена текущей сцены

После загрузки сцены вы можете захотеть заменить её на другую. Один из способов сделать это — использовать функцию SceneTree.change_scene_to_file():

func _my_level_was_completed():
    get_tree().change_scene_to_file("res://levels/level2.tscn")

Вместо использования путей к файлам можно также использовать готовые ресурсы PackedScene, используя эквивалентную функцию SceneTree.change_scene_to_packed(PackedScene scene):

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

func _my_level_was_completed():
    get_tree().change_scene_to_packed(next_scene)

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