언리얼 오브젝트 리플렉션 시스템의 활용
강의 목표
언리얼 오브젝트 리플렉션 시스템을 사용해 언리얼 오브젝트를 다루는 방법의 학습
정리
1. 리플렉션 시스템을 사용해 언리얼 오브젝트의 특정 속성과 함수를 이름으로 검색할 수 있다.
2. 리플렉션 시스템을 사용해 접근 지시자와 무관하게 값을 설정할 수 있다.
3. 리플렉션 시스템을 사용해 언리얼 오브젝트의 함수를 호출할 수 있다.
언리얼 엔진의 기본 프레임웍은 리플렉션을 활용해 구축되어 있으므로 언리얼 엔진을 이해하기 위해서는 리플렉션 시스템을 이해하는 것이 필요함.
Person 클래스와 이를 상속받은 Student, Teacher 클래스를 만든다.
일단 Person.h 에
UCLASS()
class OBJECTREFLECTION_API UPerson : public UObject
{
GENERATED_BODY()
public:
UPerson();
UFUNCTION()
virtual void DoLesson();
const FString& GetName() const;
void SetName(const FString& InName);
protected:
UPROPERTY()
FString Name;
UPROPERTY()
int32 Year;
private:
};
이렇게 변수와 함수를 선언 해주고 alt + enter키를 눌러 Person.cpp에 구현부를 만들어 준다.
UPerson::UPerson()
{
Name = TEXT("홍길동");
Year = 1;
}
void UPerson::DoLesson()
{
UE_LOG(LogTemp, Log, TEXT("%s님이 수업에 참여합니다."), *Name);
}
const FString& UPerson::GetName() const
{
return Name;
}
void UPerson::SetName(const FString& InName)
{
Name = InName;
}
컴파일을 해서 잘 되나 확인한다.
이제 이걸 상속받은 Student클래스를 구현해보자.
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "Person.h"
#include "Student.generated.h"
언리얼 Object 를 선언할 떄는 generated.h가 가장 밑에 오게 해야 한다.
UCLASS()
class OBJECTREFLECTION_API UStudent : public UPerson
{
GENERATED_BODY()
public:
private:
};
이렇게 하고 빌드를 한다.
UCLASS()
class OBJECTREFLECTION_API UStudent : public UPerson
{
GENERATED_BODY()
public:
UStudent();
virtual void DoLesson() override;
private:
UPROPERTY()
int32 Id;
};
이렇게 하고, 함수들의 구현부를 alt + enter를 이용해 만들어준다.
컴파일을 진행한다.
#include "Student.h"
UStudent::UStudent()
{
Name = TEXT("이학생");
Year = 1;
Id = 1;
}
void UStudent::DoLesson()
{
Super::DoLesson();
UE_LOG(LogTemp, Log, TEXT("%d학년 %d번 %s님이 수업을 듣습니다."), Year, Id, *Name);
}
이렇게 구현부를 작성하고, 디폴트 오브젝트가 다시 생성해줘야 하기 때문에 컴파일 해준다.
Teacher도 동일하게 구현을 해준다.
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "Person.h"
#include "Teacher.generated.h"
/**
*
*/
UCLASS()
class OBJECTREFLECTION_API UTeacher : public UPerson
{
GENERATED_BODY()
public:
UTeacher();
virtual void DoLesson() override;
private:
UPROPERTY()
int32 Id;
};
이렇게 하고, alt+enter로 함수의 구현부를 만든 후 컴파일을 하기 전에 기본값을 지정한다.
가끔 Super:: 다음 것이 자동 검색이 안된다면 헤더 파일에서 한칸 엔터를 치거나 하면 .generated.h이 재생성 된다.
#include "Teacher.h"
UTeacher::UTeacher()
{
Name = TEXT("이선생");
Year = 3;
Id = 1;
}
void UTeacher::DoLesson()
{
Super::DoLesson();
UE_LOG(LogTemp, Log, TEXT("%d년차 선생님 %s님이 수업을 강의합니다"), Year, *Name);
}
이렇게 작성하고, 한글이 들어가 있기 때문에 새 이름으로 저장해서 인코딩을 유니코드로 바꿔준다. Student.cpp, Person.cpp도 마찬가지로 해준다.
빌드를 한다.
이 세가지 클래스들은 MyGameInstance의 Init함수에서 실행하면서 리플렉션 기능들을 테스트 해보자.
MyGameInstnace.cpp에 헤더를 선언해준다.
.cpp에 선언할 헤더도 해당 오브젝트의 헤더가 가장 위쪽에 위치해 있어야 한다. 이 규칙을 지키지 않으면 컴파일러에서 에러를 띄운다.
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyGameInstance.h"
#include "Student.h"
#include "Teacher.h"
UMyGameInstance::UMyGameInstance()
{
SchoolName = TEXT("기본학교");
}
void UMyGameInstance::Init()
{
Super::Init();
UE_LOG(LogTemp, Log, TEXT("=============================="));
UClass* ClassRuntime = GetClass();
UClass* ClassCompile = UMyGameInstance::StaticClass();
//check(ClassRuntime != ClassCompile);
//ensure(ClassRuntime != ClassCompile);
//ensureMsgf(ClassRuntime != ClassCompile, TEXT("일부러 에러를 발생시킨 코드"));
UE_LOG(LogTemp, Log, TEXT("학교를 담당하는 클래스 이름 : %s"), *ClassRuntime->GetName());
SchoolName = TEXT("청강문화산업대학교");
UE_LOG(LogTemp, Log, TEXT("학교 이름: %s"), *SchoolName);
UE_LOG(LogTemp, Log, TEXT("학교 이름 기본값: %s"), *GetClass()->GetDefaultObject<UMyGameInstance>()->SchoolName);
UE_LOG(LogTemp, Log, TEXT("=============================="));
UStudent* Student = NewObject<UStudent>();
UTeacher* Teacher = NewObject<UTeacher>();
Student->SetName(TEXT("학생1"));
UE_LOG(LogTemp, Log, TEXT("새로운 학생 이름 %s"), *Student->GetName());
FString CurrentTeacherName;
FProperty* NameProp = UTeacher::StaticClass()->FindPropertyByName(TEXT("Name"));
if (NameProp)
{
NameProp->GetValue_InContainer(Teacher, &CurrentTeacherName);
UE_LOG(LogTemp, Log, TEXT("현재 선생님 이름 %s"), *CurrentTeacherName);
}
}
이렇게 하고 빌드 하고, 언리얼에서 확인해보면

새로운 학생 이름을 GetName으로 잘 가져온 거 볼 수 있고,
이름과 선생 이름에 대해서는 언리얼 리플렉션 시스템을 사용해서 protected 지시자로 보호 받고 있는 프로퍼티 값을 가져와서 출력하게 된거. 이런 기능도 가능하다 정도로 이해하면 된다.
이번엔 선생님 이름 바꿔보자.
FString CurrentTeacherName;
FString NewTeacherName(TEXT("야부키나코"));
FProperty* NameProp = UTeacher::StaticClass()->FindPropertyByName(TEXT("Name"));
if (NameProp)
{
NameProp->GetValue_InContainer(Teacher, &CurrentTeacherName);
UE_LOG(LogTemp, Log, TEXT("현재 선생님 이름 %s"), *CurrentTeacherName);
NameProp->SetValue_InContainer(Teacher, &NewTeacherName);
UE_LOG(LogTemp, Log, TEXT("새로운 선생님 이름 %s"), *Teacher->GetName());
}
이 코드를 추가하고 언리얼에서 alt ctrl f11을 누르고 실행해 보면

잘 변경된 것을 볼 수 있다.
이번엔 리플렉션 기능으로 함수를 출력해보는 기능을 구현해보자.
Student->DoLesson();
이 함수를 실행하면 로그가 나오는지 보자

선생님과 관련된 함수는 리플렉션을 써보자.
UE_LOG(LogTemp, Log, TEXT("=============================="));
Student->DoLesson();
UFunction* DoLessonFunc = Teacher->GetClass()->FindFunctionByName(TEXT("DoLesson"));
if (DoLessonFunc)
{
Teacher->ProcessEvent(DoLessonFunc, nullptr);
}
UE_LOG(LogTemp, Log, TEXT("=============================="));

잘 찍히는 걸 볼 수 있다.
'Unreal engine > Unreal C++' 카테고리의 다른 글
| 2_2_언리얼 C++ 모던객체지향 설계_컴포지션 (0) | 2023.09.25 |
|---|---|
| 2_1_언리얼 C++ 모던객체지향 설계_인터페이스 (0) | 2023.09.22 |
| 1_5_언리얼 오브젝트의 이해_언리얼 오브젝트 리플렉션 시스템1 (0) | 2023.09.18 |
| 1_4_언리얼 오브젝트의 이해_언리얼 오브젝트 기초 (0) | 2023.09.18 |
| 1_3_언리얼 오브젝트의 이해_언리얼C++ 기본타입과 문자열 (0) | 2023.09.15 |
댓글