Entity и иерархия
Типы сущностей, пути, жизненный цикл и владение.
Entity — базовый класс иерархии. Entity3D добавляет положение, поворот и масштаб в 3D; Entity2D — в 2D. Специализированные классы добавляют конкретные возможности.
Родитель и дочерние сущности
World (Entity3D)
└── Player (CharacterBody3D)
├── Visual (MeshInstance3D)
├── CollisionShape3D
└── Camera3DWorld — родитель Player. Для Player объекты Visual, CollisionShape3D и Camera3D — дети. У сущности может быть не больше одного родителя. У соседних детей должны быть разные имена.
Для обычных пространственных дочерних объектов трансформация задаётся относительно родителя. Если сдвинуть Player, его модель, коллизия и камера переместятся вместе с ним. Специальный режим Top Level меняет наследование трансформации; в первых уроках оставляйте его выключенным.
Дерево задаёт организацию. Одна лишь вложенность не создаёт игровые правила: например, MeshInstance3D показывает модель, но не становится твёрдым телом без физического объекта и формы столкновения.
Как выбрать нужный тип
| Задача | С чего начать |
|---|---|
| Сгруппировать объекты без пространственных свойств | Entity |
| Сгруппировать объекты в 3D | Entity3D |
| Показать 3D-модель | MeshInstance3D и ресурс Mesh |
| Создать управляемого персонажа | CharacterBody3D или CharacterBody2D |
| Сделать неподвижный физический пол | StaticBody3D с CollisionShape3D |
| Показать интерфейс | Control, Label, Button |
Не выбирайте Entity3D для каждой задачи автоматически. Например, Label уже содержит возможности элемента интерфейса.
Имена, пути и типы
Имя Visual — произвольное имя конкретного объекта. Тип MeshInstance3D определяет, что этот объект умеет. Переименование Visual в BodyMesh не меняет его тип.
Путь читается от сущности, на которой выполняется код. В примере выше из скрипта на Player путь к камере — Camera3D; из скрипта на World — Player/Camera3D. Регистр букв имеет значение. asset:// относится к файлам проекта, а не к путям внутри дерева.
using Reckfell;
public partial class PlayerView : Entity3D
{
public override void _Ready()
{
var camera = GetEntity<Camera3D>("Camera3D");
camera.Current = true;
}
}Этот пример требует дочернюю Camera3D с именем Camera3D. Скрипт можно прикрепить к Player из примера: CharacterBody3D наследует Entity3D. Если переместить камеру внутрь Pivot, путь станет Pivot/Camera3D.
Когда выполняется код
| Метод C# | Когда вызывается | Для чего подходит |
|---|---|---|
_EnterTree() | При входе в активное дерево; родитель раньше детей | Подключение к дереву приложения |
_Ready() | После готовности детей; дети раньше родителя | Получить дочерние объекты, задать начальные значения |
_Process(double delta) | Каждый отображаемый кадр | Визуальное вращение, обновление интерфейса |
_PhysicsProcess(double delta) | С фиксированным физическим шагом | Движение персонажа и работа с физикой |
delta — время в секундах, прошедшее с предыдущего соответствующего шага. Подробное объяснение и первый скрипт — в уроке C#.
Родитель, владелец и удаление
Parent определяет положение в дереве. Owner определяет, к чьему сохраняемому дереву принадлежит объект. При обычном создании через редактор он настраивает владение сам. После AddChild() из кода объект существует в работающей игре, но это ещё не означает, что он будет записан в исходный файл при сохранении дерева.
QueueFree() планирует удаление объекта вместе с детьми в конце кадра, после отложенных вызовов. Не обращайтесь к удалённой сущности позже. Для начала используйте этот метод вместо немедленного Free() во время обработки игровых событий.
Справочник: Entity, Entity3D, EntityTree.