Per aspera ad astra или RoadMap по вашей будущей игре. Godot 4 C# Часть 6 "Scene и Node".
Что же в Godot представляет собой сцена?
Сцена – это любой самодостаточный объект, собранный из узлов или других сцен. В идеале, сцена должна запускаться без проблем с помощью кнопки F6 (Запустить текущую сцену) при активной вкладке этой сцены.
Это говорит о том, что у вашей сцены отсутствуют связи с другими и ее можно считать самодостаточной ( не всегда возможно, но как хорошая практика).
В вашей игре сценой может быть, например:
- Персонаж
- Его меч
- Бочка на обочине
По сути, любой игровой объект (GameObject) = Сцена.
Дочерние сцены наследуют положение и вращение родительских. Это означает, что, создав сцену меча внутри игрока и расположив ее относительно его локальных координат, вы заставите меч двигаться вместе с игроком.
Node (или узел) – это один маленький элемент вашей игры. Узел являет собой самодостаточный функциональный модуль, например: камера, коллайдер, спрайт. Если проводить аналогию со строительством дома, то Node — это кирпич, а стена — это сцена.
Мы можем создать несколько стен, чтобы можно было поставить крышу; в движке подобное называется экземпляр (instance, похоже на prefab в Unity) сцены. По сути это копия сцены, которая может быть использована без накладных расходов на производительность.
Все изменения в базовой сцене транслируются и на все ее экземпляры. Также движок позволяет наследовать сцены, изменять поведение и отображение для дочерних сцен, но при этом сохраняя состав Node как у родителя.
Я сначала не мог понять, как это делать, но после ковыряния в интернете нашел. Чтобы создать дочернюю сцену, нужно кликнуть по этой сцене ПКМ в Файловом менеджере, и там появится соответствующий пункт. Также из родительской сцены проблематично удалять узлы — это приводит к необходимости удалять этот узел у всех дочерних сцен.
Когда вы будете строить сцены из Node, у вас будет иногда возникать желание продублировать состав нескольких Node. Вместо дублирования стоит подумать о создании дополнительной сцены и дальнейшего использования ее экземпляра.
К каждой сцене и узлу есть возможность прикрепить пользовательский скрипт ( через ПКМ ). Правильным будет это делать для корневого узла сцены. Прикрепленный скрипт позволяет из кода получить доступ к любому потомку.
При создании сцен часто возникает вопрос, какой Node использовать как корневой для сцены. Есть два типа сцен:
- Основные, которые являются отражениями частей (levels) игры (типа Bootstrap, GameStart, GamePlay, GameEnd) — в общем, сцены-контейнеры. Для них я использую Node, так как он не содержит никаких лишних свойств типа Position (вряд ли я захочу двигать эти сцены).
- Для игровых объектов — Node2D, так как их двигать придется и Position для этого пригодится.
- Для интерфейсов — Control и его обертки.
С версии Godot 4.4 движок начнет ругаться при попытке изменять параметры корневого узла и выбрасывать предупреждение в виде желтого треугольника с сообщением «Корневой узел сцены нельзя преобразовывать...». Чтобы избавиться от этого предупреждения, создайте обертку для сцены типа Node2D, которая не будет изменяться у вас в редакторе.
После присвоения скрипта сцене в C# вы получите тип, с которым вы вольны делать что угодно. Этот тип будет содержать внутри все необходимые методы жизненного цикла.
Вот некоторые из них:
_EnterTree()
- Вызывается, когда узел добавляется в дерево сцены (например, через AddChild()).
- Доступ к родителю и детям возможен, но они могут быть ещё не готовы.
_Ready()
- Вызывается после того, как узел и все его потомки полностью добавлены в дерево сцены.
- Идеальное место для настройки зависимостей (например, подключение сигналов).
- Порядок выполнения: снизу вверх (сначала дети, потом родители).
_Process(double delta)
- Вызывается каждый кадр рендеринга. Частота зависит от FPS.
- delta — время в секундах с предыдущего кадра. Используется для плавной анимации.
- Включается/выключается через SetProcess(true/false).
_PhysicsProcess(double delta)
- Вызывается с фиксированной частотой (по умолчанию 60 раз в секунду).
- Используется для физики и детерминированных вычислений.
- Включается/выключается через SetPhysicsProcess(true/false).
_ExitTree()
- Вызывается перед удалением узла из дерева сцены (например, через RemoveChild() или QueueFree()).
- Место для очистки ресурсов и отключения сигналов.
_Notification( int what )
- Обрабатывает системные уведомления (например, NOTIFICATION_READY, NOTIFICATION_PROCESS).
- Альтернатива переопределению методов вроде _Ready() или _Process().
- Можно использовать для сохранения игры перед ее закрытием.
_Input(InputEvent event)
- Вызывается для каждого входного события (клавиши, мышь). Все что вы вводите будет перехвачено.
_Unhandled_Input(InputEvent event)
- Обрабатывает события, не перехваченные другими узлами (например, GUI). Перехватит только те события ввода, которые не были обработаны на пути к этому узлу.
Спасибо за внимание!