액터의 생명주기를 정확히 이해하는 것은 초기화 시점(Initialization Timing), 참조 유효성(Reference Validity), 그리고 모리 누수 방지(Memory Management) 위해 필수적이다. UE5 C++에서 액터가 생성되고 소멸되기까지의 과정을 단계별알아보자.
1. 액터 생명주기 흐름도 (Life Cycle Flow)
복잡한 과정을 크게 생성 및 로드(Disk/Memory) -> 초기화 및 플레이(Play) -> 종료 및 소멸(Destroy) 세 단계로 나눌 수 있다.
Disk/Spawn -> Constructor -> PostInitProperties -> OnConstruction -> BeginPlay ->
Tick -> EndPlay -> Destructor
2. 단계별 상세 및 C++ 구현
1단계: 생성 (Creation) - 메모리에 올라오는 순간
이 단계에서는 아직 "게임 월드"에 완전히 존재한다고 볼 수 없다. 데이터가 메모리에 할당되는 시점이다.
- 생성자 (
AMyActor::AMyActor): - 역할: CDO(Class Default Object) 설정,
CreateDefaultSubobject를 통한 컴포넌트 생성, 변수 기본값 초기화. - 주의: 절대 이곳에 게임플레이 로직을 넣으면 안됨. 월드나 다른 액터에 접근할 수 없으며, 에디터 실행 시점에도 호출된다.
- UE5 Tip: 포인터 멤버 변수는
TObjectPtr<T>를 사용하는 것이 UE5 표준. (지연 로딩 및 접근성 개선).
// AMyActor.h
UPROPERTY(VisibleAnywhere)
TObjectPtr<UStaticMeshComponent> MeshComp;
// AMyActor.cpp
AMyActor::AMyActor()
{
// Tick 활성화 여부 (최적화를 위해 필요없다면 false로 설정)
PrimaryActorTick.bCanEverTick = true;
// 컴포넌트 생성 (생성자에서만 가능)
MeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComp"));
RootComponent = MeshComp;
}
PostInitProperties:- 속성 값이 초기화된 직후 호출된다. 블루프린트에서 설정한 기본값이 C++ 변수에 덮어씌워진 후 실행된다.
2단계: 초기화 (Initialization) - 월드 진입 준비
액터가 레벨에 배치되거나 스폰될 때 실행된다.
OnConstruction(ExecuteConstructionScript):- 역할: 블루프린트의
Construction Script와 대응된다. 액터가 스폰되거나 에디터에서 속성을 변경할 때마다 호출된다. - 용도: 절차적 메시 생성, 머티리얼 동적 할당 등 시각적 갱신.
- 역할: 블루프린트의
PostInitializeComponents:- 역할: 액터의 모든 컴포넌트가 등록되고 초기화가 완료된 시점.
- 용도: 컴포넌트 간의 의존성 설정(예: MovementComponent가 RootComponent를 참조해야 할 때)에 적합하다.
BeginPlay:- 역할: 게임플레이 로직의 시작점. 모든 액터가 생성된 후, 게임이 시작될 때 호출된다.
- 주의: 다른 액터의
BeginPlay가 실행되었음을 보장하지 않는다. 따라서 다른 액터의 데이터를 참조할 때는IsValid()체크가 필수. - 하이브리드 팁:
Super::BeginPlay()를 호출해야 블루프린트의Event BeginPlay도 실행된니다.
void AMyActor::BeginPlay()
{
Super::BeginPlay(); // 필수!
// 게임플레이 로직 시작
// 예: 타이머 설정, UI 위젯 생성, 초기 사운드 재생
}
3단계: 런타임 (Runtime) - 게임 진행 중
Tick(float DeltaTime):- 매 프레임 호출.
- 최적화 전략:
- 가능하면
PrimaryActorTick.bCanEverTick = false;로 틱을 꺼야 함. - 특정 간격으로만 로직이 필요하다면
GetWorldTimerManager().SetTimer(...)를 사용하는 것이 성능상 월등히 유리.
- 가능하면
4단계: 소멸 (Destruction) - 메모리 해제
액터가 Destroy() 되거나, 레벨이 바뀔 때, 혹은 게임이 종료될 때 발생.
EndPlay(const EEndPlayReason::Type EndPlayReason):- 역할: 게임플레이와 관련된 정리 작업을 하는 가장 안전한 장소이다.
- 용도: 타이머 해제(
ClearTimer), 델리게이트 바인딩 해제, 생성한 동적 UI 제거. - 이유(Reason):
Destroyed,LevelTransition,EndPlayInEditor,RemovedFromWorld등 종료 사유를 알 수 있다.
void AMyActor::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
// 타이머 핸들 정리 등 게임 로직 정리
GetWorld()->GetTimerManager().ClearAllTimersForObject(this);
Super::EndPlay(EndPlayReason);
}
BeginDestroy:- 가비지 컬렉션(GC)이 객체 소멸을 시작한다고 알리는 단계. 메모리 해제가 임박.
- 소멸자 (
AMyActor::~AMyActor):- 역할: 표준 C++ 소멸자.
- 주의: UObject(언리얼 오브젝트)와 관련된 처리를 여기서 하면 안된다. 이 시점에서는 월드나 다른 UObject가 이미 메모리에서 날아갔을 수 있어 접근 시 크래시가 발생할 수 있다. 주로 순수 C++ 클래스나 비관리형 메모리(Non-UObject)를 해제할 때만 사용.
3. 요약 및 핵심 비교표
| 함수명 | 호출 시점 | 주요 역할 및 주의사항 |
|---|---|---|
| Constructor | 메모리 할당 시 | CDO 설정, 컴포넌트 생성. 게임 로직 금지. |
| PostInitializeComponents | 컴포넌트 초기화 후 | 컴포넌트 간 연결 설정. |
| BeginPlay | 게임 시작 시 | 게임플레이 로직 시작. Super::BeginPlay() 필수. |
| Tick | 매 프레임 | 지속적인 업데이트. 성능 주의. |
| EndPlay | 게임 종료/소멸 시 | 타이머, 델리게이트 등 로직 정리의 최적 장소. |
| Destructor | 메모리 해제 시 | 비 UObject 리소스 정리. UObject 접근 금지. |
'프로그래밍 > Unreal Engine 5' 카테고리의 다른 글
| [Unreal Engine 5] TSubclassOf<T> (0) | 2026.01.16 |
|---|---|
| [Unreal Engine 5] UPROPERTY()와 지정자(Specifier)들 (0) | 2026.01.15 |
| [Unreal Engine 5] 언리얼 엔진 5의 스마트 포인터 (1) | 2026.01.08 |
| [Unreal Engine 5] Transform Direction (0) | 2025.12.04 |
| [Unreal Engine 5] 움직이는 발판 위 문제 (0) | 2025.12.03 |