개인프로젝트

[Unreal_C++_DarkSoul]#1_공부, Interaface 클래스

Hardii2 2022. 11. 22. 18:42

 

[Unreal_C++_DarkSoul]#1_Interaface 클래스

 

Unreal C++ 개발 중 "Interface 클래스"에 대한 내용입니다.

포트폴리오 진행 사항을 기록하기 위한 포스팅입니다.

 

 


 

Interface 

1. Header File

#include "UObject/Interface.h"

 

2. Definition

출저: https://docs.unrealengine.com/4.27/ko/ProgrammingAndScripting/GameplayArchitecture/Interfaces/

 

3. Why?

  • 두 가지 다른 객체가 공통의 기능을 구현하기 위해 필요한 클래스
  • 다중 상속에 의한  가독성 저하 + 유지 보수성 저하를 방지합니다.
  • 가독성, 유지보수성, 디버깅 효율 상승을 위한 객체지향 프로그래밍 방법

 

4. How?

  1. 새로운 C++ 클래스 생성 -> Unreal Interface 클래스를 부모 클래스로 하위 클래스 생성합니다.
  2. "IInterface_Test(임시로 만든 클래스)" 내부에 공통으로 구현할 순수 가상 함수들을 선언합니다.
  3. 해당 Interface 클래스를 각 클래스는 상속하고, 미리 선언한 순수 가상 함수들의 정의부를 작성합니다.
  4. 공통 함수들을 구현한 각 클래스는 서로의 위치에서 자유롭게 해당 함수들을 호출할 수 있게 됩니다.

 

코드 예제

1. Interface_Test.h

#pragma once

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

UINTERFACE(MinimalAPI)
class UInterface_Test : public UInterface
{
	GENERATED_BODY()
};

class U04_ACTION_API IInterface_Test
{
	GENERATED_BODY()

public:
	UFUNCTION(BlueprintNativeEvent, Category = "Interact")
		void Interact();

	UFUNCTION()
		virtual void InteractPure() = 0;

};
  1. UInterface_Test 클래스는 Unreal과 Reflection 하기 위함입니다. 따라서, 비워둡니다.
  2. "BlueprintNativeEvent"는 C++의 함수를 Blueprint에서 오버 라이딩할 수 있도록 열어줍니다.
  3. 순수 가상 함수를 선언합니다.

 

2. CPlayer.h

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Interface_Test.h"

#include "CPlayer.generated.h"

UCLASS()
class U04_ACTION_API ACPlayer : public ACharacter, public IInterface_Test
{
	GENERATED_BODY()

public:
	void Interact_Implementation() override;

	virtual void Interact_Pure() override;
	
  	//...
};
  1. "Public 상속"을 통해 인터페이스 클래스를 상속합니다.
  2. 이때, UInterface_Test 클래스가 아니라, IInterface_Test 클래스를 상속합니다.
  3. 다시 한번 강조하자면, UInterface_Test 클래스는 단순히 Unreal Editor에 Reflection 하기 위함입니다.
  4. "BlueprintNativeEvent" 함수는 "FunctionName _Implementation"을 통해 선언합니다.
  5. 일반 C++ 함수는 기존의 C++의 오버 라이딩과 동일한 방식으로 선언합니다.

 

3. 어딘가. cpp

void LineTrace()
{
    //...
    if(bHit == true)
    {
    	if(Hit.GetActor()->GetClass()->ImplementsInterface(UInterface_Test::StaticClass()))
        {
            IInterface_Test* Interface = Cast<IInterface_Test>(Hit.GetActor());
            if(Interface != nullptr)
            {
            	// C++ Only Function
            	Interface->Interact_Pure();
            	// C++ & Blueprint Overridable(?) Function
            	Interface->Execute_Interact(Hit.GetActor);
            }
        }
    }
}
  1. 먼저 특정 클래스가 Interface의 구현을 선행했는지 체크합니다.
  2. "IInterface_Test" 클래스로 캐스팅한 후, 사용하고자 하는 공통 함수를 호출합니다. 
  3. 눈여겨볼 특징은 "BlueprintNativeEvent"로 선언된 함수들은 대체로 "Implementation" 혹은 "Execute" 등의 동작을 명시하는 단어들이 함수 뒤에 따라오는 점입니다.
  4. 또 하나는 "Null Check"입니다. Unreal에서 Null Check는 "Crash"를 발생시키는 악독한 놈입니다. 조심합시다!

 

Summary
  1. UInterface_Test 클래스는 무시한다.
  2. 공통 함수는 순수 가상 함수입니다. 따라서, 인터페이스 클래스를 상속하는 하위 클래스들은 무조건 구현부를 정의해야 합니다.
  3. IInterface_Test 클래스 자료형으로 타입 캐스팅하는 과정에서 Null Check를 주의 깊게 해야 합니다.