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, а не в конструкторе.