본문 바로가기

게임 개발 공부/언리얼엔진

UE5 | C++ 개발학습 - 인터페이스

관리엔 질서가 필요하다.

질서가 생기면 효율이 생긴다.

질서는 명시되어야하고, 공유되어야한다.

그리고 경우에 따라 강제되어야하기도 한다.

대상이 자아가 있는 인격체라면 예민한 문제지만

생명이 없는 기계장치라면 이야기가 달라진다.

 

협업을 진행할 때 물론 규칙을 정해놓고 사용할 수도 있지만,

인터페이스를 사용한다면, 어긋나는 경우가 없을 것이다.

 

인터페이스(Interface)

- 여러 클래스에서 공통적으로 사용할 함수를 명시해놓는 기능.

- 일종의 코딩 설명서 또는 설계도

- 중복코드를 감소시키고, 다형성과 확장성이 좋아지고, 독립성을 증가시켜 유지보수에 이점을 가져온다.

- 인터페이스를 상속받은 클래스는 모두 인터페이스의 함수를 구현해야한다. (구현하지 않으면 에러발생)

 

작성 방법

#pragma once

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

UINTERFACE(MinimalAPI)
class UItemInterface : public UInterface // 인터페이스가 리플렉션 시스템에 등록되는 부분
{
    GENERATED_BODY()
};

class YOURGAME_API IItemInterface // 실제 인터페이스 기능이 작성되는 부분
{
    GENERATED_BODY()

public:
    // 아이템이 플레이어와 오버랩되었을 때 호출됨 
    virtual void OnItemOverlap(AActor* OverlapActor) = 0;

    // 아이템을 사용했을 때 호출됨
    virtual void UseItem() = 0;
};

- 인터페이스에선 함수는 순수가상함수로 작성되어 정의는 상속받은 클래스에서 하도록 한다.

// cpp 파일

#include "ItemInterface.h" //아무것도 정의하지 않는다.

 

 

상속받은 클래스에서 구현 

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ItemInterface.h"  // 인터페이스 포함
#include "BaseItem.generated.h"

UCLASS()
class YOURGAME_API ABaseItem : public AActor, public IItemInterface // 상속
{
    GENERATED_BODY()

public:
    ABaseItem();

    /** IItemInterface 구현 */
    virtual void OnItemOverlap(AActor* OverlapActor) override;
    virtual void UseItem() override;
};
//cpp파일에서 함수 구현
#include "BaseItem.h"
#include "GameFramework/Actor.h"

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

void ABaseItem::OnItemOverlap(AActor* OverlapActor)
{
    UE_LOG(LogTemp, Warning, TEXT("아이템과 플레이어가 충돌했습니다."));
}

void ABaseItem::UseItem()
{
    UE_LOG(LogTemp, Warning, TEXT("아이템이 사용되었습니다."));
}

 

 

사용 예시

- 인터페이스를 사용하지 않으면 아래와 같은 경우에 비슷한 기능을 각자 따로 구현해주어야한다.

// 인터페이스를 사용하지 않으면
class AWeapon : public AActor
{
public:
    void Equip();
};

class AArmor : public AActor
{
public:
    void Wear();
};

class AConsumable : public AActor
{
public:
    void Use();
};

 

- 장착 실행 함수

void AMyCharacter::InteractWithItem(AActor* ItemActor)
{
    if (AWeapon* Weapon = Cast<AWeapon>(ItemActor))
    {
        Weapon->Equip();
    }
    else if (AArmor* Armor = Cast<AArmor>(ItemActor))
    {
        Armor->Wear();
    }
    else if (AConsumable* Consumable = Cast<AConsumable>(ItemActor))
    {
        Consumable->Use();
    }
}

 

 

- 이러한 경우에 인터페이스를 이용해 하나로 통일해 줄 수 있다.

class IItemInterface
{
public:
    virtual void UseItem() = 0;  // 모든 아이템이 반드시 구현해야 하는 함수
};

class AWeapon : public AActor, public IItemInterface
{
public:
    void UseItem() override;
};

class AArmor : public AActor, public IItemInterface
{
public:
    void UseItem() override;
};

class AConsumable : public AActor, public IItemInterface
{
public:
    void UseItem() override;
};

 

- 장착 실행 함수

void AMyCharacter::InteractWithItem(AActor* ItemActor)
{
    if (ItemActor->Implements<UItemInterface>()) // 인터페이스 상속 확인
    {
        IItemInterface* Item = Cast<IItemInterface>(ItemActor);
        if (Item)
        {
            Item->UseItem();  // 아이템 종류와 관계없이 동일한 함수 호출
        }
    }
}

- 불필요한 조건문을 줄이고 새로운 아이템을 추가할 때도 기존 코드를 수정할 필요가 없다.

 

새로운 상속 클래스에서

- 새로운 상속 클래스를 생성할 때, 인터페이스에 있는 함수들을 일일이 작성할 필요 없이 자동완성 기능을 사용할 수 있다고 한다.

 

자동 완성 기능 활용법

  1. AMyActor의 클래스 정의 부분에서 public IMyInterface까지 입력한 후, 클래스 안에서 우클릭 > "Quick Actions and Refactorings..." 선택 (Ctrl + . 단축키)
  2. Implement pure virtual functions (순수 가상 함수 구현) 옵션 선택
  3. 필요한 함수들이 자동으로 생성

'게임 개발 공부 > 언리얼엔진' 카테고리의 다른 글

UE5 | C++ - FPlatformTime::Seconds();  (0) 2025.02.17
UE5 | C++ - FTimerHandle  (0) 2025.02.13
UE5 학습 - DataTable  (1) 2025.02.07
UE5 학습 - 애니메이션 리타겟팅  (1) 2025.02.06
UE5 - 모델링모드  (2) 2025.02.04