액터의 라이프사이클

언리얼 엔진에서 액터(Actor)는 게임 도중에 언제든지 생성(Spawn)될 수 있고, 필요 없어지면 파괴(Destroy)될 수 있습니다.
이를 액터 생명주기 혹은 라이프사이클이라 부르며, 이 과정을 이해하면 게임 로직을 보다 효율적이고 안정적으로 작성할 수 있습니다.

라이프사이클 분해도

actorlifecycle1

주요 라이프 사이클 함수

액터의 라이프 사이클 시작

생성자(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로 옮기는 것이 좋습니다.

참고

액터 라이프사이클

UE5 카테고리 내 다른 글 보러가기

댓글남기기