Actor и Component: из чего состоит сцена

Урок объясняет два главных кирпичика Unreal — Actor и Component — и как из них собирается всё на сцене.

Actor — это любой объект, который может быть размещён на уровне; Component — функциональный блок, который добавляется внутрь Actor'а и наделяет его поведением или внешним видом.

Зачем нужно это разделение

В Unity вы знаете пару GameObject и Component: пустой объект, на который навешиваются компоненты. В Unreal идея похожа, но называется иначе. Любая вещь на уровне — стена, свет, персонаж, камера, триггер — это Actor. Сам по себе Actor почти пустой; всё интересное ему дают Component'ы. Меш для отрисовки — это компонент. Источник света — компонент. Коллизия — компонент. Такое разделение позволяет собирать любой объект как конструктор.

Иерархия компонентов внутри Actor'а

Внутри одного Actor'а компоненты образуют дерево. Один из них — корневой (Root Component), остальные крепятся к нему. Положение Actor'а в мире — это положение его корня, а дочерние компоненты двигаются вместе с ним. Схема простого персонажа:

Actor: PlayerCharacter
 +-- CapsuleComponent      (корень, форма коллизии)
      +-- SkeletalMesh      (видимая модель)
      +-- SpringArm         (штанга для камеры)
           +-- Camera        (камера за спиной)

Жизненный цикл Actor'а

У каждого Actor'а есть набор событий, которые движок вызывает автоматически. Они аналогичны методам жизненного цикла в Unity, но называются по-своему.

Событие UnrealКогда вызываетсяАналог в Unity
BeginPlayПри старте игры или появлении Actor'аStart
TickКаждый кадрUpdate
EndPlayПри удалении или завершении игрыOnDestroy

Как это выглядит в C++

Объявление простого Actor'а на C++ выглядит так. Обратите внимание на макросы — они нужны движку для рефлексии, разберём их позже.

UCLASS()
class AMyActor : public AActor
{
    GENERATED_BODY()
public:
    AMyActor();
    virtual void BeginPlay() override;
    virtual void Tick(float DeltaTime) override;
};

Как работает под капотом

Когда уровень загружается, движок создаёт экземпляры всех размещённых Actor'ов и регистрирует их в мире. На каждом кадре движок обходит список активных Actor'ов и вызывает их Tick (если он включён). Компоненты тоже могут иметь свой Tick. Чтобы не тратить ресурсы, Tick стоит выключать у объектов, которым он не нужен, — об этом мы поговорим в разделе про оптимизацию.

Частые ошибки

  • Путать Actor и Component. Actor можно поставить на уровень, Component — нельзя, он живёт только внутри Actor'а.
  • Логика в конструкторе. Игровую логику пишут в BeginPlay, а не в конструкторе C++, потому что в момент конструктора мир ещё не готов.
  • Лишний Tick. Оставлять Tick включённым у статичных объектов — частая причина просадок производительности.

Откуда берутся Actor'ы на уровне

Actor попадает на уровень двумя путями. Первый — вы перетаскиваете его из Content Browser или ставите вручную в редакторе; такой Actor существует в файле уровня и загружается вместе с ним. Второй — Actor создаётся во время игры кодом (спавнится): так появляются пули, эффекты, выпавшие предметы. Разница принципиальна: размещённые в редакторе объекты вы видите и настраиваете заранее, а заспавненные возникают динамически по ходу игры и исчезают, когда становятся не нужны.

Компоненты тоже бывают двух сортов. Одни добавляют как часть «чертежа» класса — они есть у каждого экземпляра. Другие можно добавить конкретному размещённому экземпляру прямо на уровне. Первый подход — для общей структуры объекта, второй — для разовых украшений конкретной копии. Понимание этой двойственности убирает частую путаницу новичков о том, «почему компонент есть тут, но нет там».

Итоги

  • Actor — любой объект на уровне; Component — его строительный блок.
  • Компоненты образуют дерево с корнем; положение Actor'а — это положение корня.
  • BeginPlay, Tick и EndPlay — ключевые события жизненного цикла (аналоги Start, Update, OnDestroy).
  • Игровую логику начинают в BeginPlay, а не в конструкторе.
Проверьте себя
1. Что из перечисленного можно напрямую разместить на уровне?
AComponent
BActor
CTick
DRoot
2. Какое событие Unreal соответствует методу Update в Unity?
ABeginPlay
BTick
CEndPlay
DConstruct
3. Где правильно размещать стартовую игровую логику Actor'а?
AВ конструкторе C++
BВ BeginPlay
CВ деструкторе
DВ Content Browser