해당 포스팅은 Stuart Butler , Tom Oliver의 Game Development Patterns with Unreal Engine 5를 바탕으로 작성한 내용입니다.
인터페이스(Interface)란 무엇인가?
인터페이스는 서로 다른 클래스가 공통적으로 제공해야 하는 동작(함수) 의 "계약(contract)"을 정의한다.
인터페이스는 구현을 가지지 않고 함수 시그니처만 정의한다. 어떤 객체가 인터페이스를 구현하면, 해당 객체는 인터페이스에 정의된 동작을 반드시 제공한다.
인터페이스의 장점
- 느슨한 결합(Loose Coupling)을 유지한다.
- 다형성(Polymorphism)을 확보한다.
- 블루프린트와 C++ 간 공통 구조를 제공한다.
인터페이스의 단점 / 주의점
* 상태(변수)를 포함하지 않는다. * 데이터 전달은 함수 매개변수로만 처리한다. * 매우 자주 호출되는 반복 로직에서는 미세한 비용이 발생한다.
사용 목적
* 여러 클래스가 동일한 동작을 처리해야 할 때 활용한다. * 타입 정보를 몰라도 동작만 호출하고 싶을 때 사용한다.
언제 인터페이스를 사용해야 하는가?
* 문, 상자, NPC 등 다양한 클래스가 Interact 같은 동일한 상호작용 기능을 제공해야 할 때 * 구체 클래스를 몰라도 메시지만 전달하고 싶을 때 * 유지보수성과 확장성을 고려하여 결합도를 낮추고 싶을 때
상태 전달이 잦다면 인터페이스보다는 이벤트/디스패처나 직접 참조가 적합할 수 있다.
블루프린트에서 인터페이스
인터페이스 생성
먼저 콘텐츠 브라우저 → Blueprint Interface 생성한다.
우선 예시로 Interact라는 함수를 만들었다.
클래스에 인터페이스 적용
블루프린트 클래스 → Class Settings → Implemented Interfaces에서 추가한다.
인터페이스 함수는 기본적으로 이벤트 형태로 표시되며 구현할 수 있다. 인터페이스에서 변수를 추가하면 리턴 노드가 포함된 함수로도 만들 수 있다.
인터페이스 호출
이제 구현된 인터페이스 함수나 이벤트를 다른 액터에서 호출할 수 있다.
C++에서의 인터페이스
인터페이스 선언 구조
언리얼 C++ 인터페이스는 두 파트로 구성된다.
* UINTERFACE 클래스: UObject 시스템용 메타 계층 * IInterface 클래스: 실제 함수 계약을 정의한다.
헤더 선언 예시
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "InteractInterface.generated.h"
// 언리얼 리플렉션용 클래스 (구현 없음)
UINTERFACE(MinimalAPI, Blueprintable)
class UInteractInterface : public UInterface
{
GENERATED_BODY()
};
// 실제 인터페이스 (함수 계약 정의)
class IInteractInterface
{
GENERATED_BODY()
public:
// 블루프린트와 C++ 둘 다에서 구현 가능하게 함
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Interaction")
void Interact(AActor* Interactor);
};
구현 예시
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "InteractInterface.h"
#include "Door.generated.h"
UCLASS()
class ADoor : public AActor, public IInteractInterface
{
GENERATED_BODY()
public:
// BlueprintNativeEvent를 구현할 때 반드시 _Implementation 필요
virtual void Interact_Implementation(AActor* Interactor) override;
};인터페이스 호출
void AMyCharacter::TryInteract()
{
FHitResult Hit;
FVector Start = FollowCamera->GetComponentLocation();
FVector End = Start + FollowCamera->GetForwardVector() * 300.0f;
FCollisionQueryParams Params;
Params.AddIgnoredActor(this);
if (GetWorld()->LineTraceSingleByChannel(Hit, Start, End, ECC_Visibility, Params))
{
AActor* HitActor = Hit.GetActor();
if (HitActor && HitActor->GetClass()->ImplementsInterface(UInteractInterface::StaticClass()))
{
// 인터페이스 함수 호출
IInteractInterface::Execute_Interact(HitActor, this);
}
}
}더 자세한 내용은 공식 문서의 언리얼 인터페이스를 읽어보면 도움이 된다.