Unreal5 인터페이스

이승한·2024년 3월 19일
0

Unreal5

목록 보기
5/11

언리얼 C++ 인터페이스

인터페이스란?

  • 객체가 반드시 구현해야 할 행동을 지정하는데 활용되는 타입
  • 다형성(Polymorphism)의 구현, 의존성이 분리(Decouple)된 설계에 유용하게 활용

언리얼 엔진에서 게임 콘텐츠를 구성하는 오브젝트의 설계 예시

  • 월드에 배치되는 모든 오브젝트 , 안 움직이는 오브젝트를 포함 (Actor)
  • 움직이는 오브젝트(Pawn)
  • 길찾기 시스템을 반드시 사용하면서 움직이는 오브젝트
    (INavAgentInterface 인터페이스를 구현한 Pawn)

인터페이스를 생성하면 두 개의 클래스가 생성

  • U로 시작하는 타입 클래스
  • I로 시작하는 인터페이스 클래스
    UInterface : 클래스 타입 정보의 제공
    IInterface : 실질적인 설계 및 구현

객체를 설계할 때 I 인터페이스 클래스를 사용

  • U타입 클래스 정보는 런타임에서 인터페이스 구현 여부를 파악하는 용도로 사용
  • 실제로 U타입 클래스에서 작업할 일은 없음
  • 인터페이스에 관련된 구성 및 구현은 I 인터페이스 클래스에서 진행

C++ 인터페이스의 특징

  • 추상 타입으로만 선언할 수 있는 Java, C#과 달리 언리얼은 인터페이스에도 구현 가능

예제

  • 수업에 참여하는 사람과 참여하지 않는 사람 구분
    -> 수업에 반드시 참여해야 하는 학교 구성원: Student,Teacher
    -> 수업에 참여하지 않는 학교 구성원: Staff
    -> 수업 행동에 관련된 인터페이스 :ILessonInterface

LessonInterface
LessonInterface.h

#pragma once

#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "LessonInterface.generated.h"

// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class ULessonInterface : public UInterface
{
	GENERATED_BODY()
};

/**
 * 
 */
class UNREALINTERFACE_API ILessonInterface
{
	GENERATED_BODY()

	
public:
	virtual void DoLesson()
	{
		//원래 가상함수에서 구현을 하면 안되지만 여기서는 가능하다. 근데 비워두는게 좋다.
		//이렇게 인터페이스에서 가상함수를 구현하는 경우에는 하위 상속받은 클래스에서 딱히 선언하지않아도 된다.
		UE_LOG(LogTemp, Log, TEXT("수업에 입장합니다."));
	}
};

LessonInterface.cpp

#include "LessonInterface.h"

Person 클래스

  • Student
  • Staff
  • Teacher

Person.h

#pragma once

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

/**
 * 
 */
UCLASS()
class UNREALINTERFACE_API UPerson : public UObject
{
	GENERATED_BODY()
	
public:
	UPerson();

	FORCEINLINE FString& GetName() { return Name; }
	FORCEINLINE void SetName(const FString& InName) { Name = InName; }

protected:
	UPROPERTY()
	FString Name;

};

Person.cpp

#include "Person.h"

UPerson::UPerson()
{
	Name = TEXT("홍길동");
}

Staff.h

#pragma once

#include "CoreMinimal.h"
#include "Person.h"
#include "Staff.generated.h"

/**
 * 
 */
UCLASS()
class UNREALINTERFACE_API UStaff : public UPerson
{
	GENERATED_BODY()

public:
	UStaff();
	
};

Staff.cpp

#include "Staff.h"

UStaff::UStaff()
{
	Name = TEXT("이직원");
}

Student.h

#pragma once

#include "CoreMinimal.h"
#include "Person.h"
#include "LessonInterface.h"
#include "Student.generated.h"

/**
 * 
 */
UCLASS()
class UNREALINTERFACE_API UStudent : public UPerson,public ILessonInterface
{
	GENERATED_BODY()
	
public:
	UStudent();

	virtual void DoLesson() override;
};

Student.cpp

#include "Student.h"

UStudent::UStudent()
{
	Name = TEXT("이학생");
}

void UStudent::DoLesson()
{
	ILessonInterface::DoLesson();
	UE_LOG(LogTemp, Log, TEXT("%s님은 공부합니다."), *Name);
}

Teacher.h

#pragma once

#include "CoreMinimal.h"
#include "Person.h"
#include "LessonInterface.h"
#include "Teacher.generated.h"

/**
 * 
 */
UCLASS()
class UNREALINTERFACE_API UTeacher : public UPerson,public ILessonInterface
{
	GENERATED_BODY()

public:
	UTeacher();
	
	virtual void DoLesson() override;
};

Teacher.cpp

#include "Teacher.h"

UTeacher::UTeacher()
{
	Name = TEXT("이선생");
}

void UTeacher::DoLesson()
{
	ILessonInterface::DoLesson();
	UE_LOG(LogTemp, Log, TEXT("%s님은 가르칩니다."), *Name);
}

MyGameInstance.h

#pragma once

#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "MyGameInstance.generated.h"

/**
 * 
 */
UCLASS()
class UNREALINTERFACE_API UMyGameInstance : public UGameInstance
{
	GENERATED_BODY()
	
public:
	UMyGameInstance();

	virtual void Init() override;

private:
	UPROPERTY()
	FString SchoolName;
	
};

MyGameInstance.cpp


#include "MyGameInstance.h"
#include "Student.h"
#include "Teacher.h"
#include "Staff.h"

UMyGameInstance::UMyGameInstance()
{
	SchoolName = TEXT("기본학교");
}

void UMyGameInstance::Init()
{
	Super::Init();


	UE_LOG(LogTemp, Log, TEXT("========================"));
	
	TArray<UPerson*> Persons = { NewObject<UStudent>(),NewObject<UTeacher>(),NewObject<UStaff>() };
	for (const auto Person : Persons)
	{
		UE_LOG(LogTemp, Log, TEXT("구성원 이름 : %s"), *Person->GetName());
	}
	UE_LOG(LogTemp, Log, TEXT("========================"));

	for (const auto Person : Persons)
	{
		//ILessonInterface를 상속받은 Person을 가려내는 방법으로 Cast 캐스팅 방법을 이용하여 LessonInterface가 true값으로 반환되면, 상속받은것.
		ILessonInterface* LessonInterface = Cast<ILessonInterface>(Person);
		if (LessonInterface)
		{
			UE_LOG(LogTemp, Log, TEXT("%s님이 수업에 참여 가능합니다."), *Person->GetName());
			LessonInterface->DoLesson();
		}
		else 
		{
			UE_LOG(LogTemp, Log, TEXT("%s님이 수업에 참여하지 못했습니다.."), *Person->GetName());
		}

	}
}

출력

LogTemp: ========================
LogTemp: 구성원 이름 : 이학생
LogTemp: 구성원 이름 : 이선생
LogTemp: 구성원 이름 : 이직원
LogTemp: ========================
LogTemp: 이학생님이 수업에 참여 가능합니다.
LogTemp: 수업에 입장합니다.
LogTemp: 이학생님은 공부합니다.
LogTemp: 이선생님이 수업에 참여 가능합니다.
LogTemp: 수업에 입장합니다.
LogTemp: 이선생님은 가르칩니다.
LogTemp: 이직원님이 수업에 참여하지 못했습니다..

0개의 댓글