튀김족발
공부 끄적이는 공간
튀김족발
전체 방문자
오늘
어제
  • 분류 전체보기 (33)
    • C++ (10)
    • DirectX (12)
    • Unreal (11)
    • Unity (0)
    • EASTL (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
튀김족발

공부 끄적이는 공간

Unreal

3-2. 언리얼 오브젝트 리플렉션 시스템

2023. 8. 7. 20:54

이제 이 리플렉션 시스템을 사용하는 예제를 만들어보자

 

새로운 클래스를 만들자

UCLASS()
class OBJECTREFLECTION_API UMyGameInstance : public UGameInstance
{
	GENERATED_BODY()
public:
	UMyGameInstance();

	virtual void Init() override;

private:
	UPROPERTY()
	FString SchoolName;
};

그리고 FString 변수에 언리얼이 관리 할수 있게 UPROPERTY() 매크로를 넣어둔다.

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());
	UE_LOG(LogTemp, Log, TEXT("===================="));
}

GetClass();, UMyGameInstance::StaticClass(); 이 두개의 함수 전부 클래스 이름을 갖고온다.
이를 확인하기 위해 주석 처리를 해놓은 함수를 한번 보자

check 함수는 꼭 검증해야 할 사항을 넣어서 체크 하자. 만약 안에 있는 값이 true 면 아무런 일이 일어나지 않지만, false 일 경우  크래시가 나게 된다. 그리고 게임을 빌드 할 경우 함수를 제거해서 문제 없어진다.

ensure 함수는 check함수와 비슷하지만, false 일 경우에 크래시가 나지 않는다. 로드만 출력 된다.

그리고 ensureMsgf는 원하는 로그 까지 출력이 가능하다.

 

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("Null 학교");

	UE_LOG(LogTemp, Log, TEXT("학교 이름 : %s"), *SchoolName);

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

중간에 수정을 하면 Null 학교로 수정이 되지만,

	UE_LOG(LogTemp, Log, TEXT("학교 이름 기본값 : %s"), *GetClass()->GetDefaultObject<UMyGameInstance>()->SchoolName);

이 함수를 사용하게 되면 생성자에서 만든 기본 값을 출력하게 된다.

 

예제를 위한 클래스

  • 어떤 학교에서 학생과 교스가 함께 수업하는 상황의 구현
  • 학교 정보는 GameInstance에서 지정
  • 인물 클래스(Person)
    • 학생 클래스(Student)
    • 선생 클래스(Teacher)
  • 클래스에 설정할 프로퍼티 정보
  • Person에는 DoLesson이라는 가상함수가 있음.
    • Studen의 DoLesson은 수업을 듣는 행동
    • Teacher의 DoLesson은 수업을 가르치는 행동

Person

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

가상함수로 DoLesson()을 선언하고 Name을 반환, 수정을 할수 있게 GetName, SetName을 선언해준다. Name과 Year은 언리얼에서 관리할 수 있게 UPROPERTY 매크로를 같이 선언해둔다

 

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

기본값, DoLesson 기본 명령어를 넣어둔다.

 

Student

#pragma once

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

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

	virtual void DoLesson() override;
	
private:
	UPROPERTY()
	int32 Id;
};

Header파일을 include 할때 generated.h 이건 맨 마지막에 오도록 하고 컴파일 해준다.
고유의 값인 Id만 선언한다.

#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

// 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:
	UPROPERTY()
	int32 Id;
};
#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);
}

그리고 처음에 만들었던 MyGameInstance 클래스로 다시 돌아온다.

 

예제

	UStudent* Student = NewObject<UStudent>();
	UTeacher* Teacher = NewObject<UTeacher>();
	Student->SetName(TEXT("학생1"));
	UE_LOG(LogTemp, Log, TEXT("새로운 학생 이름 %s"), *Student->GetName());

	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"), *Teacher->GetName());

		NameProp->SetValue_InContainer(Teacher, &NewTeacherName);
		UE_LOG(LogTemp, Log, TEXT("새로운 선생님 이름 %s"), *Teacher->GetName());
	}

Init에 넣어준다.
FProperty라는 변수에 프로퍼티 정보를 갖고온다. 저렇게 하면 UPROPERTY에 대한 포인터를 갖고온다.
그리고 GetValue_InContainer로 값을 갖고오거나, SetValue_InContrainer로 값을 변경할수 있다.

	Student->DoLesson();
	UFunction* DoLessonFunc = Teacher->GetClass()->FindFunctionByName(TEXT("DoLesson"));
	if (DoLessonFunc != nullptr)
	{
		Teacher->ProcessEvent(DoLessonFunc, nullptr);
	}

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

함수도 위 처럼 이름으로 호출이 가능하다.

언리얼의 기본 프레임 워크가 이런 리플렉션 시스템으로 이루어져있다.

'Unreal' 카테고리의 다른 글

5. 컴포지션  (0) 2023.09.11
4. 인터페이스  (0) 2023.08.31
3-1. 언리얼 오브젝트 리플렉션 시스템  (0) 2023.07.31
1. 코딩 규칙  (0) 2023.07.03
0. 서론  (0) 2023.07.03
    'Unreal' 카테고리의 다른 글
    • 5. 컴포지션
    • 4. 인터페이스
    • 3-1. 언리얼 오브젝트 리플렉션 시스템
    • 1. 코딩 규칙
    튀김족발
    튀김족발

    티스토리툴바