Жизненный цикл Entity: где выполнять код
Порядок EnterTree, Ready и ExitTree; повторный вход, RequestReady и законченный C#-стенд.
Выбрать callback
| Задача | Место |
|---|---|
| Начальные значения полей | Инициализатор/конструктор; активное дерево ещё не предполагается |
| Подписка при каждом входе | _EnterTree |
| Настройка после готовности детей | _Ready |
| Снять внешние подписки при выходе | _ExitTree |
| Обычное обновление кадра | _Process(double delta) |
| Логика физического шага | _PhysicsProcess(double delta) |
| Обработать ещё не использованный ввод | _UnhandledInput / _UnhandledKeyInput |
| Нарисовать CanvasItem | _Draw; запрос обновления через QueueRedraw |
Имя метода и регистр важны. Для C# используйте public override и точную сигнатуру SDK. Конструктор не означает, что объект уже находится в уровне. Не ищите в нём детей, которые ещё должны загрузиться из префаба. Если ваш собственный C#-базовый класс реализует callback, решите явно, нужен ли вызов base; пустой базовый метод Entity не является обязательным ритуалом.
Проверить порядок
Добавьте оба файла в C#-проект Reckfell 1.0.0. Прикрепите LifecycleDemo к Entity отдельного уровня, соберите и нажмите F6. Output покажет журнал и Ready calls: Parent=1, Child=2. Первые события входа/готовности: Parent:enter → Child:enter → Child:ready → Parent:ready.
LifecycleProbe.cs
using System.Collections.Generic;
using Reckfell;
public partial class LifecycleProbe : Entity
{
public List<string> Journal { get; set; } = new();
public int Entries { get; private set; }
public int ReadyCalls { get; private set; }
public int Exits { get; private set; }
private void Record(string stage) => Journal.Add(Name + ":" + stage);
public override void _EnterTree() { Entries++; Record("enter"); }
public override void _Ready() { ReadyCalls++; Record("ready"); }
public override void _ExitTree() { Exits++; Record("exit"); }
public override void _Notification(int what)
{
if (what == NotificationParented) Record("parented");
if (what == NotificationUnparented) Record("unparented");
if (what == NotificationPredelete) Record("predelete");
}
}LifecycleDemo.cs
using System.Collections.Generic;
using Reckfell;
public partial class LifecycleDemo : Entity
{
public List<string> Journal { get; } = new();
public LifecycleProbe ParentProbe { get; private set; } = null!;
public LifecycleProbe ChildProbe { get; private set; } = null!;
public override void _Ready()
{
ParentProbe = new LifecycleProbe { Name = "Parent", Journal = Journal };
ChildProbe = new LifecycleProbe { Name = "Child", Journal = Journal };
ParentProbe.AddChild(ChildProbe);
AddChild(ParentProbe);
RemoveChild(ParentProbe);
AddChild(ParentProbe);
RemoveChild(ParentProbe);
ChildProbe.RequestReady();
AddChild(ParentProbe);
ReckfellApi.Print(string.Join(" → ", Journal));
ReckfellApi.Print("Ready calls: Parent=" + ParentProbe.ReadyCalls + ", Child=" + ChildProbe.ReadyCalls);
}
}При выходе сначала вызывается Child:_ExitTree, затем Parent:_ExitTree. RemoveChild не удаляет объект; последующий AddChild снова вызывает _EnterTree, но обычный _Ready автоматически не повторяется. RequestReady меняет поведение следующего входа только для вызвавшей Entity: не вызывает _Ready сразу и не распространяется рекурсивно на детей.
Подписки и зависимости
Если создаваемый ребёнок испускает сигнал в _Ready, подключите обработчик до AddChild. Для внешнего долгоживущего источника пара _EnterTree/_ExitTree позволяет повторно присоединять объект без дублирующихся обработчиков. Только подписаться в _Ready и отписаться в _ExitTree недостаточно для повторного входа.
_Ready гарантирует готовность обычных существующих детей, а не всех будущих динамических объектов или произвольной внешней службы. Передавайте зависимости до активации либо задавайте отдельный этап инициализации. Пауза не отменяет ручной вызов метода или уже испускаемый сигнал: см. правила паузы.
Стенд проверяет реальные callbacks, три входа, два выхода, RequestReady и native-освобождение. Клавиатурный ввод и управление памятью во всех типах Resource этим журналом не проверены.