Unreal Object

UObject

  • 오브젝트의 베이스 클래스
    • 언리얼 엔진의 관리를 받는, 효율적으로 관리하기 위해 고안된 특수한 객체
  • UCLASS 매크로를 통해 UObject 처리 시스템이 인식
    • UE에서 제공하는 GC의 관리를 받을 수 있다
    • UCLASS의 레퍼런스를 UObject에게 넘겨준다?
  • 모든 언리얼 오브젝트는 실행 초기의 런타임 과정에서 다음 두가지를 생성한다
    • UClass 인스턴스
    • CDO
  • UObject는 U 접두사로 시작
  • 일반 C++ 클래스는 F로 시작한다
    • ex) FVector 등

UCLASS 매크로

  • 언리얼 오브젝트에 대한 계층 구조, 멤버 변수, 함수, 정보 등을 기록한다
    • 이른바 메타 정보
  • 이 매크로를 선언함으로써 언리얼 엔진이 클래스에 접근해 정보를 찾아 열람하고 사용할수 있다는 뜻
  • 런타임에 특정 클래스를 검색해 타입을 알아내고, 인스턴스의 멤버 변수 값을 변경하거나 특정 인스턴스의 멤버 함수를 호출하는 것이 가능
    • 리플렉션 같은 거라고 생각하면 될 듯?
  • 이 매크로로 UClass 클래스를 생성하고, UClass 클래스는 CDO를 생성
    • UObject에게 UClass의 레퍼런스를 전달한다

UClass 클래스

  • UCLASS 매크로가 선언된 UObject의 파생 클래스와는 별개로, 리플렉션을 위한 클래스
  • 아래와 같은 상속 계층을 가지고 있다
    • UObjectBase
      • UObjectBaseUtility
        • UObject
          • UField 외 사용자가 생성한 C++ 클래스 등등
          • UField부터는 리플렉션 데이터 관련 객체이다
            • UEnum - C++ 열거형을 위한 리플렉션 테이터 클래스
            • FProperty - C++ 멤버 변수, 함수 인자를 위한 리플렉션 데이터 클래스
            • UStruct
              • UFunction - C++ 함수를 위한 리플렉션 데이터 클래스
              • UScriptStruct - C++ 구조체를 위한 리플렉션 데이터 클래스
              • UClass - C++ 클래스를 위한 리플렉션 데이터 클래스
                • UBlueprintGeneratedClass
                • UDynamicClass
  • 컴파일 타임에는 메타 데이터를 수집, 저장하고 개별 UObject에 대한 UClass를 생성한다
    • UClass의 인스턴스를 생성하지는 않는다
  • 런타임에 UObject의 UClass 인스턴스를 생성하고, CDO를 생성 및 유지한다
  • 수집된 리플렉션 정보는 UClass에 보관되고, GetClass 함수를 통해 런타임에 접근할 수 있다
    • 컴파일 타임에는 StaticClass를 사용해 접근한다
      • 이 함수는 UHT를 통해 자동으로 생성된다
  • 코드 모듈이 로드되었을 때, 즉 엔진 초기화 시점에 생성된다
    • 모듈을 리로드하는 핫리로드일 때도 다시 생성한다

하나의 UObject에 2개의 인스턴스가 생성된다

post_thumbnail

  • UClass 인스턴스
    • 리플렉션 데이터를 보관
    • UObject 시스템 동작을 제어아는 전용 리플렉션 데이터도 포함
  • CDO 인스턴스
    • UClass에서 생성된 Object 인스턴스
    • 클래스 초기값을 보관하고, 클래스를 정의하는 C++ 함수 및 변수 정보를 포함한다
  • 위의 두 인스턴스는 읽기 전용으로 사용

Class Default Object (CDO)

  • 언리얼 오브젝트의 기본 세팅 상태를 지정
    • 기본 탬플릿 오브젝트
    • Master copy
  • UClass, 리플렉션 시스템에서 작동하기 위해 고안된 클래스에서 이 정보를 포함한다
    • C++ 언어 차원에서 제공하지 않는 리플렉션 기능을 위 방법을 통해 지원
  • 엔진이 각 오브젝트에 대한 UClass 객체를 생성하는 시점, 즉 엔진 초기화 시점에 CDO도 생성된다
    • 생성자 부분에 게임플레이와 관련된 코드를 작성하면 안되는 이유
    • 게임 스테이지 정보가 로드되지도 않은 상태에서 호출되기 때문
  • 클래스 생성자에 의해 생성된 이후 변경되지 않는다
    • 언리얼 오브젝트를 생성할 때마다 매번 초기화하지 않고, 기본 인스턴스(CDO)를 미리 만든 후 이를 복제해서 사용
    • 따라서 생성자 코드는 초기화에서만 1번 실행되고, 다른 객체에서 필요한 초기화 코드는 BeginPlay에서 실행하는 것을 권장
  • 실제 생성자에 작성한 코드는 CDO 프로퍼티를 초기화하는 데 사용한다
  • UObject가 생성될 때마다 생성자 코드는 실행된다
    • 다만 각 생성된 객체의 초기화된 값은 CDO에 정의된 값을 따른다
  • FObjectInitializer는 생성자 호출 후 처리해야할 정보를 가지고 있다
  • Object가 메모리에 할당되는 즉시 생성자가 호출되며, C++ 컴파일러의 룰에 의해 엔진이 이 과정에서 관여할 수 있는 것은 없다
    • 생성된 Object는 UObject와 Actor 초기화가 필요한 경우에 대비한 추가적인 세팅 코드를 가지고 있으며 이는 생성자 호출 이후에 실행된다

CDO에 대해서 굳이 알아야 하는 점

  • CDO는 Default 상태를 가지고 있으며, UClass에서 CDO를 통해 그 기본값을 가져올 수 있다.
  • engine 시작 시의 CDO 생성은 class의 생성자를 호출하게 되므로, 생성자에서의 잘못된 작업은 crash를 야기할 수 있다
  • engine 초기화 중 비교적 앞 단계에서 생성자가 호출되기 때문에, gameplay 관련 코드는 여기에서 실행하지 않는 것을 강하게 권장한다

리플렉션 시스템이란?

  • C++ 언어는 컴파일된 상태로 CPU로 전달된다.
    • CPU는 변수고 클래스도 일절 모르며, 이 같은 개념은 사실 컴파일러가 cpu에 명령 및 변수를 전달하고 이를 메모리 주소값으로 변환시키게 하기 위한 정보일 뿐
    • 위 같은 정보를 추적할 수 있도록 하는 것이 리플렉션 시스템이며, UE에서 제공하는 UPROPERTY, UFUNCTION, UCLASS 등과 같은 매크로로 C++ 코드를 리플렉션 시스템에 등록해서 추적할 수 있다
    • 등록된 정보는 UField 오브젝트로 생성되어 보관된다

왜 CDO를 사용하는가?

  • 동일한 class의 여러 객체를 생성한다고 가정할 때,
    • 생성자를 호출해 초기화 한 뒤 속성 값을 변경하는 방법
    • 기본 객체를 복제한 후 속성 값을 변경하는 방법

Unreal Header Tool

  • UObject 파생 유형에 제공되는 함수성을 활용하기 위해 해당 유형에 대해 헤더 파일에서 전처리 단계를 거쳐줘야 필요한 정보를 수집할 수 있다
    • 유저가 정의하는 대부분의 클래스(UObject에서 파생할테니까…)에서 언리얼 엔진이 제공하는 기능을 활용하기 위해서는, 해더파일에 전처리 단계가 이뤄져야 한다
    • 이 단계가 UHT에서 이뤄진다
#pragma once

#include 'Object.h'
#include 'MyObject.generated.h'

// UCLASS 매크로는 UMyObject 를 언리얼 엔진에 보이도록 만듭니다. 
// 이 매크로는 다양한 클래스 지정자 지원을 통해 클래스에 어떤 기능을 켜고 끌 지 결정할 수 있습니다.
UCLASS()

// MyProject 가 UMyObject 클래스를 다른 모듈에 노출시키고자 한다면, MYPROJECT_API 지정이 필수입니다.
class MYPROJECT_API UMyObject : public UObject
{
    // UObject로서 정상적으로 작동하도록 추가 함수를 생성해주는 매크로
    // 등록 함수를 자동 생성해주고 실행
    // StaticClass() 같은 함수도 포함시켜준단다 (?)
    GENERATED_BODY()

};

출처

Categories: ,

Updated: