Unreal

언리얼 엔진 Actor의 라이프 사이클

(ꐦ •᷄ࡇ•᷅) 2025. 1. 22. 16:32

 

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

 

1. 액터 라이프 사이클을 알아야 하는 이유

1. 초기화 시점 결정

  • 생성자(Constructor), PostInitailizeComponents, BeginPlay 등이 각각 언제 호출되는지 알아야 적절한 곳에 코드를 배치할 수 있다.
  • 예) 컴포넌트 생성(CreateDefaultSubobject)은 생성자에서, 다른 액터 참조나 월드 접근은 BeginPlay에서 처리.

 

2. 성능 관리

  • 매 프레임마다 호출되는 Tick 함수는 비용이 클 수 있다.
  • 따라서 필요한 액터만 Tick을 활성화하거나 이벤트 기반으로 전환해 최적화해야 한다.

 

3. 리소스 정리

  • 액터가 사라질 때(EndPlay, Destroyed 등) 메모리를 해제하거나 특정 상태를 저장해야 할 수 있다.
  • 적절한 시점에 필요한 정리 작업을 하지 않으면 메모리 누수나 예외 상황이 발생할 수 있다.

2. 주요 라이프 사이클 함수

언리얼 엔진의 Actor는

  1. 생성
  2. 초기화
  3. 월드 배치
  4. Tick(실행)
  5. 제거

순으로 동작하며, 이를 지원하기 위해 여러 함수가 자동 호출된다.

 

2 - 1. 생성자(Constructor)

  • C++ 클래스 객체가 메모리에 생성될 때 단 한 번 호출한다.
  • 아직 월드에 완전히 등록된 상태가 아니므로, 다른 액터나 월드 관련 기능은 안전하게 호출하기 어렵다.
  • 보통 컴포넌트 생성(CreateDefaultSubobject) 및 기본 변수 초기화에 사용한다.

 

2 - 2. PostInitializeComponents()

  • 액터의 모든 컴포넌트가 생성/초기화를 마친 뒤 자동으로 호출된다.
  • 컴포넌트들이 이미 준비된 상태이므로, 컴포넌트 간 상호작용 초기화 코드를 넣기 좋다.

 

2 - 3. BeginPlay()

  • 게임이 시작되거나 런타임 중 액터가 새로 생성(Spawn)되는 순간에 한 번 호출된다.
  • 이 시점에서는 월드와 다른 액터들이 준비된 상태이므로 자유롭게 상호작용 코드를 작성할 수 있다.
  • AI, 게임 모드, 플레이어 컨트롤러 등 다른 시스템과의 연동도 보통 이 시점에 처리한다.

 

2 - 4. Tick(float DeltaTime)

  • 매 프레임마다 반복 호출되며, 실시간 업데이트가 필요한 로직(캐릭터 이동, 물리 연산 등)을 넣는다.
  • 불필요한 액터에는 Tick을 끄고, 이벤트 기반으로 전환하면 성능을 절약할 수 있다.

 

2 - 5. Destroyed

  • Destroy() 함수를 직접 호출해 액터를 제거하기 직전에 호출된다. (단 게임 종료나 레벨 전환 시에는 호출되지 않을 수 있음.)
  • 보통 EndPlay에서 주요 정리를 마치고 Destroyed()에서 메모리 해제나 사운드/파티클 정리등 최종 작업을 수행한다.
  • Destroyed가 불리면 마지막에 EndPlay도 같이 호출된다.

 

2 - 6. EndPlay(const EEndPlayReason::Type EndPlayReason)

  • 액터가 더 이상 월드에서 활동하지 않을 때 (파괴, 게임 종료, 레벨 전환 등) 호출된다.
  • EEndPlayReason::Type은 언리얼 엔진에서 EndPlay 함수가 호출되는 이유를 나타내는 열거형 타입이다.
  • 이 함수에서 자원 해제나 상태 저장을 관리한다. 

심화

언리얼 엔진 공식 문서의 Actor LifeCycle 도식화한 그림

위 그림을 보면 시작점이 Play in Editor, LoadMap(AddToWorld), SpawnActor, SpawnActorDeferred로 4개가 있다. 이들을 하나씩 자세히 알아보자.

 

Play in Editor (에디터에서 실행 시)

  1. Editor에 있는 Actor들은 New World로 복사되고, UObject::PostDuplicate가 호출된다.
  2. 이후 Actor들이 gameplay를 시작하기 위한 UAISystemBase::InitializeActorsForPlay가 world에 의해 호출된다.
  3. 초기화되지 않은 Actor에 ULevel::RouteActorInitialize를 호출한다.
  4. 레벨이 시작되었다는 AActor::BeginPlay를 호출한다.
더보기

초기화 순서

  1. AActor::PreInitializeComponents
  2. UActorComponent::InitializeComponent
  3. AActor::PostInitializeComponents

 

Load from Disk (파일로 게임 실행 시)

UEngine::LoadMap 또는 동적으로 맵의 일부분을 로드하고 언로드하는 레벨 스트리밍에서 UWorld::AddToWorld를 호출할 때 발생한다. 

 

패키지/레벨에 있는 Actor가 Disk에서 로드되고, PostLoad를 호출한다. 

전체적인 흐름은 에디터에서 플레이와 매우 유사하다.

 

Spawn& Deferred Spawn

미리 레벨에 배치되지 않은 Actor를 UWorld::SpawnActor로 Spawn 할 때의 LifeCycle이다.

 

  1. Actor가 World에 Spawn된 이후 AActor::PostSpawnInitialize를 호출한다.
  2. Spawn된 Actor의 생성 이후 AActor::PostActorCreated를 호출한다. 생성자와 관련된 구현을 담는 함수로 PostLoad와 배타적이다.
  3. AActor::ExecuteConstruction -> AActor::OnConstruction(블루 프린트 Actor의 컴포넌트 생성, 변수 초기화 시점) -> AActor::PostActorConstuction
  4. 미리 배치된 Actor와 마찬가지로 컴포넌트 초기화
  5. UWorld::OnActorSpawned로 Delegate Broadcast 이후 AActor::BeginPlay를 호출한다. 

 

End of Actor Lifecycle

Destroy, Lifetime 종료, Level Transition, Editor에서 플레이 종료, Game End, applicaition closing에 의해 EndPlay가 호출되고 Actor는 RF_PendingKill로 마킹된다.

 

이후 ULevel의 Actor Array에서 해당 Actor는 제거되고 다음 garbage collection cycle에 마킹된 Actor의 메모리를 할당 해제 한다.

 

garbage collection의 과정에서 UObject::BeginDestroy, UObject::IsReadyForFinishDestroy(준비가 되지 않았다면 다음 cycle에서 진행한다.), UObject::FinisihDestroy의 함수가 추가로 호출된다.


참고 블로그

https://dlaiml.tistory.com/entry/UE5-Actor-Lifecycle-%EC%95%A1%ED%84%B0-%EC%83%9D%EC%95%A0%EC%A3%BC%EA%B8%B0