나만의 작은 도서관

[TIL][C++] 250915 MMO 서버 개발 101일차: [언리얼] 액터 스폰 과정, BeginPlay 본문

Today I Learn

[TIL][C++] 250915 MMO 서버 개발 101일차: [언리얼] 액터 스폰 과정, BeginPlay

pledge24 2025. 9. 16. 06:00
주의사항: 해당 글은 일기와 같은 기록용으로, 다듬지 않은 날것 그대로인 글입니다. 

개요

  • 언리얼은 초기화 시 호출되는 함수의 종류가 굉장히 많은 것 같다. 어떨 때는 NativeConstruct(), 또 어떨 때는 BeginPlay… 그 외에도 BeginStart(), C++ 생성자 등 언제 어디서 무엇을 넣어야 할지 헷갈린다. 오늘은 이에 대해 정리하고자 한다.

 

[언리얼] 액터 스폰 과정

  • 우선 기본이 되는 게임오브젝트, 액터(Actor)의 스폰 과정을 알아보자. 액터가 스폰되어 인스턴스화되는 과정은 크게 2가지가 있는데, 첫 번째는 1) 레벨에 직접 배치하는 것이며, 두 번째는 2) UWorld::SpawnActor를 호출하여 동적으로 액터를 생성하는 방법이다.
  • UWorld::SpawnActor의 역할은 액터의 컴포넌트들을 생성하고, 변수들의 초기값을 설정하는 등, 스폰 전 진행되어야 할 일련의 작업들을 처리하는 것이다.

 

UWorld::SpawnActor 호출시 호출되는 함수들

  • 월드에 액터 인스턴스를 스폰한다. SpawnActor함수가 호출되면 언리얼 엔진은 해당 액터의 네이티브 객체(C++ 객체)를 생성하여 메모리에 올리게 된다. C++ 객체가 생성되었으니 자연스레 C++ 생성자가 호출된다.
  • UWorld::SpawnActor 내부에서는 굉장히 많은 함수들이 호출된다. 이를 나열해 보면 아래와 같다.
    • UWorld::SpawnActor
    • AActor 생성자 (C++ 생성자, CDO 복사)
    • AActor::PostSpawnInitialize
    • AActor::PostActorCreated
    • AActor::ExecuteConstruction
      • 내부적으로 AActor::OnConstruction 호출
      • 블루프린트 Construction Script 실행
    • AActor::PostActorConstruction
    • AActor::PreInitializeComponents
    • UActorComponent::InitializeComponent (모든 컴포넌트에 대해)
    • AActor::PostInitializeComponents
    • UWorld::OnActorSpawned (브로드캐스트)
    • AActor::BeginPlay

SpawnActor 내부의 함수들의 역할

 

StaticConstructObject_Internal

  • UObject의 메모리 할당 및 기본 초기화를 담당하는 저수준(Low-level) C++ 함수이다. 내부에서 C++ 생성자를 호출한다.

 

AActor::PostActorCreated

  • 액터 스폰 이후 호출됨. 모든 생성자 구현 동작은 여기로 이동

 

PostActorConstruction

  • 액터의 BP 생성자인 OnConstruction 호출 이후 AActor::PostActorConstruction가 호출됨. 컴포넌트 초기화 단계의 시작인 PreInitializeComponents를 호출

 

Component 관련 함수들

  • 액터에 부착된 컴포넌트를 초기화하기 위한 함수들. 아래 순서대로 호출된다. 네트워크 복제 관련 초기화나 컴포넌트 간의 상호작용 설정을 하는 데 사용된다.
    • 컴포넌트 초기화 전 호출됨: AActor::PreInitializeComponents()
    • 컴포넌트 초기화 :UActorComponent::InitialzeComponent()
    • 컴포넌트 초기화 후 호출됨: AActor::PostInitializeComponents()

액터 스폰 과정 요약

  1. UWorld::SpawnActor 호출
  2. UWorld::SpawnActor로 인해 액터가 월드에 스폰된 직후 AActor::PostSpawnInitialize 호출
    • AActor::PostSpawnInitialize는 액터의 생성자, 액터의 부착된 모든 컴포넌트들의 초기화되고 등록된 후에 호출됨.
    • 네트워크 복제 관련 초기화나 컴포넌트 간의 상호작용 설정을 하는 데 사용됨.
  3. AActor::PostActorCreated
    • 생성 이후 스폰된 액터에 대해 호출됨. 모든 생성자 구현 동작은 여기로 이동
  4. AActor::ExecuteConstruction() → BP의 OnConstruction 실행
    • 블루프린트의 OnConstruction 노드를 호출
  5. 액터의 BP 생성자 호출 이후 - AActor::PostActorConstruction
    • 액터의 컴포넌트에서 InitializeComponent를 호출하기 전에 AActor::PreInitializeComponents를 호출
      • UActorComponent::InitializeComponent는 액터에 정의된 각 컴포넌트를 생성하는 헬퍼함수.
      • AActor::PreInitializeComponents() → UActorComponent::InitialzeComponent() → AActor::PostInitializeComponents()
  6. UWorld::OnActorSpawned가 UWorld에 Broadcast
  7. AActor::BeginPlay 호출됨

BeginPlay

  • 해당 액터에 대한 모든 초기 설정이 완료된 후에 실행됨. 즉, 액터의 생명 주기(lifecycle)에서 가장 마지막에 호출되는 초기화 함수. BeginPlay가 호출되는 시점은 아래 과정이 전부 완료된 후의 시점이다.
    • C++ 생성자: 액터 객체가 메모리에 생성되고, 컴포넌트가 부착됨
    • ExcuteConstruction: BP의 OnConstruction 노드가 실행됨
    • PostSpawnInitialize: UWorld::SpawnActor로 호출된 액터라면 이미 월드에 스폰됨

BeginPlay가 중요한 이유

  • 모든 준비가 끝난 후, 게임플레이가 시작될 때 단 한 번만 호출되기 때문. 아래와 같은 용도로 사용하기 적합
    • 게임플레이 로직 시작: 사운드 재생, AI 행동 패턴 초기화, 입력 바인딩 설정 등 게임플레이와 직접적으로 연관된 게임 로직을 초기화할 때 가장 적합
    • 다른 액터와의 상호작용: BeginPlay 시점에는 월드에 존재하는 다른 액터들이 이미 초기화된어 월드에 존재하는 상태이므로, 다른 액터의 정보를 찾거나 함수를 호출할 수 있는 안전한 시점이다.
    • 컴포넌트의 최종 상태 설정: 모든 컴포넌트가 완전히 초기화되고 위치가 확정된 후, 이들의 최종 상태를 설정하는 데 사용.