Unreal Reflection System
리플렉션은 런타임 중에 자기 자신을 조사하는 기능을 의미하고
C#에 있는 기능으로 C++에서는 지원하지 않지만
언리얼 오브젝트(클래스)인 경우에만 리플렉션을 이용할 수 있으며
일반 C++ 클래스는 불가능하다
언리얼 리플렉션 시스템의 동작
언리얼에서는 클래스의 멤버 변수를 속성(Property)이라고 부른다
클래스의 멤버 함수를 함수(Function)이라고 부른다
따라서,
언리얼 오브젝트 클래스의 속성에 UPROPERTY() 매크로 키워드를,
함수에 UFUNCTION() 매크로 키워드를 붙인다
매크로를 작성하고 해당 매크로에 인자를 전달함으로써
런타임 중의 언리얼 에디터에 해당 데이터를 전달할 수 있다
모든 언리얼 오브젝트는 자기 자신 클래스가 가진 속성과 함수 정보를
컴파일 타임(StaticClass())과 런타임(GetClass())에서 조회할 수 있다
기본 예시
// SGameInstance.h
...
class STUDYPROJECT_API USGameInstance : public UGameInstance
{
...
protected:
UPROPERTY()
FString Name;
};
// SGameInstance.cpp
...
USGameInstance::USGameInstance()
{
...
Name = TEXT("USGameInstance Class Default Object");
// CDO의 Name 속성에 저장
// 중단점을 걸어보면 언리얼 에디터가 실행되기 전에 호출됨
}
void USGameInstance::Init()
{
Super::Init();
UClass* CompiletimeClassInfo = StaticClass();
UClass* RuntimeClassInfo = GetClass();
checkf(CompiletimeClassInfo == RuntimeClassInfo, TEXT("CompiletimeClassInfo != RuntimeClassInfo"));
// 현재는 동일한 상태라서 크래시가 발생하지 않는다
UE_LOG(LogTemp, Log, TEXT("CompiletimeClassInfo->GetName(): %s"), *CompiletimeClassInfo->GetName());
UE_LOG(LogTemp, Log, TEXT("RuntimeClassInfo->GetName(): %s"), *RuntimeClassInfo->GetName());
// 일반적으로 모든 언리얼 오브젝트는 GetName()을 지원하고 각자의 Name이 존재한다
Name = TEXT("USGameInstance Object");
UE_LOG(LogTemp, Log, TEXT("USGameInstance::Name %s"), *(RuntimeClassInfo->GetDefaultObject<USGameInstance>()->Name));
UE_LOG(LogTemp, Log, TEXT("USGameInstance::Name %s"), *Name);
}
...
심화 예시
// SUnrealObject.h
...
class STUDYPROJECT_API USUnrealObject : public UObject
{
GENERATED_BODY()
public:
USUnrealObject();
UFUNCTION()
void HelloUnreal();
const FString& GetObjectName() const { return Name; }
protected:
UPROPERTY()
FString Name;
};
// SUnrealObject.cpp
#include "SUnrealObject.h"
USUnrealObject::USUnrealObject()
{
Name = TEXT("USUnrealObject CDO");
}
void USUnrealObject::HelloUnreal()
{
UE_LOG(LogTemp, Log, TEXT("USUnrealObjectClass::HelloUnreal() has been called."));
}
// SGameInstance.cpp
...
#include "SUnrealObject.h"
...
void USGameInstance::Init()
{
Super::Init();
USUnrealObject* USObject1 = NewObject<USUnrealObject>();
// 언리얼은 이런식으로 new 키워드가 아닌 NewObject<>() API를 사용
UE_LOG(LogTemp, Log, TEXT("USObject1's Name: %s"), *USObject1->GetObjectName());
// 우리가 정의한 Getter()
// 리플렉션 시스템을 활용한 PROPERTY 이용
FProperty* NameProperty = USUnrealObject::StaticClass()->FindPropertyByName(TEXT("Name"));
FString CompiletimeUSObjectName;
if (nullptr != NameProperty)
{
NameProperty->GetValue_InContainer(USObject1, &CompiletimeUSObjectName);
UE_LOG(LogTemp, Log, TEXT("CompiletimeUSObjectName: %s"), *CompiletimeUSObjectName);
}
// 리플렉션 시스템을 활용한 FUNCTION 이용
USObject1->HelloUnreal();
UFunction* HelloUnrealFunction = USObject1->GetClass()->FindFunctionByName(TEXT("HelloUnreal"));
if (nullptr != HelloUnrealFunction)
{
USObject1->ProcessEvent(HelloUnrealFunction, nullptr);
}
}
...
'게임 엔진 > [코드조선] 언리얼' 카테고리의 다른 글
언리얼 오브젝트 기능 - Garbage Collection (0) | 2024.05.09 |
---|---|
언리얼 오브젝트 기능 - Interface (0) | 2024.05.09 |
언리얼 오브젝트 기능 - CDO (0) | 2024.05.09 |
언리얼 기초 - 언리얼 디버깅 (0) | 2024.05.08 |
언리얼 기초 - 언리얼 코딩 컨벤션 (0) | 2024.05.08 |