게임 개발/언리얼 C++

언리얼C++ - 언리얼 오브젝트 리플렉션 시스템 2

싹난 감자 2024. 11. 13. 23:04

언리얼 오브젝트 리플렉션 시스템을 사용해 언리얼 오브젝트를 다루는 방법

 

리플렉션 시스템을 사용하면

  • 언리얼 오브젝트의 특정 속성과 함수를 이름으로 검색할 수 있음
  • 접근 지시자와 무관하게 값을 설정할 수 있음
  • 언리얼 오브젝트의 함수를 호출할 수 있음

리플렉션 시스템을 반드시 사용하는 것이 바람직한지는 사용하는 사람에 따라 다르나,

언리얼 엔진의 기본 프레임웍은 리플렉션을 활용해 구축되어 있으므로 언리얼 엔진을 이해하기 위해서는

리플렉션 시스템을 이해해야함

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "Person.generated.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:
};

Person.h

// Fill out your copyright notice in the Description page of Project Settings.

#include "Person.h"

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;
}

Person.cpp

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "Person.h" 

#include "Student.generated.h"
//언리얼 오브젝트를 선언할 때는 반드시 .generated.h가 가장 밑에 include되어야함

/**
 * 
 */
UCLASS()
class OBJECTREFLECTION_API UStudent : public UPerson
{
	GENERATED_BODY()
public:
	UStudent();

	virtual void DoLesson() override;

private:
	UPROPERTY()
	int32 Id;
};

Student.h

// Fill out your copyright notice in the Description page of Project Settings.

#include "Student.h"

UStudent::UStudent()
{
    Name = TEXT("이학생");
    Year = 1;
    Id = 1;
    //기본값을 설정했으면 CDO가 다시 생성되어야하기 때문에
    //미리 컴파일해주는 것이 좋다
}

void UStudent::DoLesson()
{
    Super::DoLesson();

    UE_LOG(LogTemp, Log, TEXT("%d학년 %d번 %s님이 수업을 듣습니다."), Year, Id, *Name); //인코딩 변경
}

Student.cpp

// Fill out your copyright notice in the Description page of Project Settings.

#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:
	int32 Id;
};

Teacher.h

// Fill out your copyright notice in the Description page of Project Settings.

#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);
}

Teacher.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("기본학교"); //CDO 기본값 설정
}

void UMyGameInstance::Init()
{
	Super::Init(); //원래 로직 실행

	UStudent* Student = NewObject<UStudent>(); //언리얼 오브젝트이기 때문에 new가 아니라 NewObject로 생성
	UTeacher* Teacher = NewObject<UTeacher>();

	//구현해둔 getter, setter를 이용해 값을 가져오는 방법
	Student->SetName(TEXT("학생1"));
	UE_LOG(LogTemp, Log, TEXT("새로운 학생 이름 %s"), *Student->GetName());

	//리플렉션을 활용해 값을 가져오는 방법
	FString CurrentTeacherName;
	FProperty* NameProp = UTeacher::StaticClass()->FindPropertyByName(TEXT("Name")); //클래스의 속성
	if (NameProp) //값이 있다면. 없다면 null로 진입하지 않음
	{
		//GetValue_InContainer를 사용해 이 속성에 대해서 지정한 인스턴스의 값을 빼올 수 있음
		//Teacher가 가지고 있는 객체의 속성 중 이름 속성값을 가져와야함.
		NameProp->GetValue_InContainer(Teacher, &CurrentTeacherName);
		UE_LOG(LogTemp, Log, TEXT("현재 선생님 이름 %s"), *CurrentTeacherName);
	}
}

MyGameInstance.cpp

학생 이름은 getter, setter를 이용,

선생님 이름은 언리얼 리플렉션 시스템을 이용해 protected로 보호받고 있는 프로퍼티 값을 가져옴

 

	//리플렉션을 활용해 값을 가져오는 방법
	FString CurrentTeacherName;
	FString NewTeacherName(TEXT("이득우"));
	FProperty* NameProp = UTeacher::StaticClass()->FindPropertyByName(TEXT("Name")); //클래스의 속성
	if (NameProp) //값이 있다면. 없다면 null로 진입하지 않음
	{
		//GetValue_InContainer를 사용해 이 속성에 대해서 지정한 인스턴스의 값을 빼올 수 있음
		//Teacher가 가지고 있는 객체의 속성 중 이름 속성값을 가져와야함.
		NameProp->GetValue_InContainer(Teacher, &CurrentTeacherName);
		UE_LOG(LogTemp, Log, TEXT("현재 선생님 이름 %s"), *CurrentTeacherName);

		//SetValue_InContainer를 사용해 이 속성에 대해서 지정한 인스턴스의 값을 변경할 수 있음
		NameProp->SetValue_InContainer(Teacher, &NewTeacherName);
		UE_LOG(LogTemp, Log, TEXT("새로운 선생님 이름 %s"), *Teacher->GetName());
	}

리플렉션 시스템을 사용해 값 변경

 

	UE_LOG(LogTemp, Log, TEXT("========================="));

	//함수실행
	Student->DoLesson();

	//리플렉션을 활용해 함수실행
	UFUNCTION()
	UFunction* DoLessonFunc = Teacher->GetClass()->FindFunctionByName(TEXT("DoLesson"));
	if (DoLessonFunc)
	{
		//함수를 찾았다면 ProcessEvent를 사용해 함수포인터를 넘겨주고 인자가 없기 때문에 null을 넣어준다
		Teacher->ProcessEvent(DoLessonFunc, nullptr);
	}

리플렉션 시스템을 사용해 함수 호출

 

 


이득우의 언리얼 프로그래밍 Part1 | 인프런

https://www.inflearn.com/course/%EC%9D%B4%EB%93%9D%EC%9A%B0-%EC%96%B8%EB%A6%AC%EC%96%BC-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-part-1/dashboard

 

이득우의 언리얼 프로그래밍 Part1 - 언리얼 C++의 이해 강의 | 이득우 - 인프런

이득우 | 대기업 현업자들이 수강하는 언리얼 C++ 프로그래밍 전문 과정입니다. 언리얼 엔진 프로그래머라면 게임 개발전에 반드시 알아야 하는 언리얼 C++ 기초에 대해 알려드립니다., [사진] 언

www.inflearn.com