KoreanFoodie's Study

언리얼 프로퍼티 시스템 : 리플렉션(Reflection) 본문

Game Dev/Unreal C++ : Study

언리얼 프로퍼티 시스템 : 리플렉션(Reflection)

GoldGiver 2022. 3. 30. 15:04

리플렉션 : 런타임에 자기 자신을 조사하게 만들자

언리얼은 UHT(Unreal Header Tool) 을 이용해 클래스 계층 구조, 멤버 변수/함수 등의 정보를 UClass 에 저장한다. 이를 리플렉션이라고도 하고, 프로퍼티 시스템이라고도 부른다.

리플리케이션 시스템은 부가 기능으로, 리플렉션 시스템에 보이도록 했으면 하는 유형이나 프로퍼티에 주석을 달아두면 UHT 가 컴파일시 해당 정보를 수집하게 된다.

 

프로퍼티 시스템 계층 구조는 아래와 같다. (UField 아래에 UStruct, UEnum, UProperty 가 있음)

실제 예시 코드를 보자.

#include "MyObject.generated.h"

UCLASS(Blueprintable)
class UMyObject : public UObject
{
    GENERATED_BODY()

public:
    MyUObject();

    UPROPERTY(BlueprintReadOnly, EditAnywhere)
    float ExampleProperty;

    UFUNCTION(BlueprintCallable)
    void ExampleFunction();
};

 

UStruct 모든 멤버에 대한 반복처리를 위해서는, TFieldIterator 를 사용한다. 특정 UObject 타입과 서브클래스에 대해서는 TObjectIterator 를 사용한다.

for (TFieldIterator<UProperty> PropIt(GetClass()); PropIt; ++PropIt)

{
	UProperty* Property = *PropIt;
	// Do something with the property
}

// Will find ALL current UObject instances
for (TObjectIterator<UObject> It; It; ++It)
{
    UObject* CurrentObject = *It;
    UE_LOG(LogTemp, Log, TEXT("Found UObject named: %s"), *CurrentObject->GetName());
}

 리플렉션 데이터를 사용하면 (프로퍼티 열거, 데이터 주도형 방식으로 값 구하거나 설정, 리플렉션된 함수 실행, 새 오브젝트 생성까지도) 여러가지 많은 작업이 가능하다.

이를 잘 활용하면, 현재 World 에 있는 특정 클래스의 액터를 조회할 수도 있다. 다음 예시 코드를 보자.

APlayerController* MyPC = GetMyPlayerControllerFromSomewhere();
UWorld* World = MyPC->GetWorld();

// Like object iterators, you can provide a specific class to get only objects that are
// or derive from that class
for (TActorIterator<AEnemy> It(World); It; ++It)
{
    // ...
}

위의 코드는 PlayerController 를 가져와서, GetWorld 함수를 호출해 해당 PlayerController 가 속한 World 를 얻은 다음, 해당 월드에 있는 AEnemy 타입의 액터들을 조회하는 코드이다. 

추가적으로, 리플렉션 데이터를 C++ generated 코드로 저장하면 바이너리와의 동기화가 보장된다. 엔진 코드와 함께 컴파일 되기 때문이다!

 

 

사용법

UPROPERTY([specifier, specifier, ...], [meta(key=value, key=value, ...)])
Type VariableName;

UPROPERTY 는 위와 같은 형식으로 사용된다. Specifier 에는 VisibleAnywhere, EditAnywhere, [Visible, Edit] [DefaultsOnly, InstanceOnly], BlueprintReadOnly/BlueprintWriteOnly, BlueprintAssignable, Config(config) 등 이 있다.

각각의 특징과 사용처는 이 글에서 자세히 다루었으니, 꼭 읽어보도록 하자.

Comments