[UE5] 액터의 라이프사이클
액터의 라이프사이클
언리얼 엔진에서 액터(Actor)는 게임 도중에 언제든지 생성(Spawn)될 수 있고, 필요 없어지면 파괴(Destroy)될 수 있습니다.
이를 액터 생명주기 혹은 라이프사이클이라 부르며, 이 과정을 이해하면 게임 로직을 보다 효율적이고 안정적으로 작성할 수 있습니다.
라이프사이클 분해도
주요 라이프 사이클 함수
액터의 라이프 사이클 시작
생성자(Constructor)
, PostInitializeComponents
, BeginPlay
함수 등이 각각 언제 호출되는지 알아야 적절한 곳에 코드를 배치할 수 있습니다.
생성자(Constructor)
C++ 클래스 객체가 메모리에 생성될 때 딱 한 번 호출됩니다.
아직 액터가 월드(World)에 완전히 등록되지 않은 상태이므로, 다른 액터나 월드 관련 기능을 안전하게 호출하기 어렵습니다.
보통 생성자에서는 단순한 생성 및 할당을 작업합니다.
주로 CreateDefaultSubobject
함수 등을 사용해 컴포넌트 생성 및 초기 변수 세팅에 활용합니다.
PostInitializeComponents
액터의 모든 컴포넌트가 생성 및 초기화된 뒤 호출됩니다.
각 컴포넌트가 이미 준비된 상태이므로, 컴포넌트 간 상호작용(예: 서로 다른 컴포넌트 참조 설정)이 필요한 코드를 배치하기 좋습니다.
PostInitializeComponents
함수에서 컴포넌트들 사이의 의존 관계를 설정합니다.
BeginPlay()
Play In Editor(PIE)나 런타임에서 게임이 시작될 때, 혹은 이미 실행 중인 게임에 SpawnActor
등으로 새 액터가 생성될 때 한 번 호출됩니다.
이 시점에는 이미 월드와 다른 액터들이 준비된 상태이므로, 자유롭게 상호작용이 가능합니다.
BeginPlay
함수에서 AI, 게임 모드, 플레이어 컨트롤러 등 다른 시스템과 연동을 주로 초기화합니다.
타이머, Delegate(Event) 바인딩 등을 시작하기에도 적합합니다.
Tick(float DeltaTime)
매 프레임마다 호출됩니다.
액터에 PrimaryActorTick.bCanEverTick
의 값이 true
로 설정되어있어야 합니다.
실시간 업데이트가 필요한 로직을 처리합니다.
예로 캐릭터 이동, 물리 연산, 카메라 추적 등이 있습니다.
매 프레임마다 호출되는 Tick
함수는 비용이 클 수 있으므로, 이벤트 기반으로 전환할 수 있는 부분은 Tick
함수를 사용하지 않는 편이 성능에 유리합니다.
액터의 라이프사이클 종료
액터가 사라질 때 (EndPlay
, Destroyed
등) 메모리를 해제하거나 특정 상태를 저장해야 할 수 있습니다.
적절한 시점에 필요한 정리 작업을 하지 않으면 메모리 누수나 예외 상황이 발생할 수 있습니다.
Destroyed()
Destroy
함수를 직접 호출하여 액터를 제거하기 직전에 호출됩니다.
Destroyed
함수가 불린 뒤에는 최종적으로 EndPlay
함수도 함께 호출됩니다.
호출이 절대적으로 보장되지 않습니다.
게임 종료나 레벨을 전환하는 등 레벨 언로드 시에는 호출되지 않을 수 있으므로, 모든 중요한 정리를 Destroyed
함수에만 의존하면 놓치는 케이스가 생길 수 있습니다.
수동으로 액터를 제거할 때, 마지막 정리 코드를 넣을 수 있는 곳입니다.
일반적으로 다음과 같은 용도로 활용합니다.
- 수동 할당한 메모리를 해제합니다.
- 액터가 생성한 다른 액터나 컴포넌트 중, 자동으로 해제되지 않는 것을 처리합니다.
- 게임 전역적 또는 외부 클래스에 바인딩해둔 델리게이트를 해제합니다.
- 재생 중인 사운드나 파티클을 수동으로 처리합니다.
EndPlay(const EEndPlayReason::Type EndPlayReason)
액터가 더 이상 월드에서 활동하지 않게 될 때 호출됩니다.
EndPlay
는 게임 종료나 레벨 언로드 같은 상황에서 Destroyed
에 비해 상대적으로 호출이 될 보장이 높습니다.
호출되는 경우는 다음과 같습니다.
Destroy
함수에 대한 명시적 호출로 인해 파괴될 때 호출됩니다.- 에디터에서의 플레이가 종료된 경우 호출됩니다.
- 레벨을 전환하는 레벨 트랜지션(심리스 트래블 또는 로드 맵)이 수행될 때 호출됩니다.
- 액터가 포함된 스트리밍 레벨이 언로드될 때 호출됩니다.
- 액터의 수명이 만료될 경우 호출됩니다.
- 게임이 종료 될 때 모든 액터가 소멸되므로 호출됩니다.
EEndPlayReason::Type
을 사용해 어떤 이유로 호출되었는지 구분합니다.
중요한 정리 로직(자원 해제, Timer 해제, 상태 저장 등)은 EndPlay
에 넣는 것이 좀 더 안전합니다.
일반적으로 다음과 같은 용도로 활용합니다.
GetWorldTimerManager().ClearTimer(…)
와 같이 타이머를 정리합니다.- 여전히 해제되지 않은 동적 메모리가 남아 있다면 정리합니다.
- 게임 진행 상황(점수, 인벤토리 등)을 파일이나 DB에 저장합니다.
- 상위 시스템에 콜백을 보내는 로직도 EndPlay에서 처리 가능합니다.
OnDestroyed()
OnDestroyed
는 이벤트 기반으로 델리게이트를 통해 호출하게 됩니다.
Destroy
함수에 대한 레거시 응답이므로, 여기에 있는 로직을 EndPlay로 옮기는 것이 좋습니다.
댓글남기기