언리얼 엔진에서의 액터 라이프사이클
언리얼 엔진에서는 액터(`Actor`)가 생성, 초기화, 실행, 종료되는 전체 과정이 체계적으로 관리됩니다. 아래는 디스크에서 로드, 에디터에서 플레이, 스폰, 디퍼드 스폰, 그리고 액터 종료에 이르는 과정을 설명합니다.
라이프사이클 분해도
🔹 디스크에서 로드
디스크에서 로그(Load from Disk) 경로는 `UEngine::LoadMap`이 발생할 때나 레벨 스트리밍에서 `UWpr;d::AddToWorld`를 호출하는 경우처럼 이미 레벨에 있는 액터에 대해서 발생합니다.
📌 UEngine::LoadMap? , UWorld::AddToWorld?
`UEngine::LoadMap()` ❓
이 함수는 새로운 레벨을 로드하는 과정에서 호출됩니다.
일반적인 게임에서 맵을 변경할 때(`Open Level` 실행 시) 실행됩니다.
1. 레벨이 새로 로드될 때
- 언리얼은 `UWorld` 인스턴스를 생성하고, 필요한 레벨 데이터를 불러옵니다.
- 레벨 데이터가 메모리에 존재하지 않는다면, HDD/SSD에서 로드 됩니다.
- 이미 로드된 레벨이라면, 디스크 I/O 없이 활성화 됩니다.
2. 액터들이 로드됨
- 레벨 파일(예:`.umap`) 내부에는 배치된 액터(Placed Actors) 정보가 포함되어 있습니다.
- `UEngine::LoadMap()`은 이 데이터를 이용해 액터들을 메모리에 생성(역직렬화, Deserialize)한 후, 활성화 합니다.
- 레벨이 완전히 준비된 후 `UWorld::BeginPlay()`에서 호출됩니다.
`UWorld::AddToWorld()` ❓
이 함수는 레벨 스트리밍(Level Streaming)에서 사용되는 함수입니다.
1. 스트리밍 레벨이 로드될 때 호출
- 예를 들어 `Load Level Instance` 또는 `Load Stream Level` 노드를 호출하면, 해당 서브 레벨의 데이터가 활성화 됩니다.
- `UWorld::AddToWorld()`는 이미 로드된 레벨 데이터를 게임 세계에 추가하는 역할을 합니다.
2. 기존 액터 활성화
- 해당 레벨에 배치된 액터들은 이미 저장된 메모리 정보에서 재구성됩니다.
- 새로운 액터를 생성하는 것이 아니라, 기존 데이터가 메모리에서 활성화됩니다.
- 패키지/레벨에 있는 액터가 디스크에서 로드 됩니다.
- 디스크에서 로드완료 후 시리얼라이즈(직렬화)된 액터에서 `PostLoad`를 호출합니다. 커스텀 버전 관리와 픽스업 행동이 여기서 이루어져야 합니다. Post Load는 PostActorCreated와 상호 배타적입니다. (PostActorCreated()는 스폰된 액터에서만 호출, PostLoad()는 디스크에서 로드된 액터에서 호출)
- 월드에서 `UAISystemBase::InitializeActorsForPlay`를 호출하여 액터를 준비하고 게임플레이를 시작합니다.
- 레벨에서 시리얼라이즈(직렬화)되지 않는 액터와 심리스 트래블 전환 처리에 대해서 `ULevel::RouteActorInitialize`를 호출합니다.
a. 액터의 컴포넌트에서 InitializeComponent를 호출하기전에 `AActor::PreInitializeComponent`를 호출합니다.
b. `UActorComponent::InitializeComponent`는 액터에 정의된 각 컴포넌트를 생성하는 헬퍼 함수입니다.
c. `AActor::PostInitializeComponents`는 액터의 컴포넌트가 초기화된 후에 호출됩니다. - 레벨이 시작될 때 AActor::BeginPlay가 호출됩니다.
📌 추가 설명
"디스크에서 로드"는 레벨 파일(`.umap`)을 읽어와 게임 세계에 배치된 액터를 복원하는 과정입니다. 레벨 파일은 마치 게임의 설계도처럼 나무, 건물, 캐릭터의 초기 위치 등이 저장된 정보입니다. 디스크에서 데이터를 읽어온 후, 각 데이터는 언리얼 엔진의 액터 객체로 변환 됩니다. 이후 `PostLoad`함수가 호출되어 데이터의 누락이나 버전을 수정하고 초기화 작업을 수행합니다.
🔹 에디터에서 플레이
에디터에서 플레이(Play In Editor) 경로에서는 액터를 디스크에서 로드하는 대신 에디터에서 복사합니다. 그런 다음 복사된 액터는 디스크에서 로드 경로에 설명된 흐름과 유사하게 초기화됩니다.
- 에디터의 액터가 새 월드에 복제됩니다.
- `UObject::PostDuplicate`를 호출합니다.
- `UAISystemBase::InitializeActorsForPlay`
- 초기화 되지 않는 액터에 대해 `ULevel::RouteActorInitialize`를 호출하고 모든 심리스 트래블 전환 처리를 처리합니다.
액터의 컴포넌트에서 InitializeComponent를 호출하기 전에 `AActor::PreInitializeComponents`를 호출합니다.
a. `UActorComponent::InitializeComponents`는 액터에 정의된 각 컴포넌트를 생성하는 헬퍼함수입니다.
b. `AAcotr::PosInitializeComponents`는 액터의 컴포넌트가 초기화된 후에 호출됩니다. - 레벨이 시작될 때 `AActor::BeginPlay`가 호출됩니다.
📌 추가 설명
"에디터에서 플레이"는 원본 데이터를 안전하게 보호하면서 테스트 환경을 만듭니다.
즉, 현재 레벨의 모든 데이터(나무, 건물, 캐릭터 등등)을 복사한 후, 복사본으로 새로운 테스트 환경을 실행합니다.
이 과정에서는 디스크에서 데이터를 다시 읽지 않고, 메모리에 있는 데이터를 그대로 복제하여 사용합니다.
🔹 스폰
액터 인스턴스를 스폰할 때 따라가는 경로는 다음과 같습니다.
- `UWorld::SpawnActor`를 호출합니다.
- 액터가 월드에 스폰된 이후 `AActor::PostSpawnInitialize`가 호출됩니다.
- `AActor::PostActorCreated`는 생성 이후 스폰된 액터에 대해 호출되며, 모든 생성자 구현 동작은 여기로 이동해야 합니다. PostActorCreated는 `PostLoad`와 상호 배타적입니다. (PostActorCreated()는 스폰된 액터에서만 호출, PostLoad()는 디스크에서 로드된 액터에서 호출)
- `AActor::ExecuteConstruction`
- AActor::OnConstruction` - 액터 생성, 블루프린트 액터의 컴포넌트 생성 및 블루프린트 변수가 초기화됩니다.
- `AAcotr::PostActorConstruction`
1. 액터의 컴포넌트에서 InitializeComponent를 호출하기 전에 `AActor::PreInitializeComponents`를 호출합니다.
a. `UActorComponent::InitializeComponents`는 액터에 정의된 각 컴포넌트를 생성하는 헬퍼함수입니다.
b. `AAcotr::PosInitializeComponents`는 액터의 컴포넌트가 초기화된 후에 호출됩니다. - `UWorld::OnActorSpawned`가 UWorld에서 브로드캐스트 됩니다.
- `AActor::BeginPlay`가 호출됩니다.
📌 추가 설명
"스폰"은 게임 도중 동적으로 액터를 생성하는 과정입니다. 예를 들어, 게임 플레이 중 적 캐릭터를 특정 위치에 소환하고 싶다면 스폰을 사용합니다. 이 과정은 미리 배치된 액터와 달리, 프로그래밍적으로 생성된 데이터를 초기화합니다.
🔹 디퍼드 스폰
스폰 시 노출(Expose On Spawn)으로 설정된 프로퍼티가 있으면 액터는 디퍼드 스폰(Deferred Spawn) 될 수 있습니다.
디퍼드 스폰(Deferred Spawn)은 스폰 시 초기 설정이 필요할 때 사용하는 방식입니다.
`UWorld::SpawnActorDeferred`를 호출하면 액터가 미완성 상태로 생성됩니다. 왜냐하면 `UWorld::SpawnActorDeferred()`는 `OnConstruction()`을 바로 실행하지 않고, 설정 후 `FinishSpawning()`을 호출하면 그때`OnConstructuion()`이 실행됩니다. `FinishSpawning()`을 호출하지 않으면 액터는 완전히 초기화 되지 않기에 액터가 불완전한 상태로 남을 수 있습니다.
- `UWorld::SpawnActorDeferred`는 프로시저럴 액터 스폰을 위한것으로, 블루프린트 컨스트럭션 스크립트 전에 추가적인 구성을 할 수 있습니다.
- SpawnActor 안의 모든일이 발생하지만, `AActor::PostActorCreated`후에 다음과 같은 일이 일어납니다.
a. 유효하지만 불완전한 액터 인스턴스로 다양한 `초기화 함수`를 구성하고 호출합니다.
b.AActor::FinishSpawning`가 액터를 마무리 하기 위해 호출되며, SpawnActor 줄 `AActor::ExecuteConstruction`에서 선택됩니다.
🔹 액터 라이프사이클 종료
액터를 소멸하는 방법은 여러가지가 있지만, 월드에서 제거하는 방법은 동일합니다. 게임플레이 도중 다음 함수를 호출 할 수 있지만, 플레이 도중 실제로 소멸되지 않는 액터가 많으므로 완전히 선택 사항입니다.
- 액터를 제거해야 하지만 게임플레이가 계속 진행 중일 때마다 게임에서 `AActor::Destroy`를 수동으로 호출합니다. 액터는 킬 보류 중(pending Kill)로 표시되고 레벨의 액터 배열에서 제거됩니다.
- 액터의 수명이 다해가는 것을 보장하기 위해 `AActor::EndPlay`가 여러 곳에서 호출됩니다. 플레이 도중 액터가 포함된 스트리밍 레벨이 언로드되면 이 메서드와 레벨 트랜지션이 호출됩니다.
- EndPlay가 호출되는 경우는 다음과 같습니다.
- Destroy에 대한 명시적 호출
- 에디터에서의 플레이가 종료된 경우
- 레벨 트랜지션(심리스 트래블 또는 로드 맵)
- 액터가 포함된 스트리밍 레벨이 언로드 될 때
- 액터의 수명이 만료됨
- 애플리케이션 종료
`Destroy()`가 호출되면 액터는 `PendingKill` 상태로 전환되며, 즉시 삭제가 아니라 다음 GC에서 해제가 됩니다.
`EndPlay()`는 Destroy(), 스트리밍 레벨 업로드, 심리스 트래블, 앱 종료 등 다양한 상황에서 호출이 됩니다.
🔹 정리
액터의 생성과 종료 과정은 크게 4가지로 나뉩니다.
- 디스크에서 로드: 레벨 데이터를 읽어와 액터를 메모리에 생성
- 에디터에서 플레이: 복제된 데이터로 테스트 환경 실행.
- 스폰: 게임 도중 동적으로 생성된 액터 초기화
- 종료: 액터 삭제 및 메모리에서 해제
'Unreal > Core Concepts' 카테고리의 다른 글
Reflection System (0) | 2025.02.08 |
---|---|
Interface (0) | 2025.02.07 |
LEVEL (0) | 2025.01.24 |
Actor (0) | 2025.01.15 |
Component (0) | 2025.01.15 |