본문 바로가기

[C++과 Unreal Engine으로 3D 게임 개발] 인터페이스 기반 아이템 클래스 설계

@iamrain2025. 9. 29. 15:23

인터페이스란?

인터페이스(Interface)는 클래스(또는 오브젝트)가 반드시 구현해야 할 함수 목록을 미리 정의해두고, 실제 함수의 동작(구현 내용)은 해당 클래스를 상속받거나 구현하는 쪽에서 자유롭게 작성할 수 있도록 하는 일종의 계약서라고 할 수 있다.

C++에서는 `UInterface`를 상속받아 `IItemInterface` 같은 인터페이스를 만들 수 있으며, 언리얼 블루프린트에서도 "블루프린트 인터페이스"를 통해 비슷한 개념을 구현할 수 있다.

상속(Inheritance)과의 차이점

  • 상속
    • 부모 클래스의 모든 속성과 기능을 자식 클래스가 물려받는 구조
    • 부모 클래스에 구현된 로직을 자식 클래스가 그대로 사용 가능. 필요 시 자식 클래스에서 재정의 할 수 있음.
  • 인터페이스
    • "이 함수는 반드시 만들어야 한다"라는 함수 원형(시그니처)만 정의
    • 실제 함수의 동작은 자식(또는 구현 클래스)에서 자유롭게 작성
상속은 부모의 실제 구현을 가져다 쓰고, 인터페이스는 "함수의 틀"만 빌리고 내부 코드는 직접 작성한다.

인터페이스의 장점

  • 결합도(Coupling) 감소
    • 클래스 간 구체적인 구현 내용을 공유하지 않고, 필요한 함수 목록만 약속하므로 클래스 간 의존도가 낮아짐
  • 확장성(Extensibility) 향상
    • 새로운 아이템 클래스를 만들 때 이미 정의된 인터페이스를 구현만 하면 기존 시스템에 쉽게 편입할 수 있음
  • 다형성(Polymorphism) 극대화
    • `TArray<IItemInterface*> Items;`와 같이 인터페이스 포인터 배열로 관리하면, 아이템 종류가 무엇이든 같은 함수를 호출하여 다룰 수 있음

 

인터페이스 정의 및 아이템 부모 클래스 구현

인터페이스 정의

#pragma once

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

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

class MYPROJECT_API IItemInterface
{
	GENERATED_BODY()

public:

	virtual void OnItemOverlap(AActor* OverlapActor) = 0;
	virtual void OnItemEndOverlap(AActor* OverlapActor) = 0;
	virtual void ActivateItem(AActor* Activator) = 0;
	virtual FName GetItemType() const = 0;
};
타입 형을 알아낼 때는 FString보다 FName가 속도도 빠르고 메모리도 절약할 수 있다. 타입을 빨리 알아내고 비교할 때는 FName을 추천한다.

부모 클래스 구현

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ItemInterface.h"
#include "BaseItem.generated.h"

UCLASS()
class MYPROJECT_API ABaseItem : public AActor, public IItemInterface
{
	GENERATED_BODY()
	
public:	
	ABaseItem();

protected:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
	FName ItemType;

	virtual void OnItemOverlap(AActor* OverlapActor) override;
	virtual void OnItemEndOverlap(AActor* OverlapActor) override;
	virtual void ActivateItem(AActor* Activator) override;
	virtual FName GetItemType() const override;
};
#include "BaseItem.h"

ABaseItem::ABaseItem()
{
	PrimaryActorTick.bCanEverTick = false;
}

void ABaseItem::OnItemOverlap(AActor* OverlapActor)
{

}

void ABaseItem::OnItemEndOverlap(AActor* OverlapActor)
{

}

void ABaseItem::ActivateItem(AActor* Activator)
{

}

FName ABaseItem::GetItemType() const
{
	return ItemType;
}

기본적으로 빈 함수이고 세부 구현은 상속받은 자식 클래스에서 구현한다.

 

아이템 클래스 구현

공통 로직 클래스 구현

#pragma once

#include "CoreMinimal.h"
#include "BaseItem.h"
#include "CoinItem.generated.h"

UCLASS()
class MYPROJECT_API ACoinItem : public ABaseItem
{
	GENERATED_BODY()
	
public:
	ACoinItem();

protected:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
	int32 PointValue;
};
#include "CoinItem.h"

ACoinItem::ACoinItem()
{

}

 

점수 아이템 클래스 구현

공통 로직 클래스를 상속받는 클래스 생성

#pragma once

#include "CoreMinimal.h"
#include "CoinItem.h"
#include "BigCoinItem.generated.h"

UCLASS()
class MYPROJECT_API ABigCoinItem : public ACoinItem
{
	GENERATED_BODY()

public:
	ABigCoinItem();

	virtual void ActivateItem(AActor* Activator) override;
};
#include "BigCoinItem.h"

ABigCoinItem::ABigCoinItem()
{
	PointValue = 50;
	ItemType = "BigCoin";
}

void ABigCoinItem::ActivateItem(AActor* Activator)
{
	DestoryItem();
}

 

`DestoryItem()`은 부모 클래스에서 구현해준다.

...

UCLASS()
class MYPROJECT_API ABaseItem : public AActor, public IItemInterface
{
	...

protected:
	...

	virtual void DestoryItem();
};
#include "BaseItem.h"

...

void ABaseItem::DestoryItem()
{
	Destroy();
}

 

효과 아이템 클래스 구현

점수 아이템과 다른 아이템이기 때문에 BaseItem으로 생성

#pragma once

#include "CoreMinimal.h"
#include "BaseItem.h"
#include "HealingItem.generated.h"

UCLASS()
class MYPROJECT_API AHealingItem : public ABaseItem
{
	GENERATED_BODY()
	
public:
	AHealingItem();

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
	float HealAmount;

	virtual void ActivateItem(AActor* Activator) override;
};
#include "HealingItem.h"

AHealingItem::AHealingItem()
{
	HealAmount = 20.0f;
	ItemType = "Healing";
}

void AHealingItem::ActivateItem(AActor* Activator)
{
	DestoryItem();
}
iamrain
@iamrain :: Annals of Unreal

iamrain 님의 블로그 입니다.

공감하셨다면 ❤️ 구독도 환영합니다! 🤗

목차