상세 컨텐츠

본문 제목

Unreal C++ 기초 7. InterFace 기반 아이템 클래스 기능 구현

Unreal C++

by hyunjunstar 2026. 4. 16. 23:52

본문

1. 아이템 충돌(Collision) 이벤트 

언리얼에서 아이템을 플레이어가 가까이 가면 자동으로 획득 하는 기능을 아이템 구현할 때 사용하며,

별도의 함수 호출 없이 자동으로 처리되어서 간편하게 구현해서 사용이 가능함

Collision

충돌컴포넌트(Sphere, Box Component 등)로 아이템 주변에 영역을 생성

플레이어가 영역 안에 들어오면 Overlap 이벤트가 발생 및 이를 감지하여 아이템 획득 로직 실행 가능

Overlap, Hit

Overlap - 겹치면 실행(아이템 획득 및 트리거 존 감지 등)

Hit - 부딪히는 물리 충돌이 일어나면 실행(총알, 벽 등)

BaseItem 클래스에 충돌 컴포넌트 추가

 

// BaseItem.h

#pragma once

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

class USphereComponent;

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

public:
    ABaseItem();

protected:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
    FName ItemType;
    // 루트 컴포넌트
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Item|Component")
    USceneComponent* Scene;
    // 충돌 컴포넌트
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Item|Component")
    USphereComponent* Collision;
    // 스태틱 메시
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Item|Component")
    UStaticMeshComponent* StaticMesh;

    virtual void OnItemOverlap(
    	// 내 충돌 컴포넌트 (아이템의 Collision, Sphere 등)
        UPrimitiveComponent* OverlappedComp,
        // 들어온 대상 (플레이어 등 액터)
        AActor* OtherActor,
        // 상대방의 충돌 컴포넌트 (플레이어 Capsule 등)
        UPrimitiveComponent* OtherComp,
        // 충돌된 바디 인덱스
        int32 OtherBodyIndex,
        // 어떻게 들어왔는지
        bool bFromSweep,
        // 충돌 상세 정보(위치, 방향 등)
        const FHitResult& SweepResult) override;

    virtual void OnItemEndOverlap(
        UPrimitiveComponent* OverlappedComp,
        AActor* OtherActor,
        UPrimitiveComponent* OtherComp,
        int32 OtherBodyIndex) override;

    virtual void ActivateItem(AActor* Activator) override;
    virtual FName GetItemType() const override;

    void DestroyItem();
};
// BaseItem.cpp

#include "BaseItem.h"
#include "Components/SphereComponent.h"

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

    // 루트 컴포넌트 생성 및 설정
    Scene = CreateDefaultSubobject<USceneComponent>(TEXT("Scene"));
    SetRootComponent(Scene);

    // 충돌 컴포넌트 생성 및 설정
    Collision = CreateDefaultSubobject<USphereComponent>(TEXT("Collision"));
    // 물리 충돌 없이 겹침만 감지하는 프로파일 설정
    Collision->SetCollisionProfileName(TEXT("OverlapAllDynamic"));
    // 루트 컴포넌트로 설정
    Collision->SetupAttachment(Scene);

    // 스태틱 메시 컴포넌트 생성 및 설정
    StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("StaticMesh"));
    StaticMesh->SetupAttachment(Collision);

	// Overlap 이벤트 연결(들어오면 실행)
    Collision->OnComponentBeginOverlap.AddDynamic(this, &ABaseItem::OnItemOverlap);
    // Overlap 이벤트 연결(나가면 실행)
    Collision->OnComponentEndOverlap.AddDynamic(this, &ABaseItem::OnItemEndOverlap);
}

void ABaseItem::OnItemOverlap(
    UPrimitiveComponent* OverlappedComp,
    AActor* OtherActor,
    UPrimitiveComponent* OtherComp,
    int32 OtherBodyIndex,
    bool bFromSweep,
    const FHitResult& SweepResult)
{
    // 플레이어인지 확인
    if (OtherActor && OtherActor->ActorHasTag("Player"))
    {	// 플레이어가 맞으면 화면에 메시지 출력
        GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, FString::Printf(TEXT("Overlap!!!")));
        // 아이템 획득 로직 호출
        // Overlap 이벤트 발생시 ActivateItem 함수가 호출되며, 
        // 실제 아이템 획득 및 효과 기능, 효과 처리는 이 함수에서 실행됨
        ActivateItem(OtherActor);
    }
}

void ABaseItem::OnItemEndOverlap(
    UPrimitiveComponent* OverlappedComp,
    AActor* OtherActor,
    UPrimitiveComponent* OtherComp,
    int32 OtherBodyIndex)
{
}

// 아이템의 진짜 기능(여기서는 Overlap 됐는지 테스트용)
void ABaseItem::ActivateItem(AActor* Activator)
{
    GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, FString::Printf(TEXT("Overlap!!")));
}

// 아이템 종류 반환
FName ABaseItem::GetItemType() const
{
    return ItemType;
}

// 아이템 삭제
void ABaseItem::DestroyItem()
{
    Destroy();
}

2. 아이템 Blueprint 및 Static Mesh

1. C++ 클래스로 생성한 아이템들(HealingItem, MineItem, SmallCoin, BigCoin)에 각 우클릭 >

Create Blueprint Class based on ~~~ 클릭 > BP_아이템이름 으로 지정 후 Blueprints 폴더에 생성

2. 각 BP 아이템 더블클릭 후 좌측 상단 Components 탭 > Static Mesh 클릭 >

우측 상단 Details 탭 > Static Mesh, Materials 원하는거로 설정

3. 좌측 상단 Components 탭 > SphereComponent 클릭 > Collision 클릭 > 우측 상단 Details 탭 >

검색창에 sphere 검색 후 Sphere Radius에서 조절 - 뷰포트에서 범위 확인 가능

4. BP_아이템 클래스들 더블클릭 > 우측 상단 Details 창 > Collision 탭 >

Collision Presets에 Overlap All Dynamic 등록

5. BP_Chracter 클래스 더블클릭 > 우측 상단 Details 창 > Actor 탭 >

Advanced > Tags 추가 후 Player 등록

Collision Preset이란 

누구랑 어떻게 충돌할지 정해놓는 설정

Collision Preset

1. NoCollision

 - 충돌 없음 이벤트도 없음

ex) 단순 배경 오브젝트(장식용 액터, 하늘 등)

2. BlockAll

 - 모든 객체와 물리적으로 충돌하며 막음, Overlap Event는 발생하지 않음

ex) 벽, 바닥 등

3. OverlapAll

 - 모든 객체와 겹쳐지며 Overlap Event 발생

ex) 트리거, 감지용 등

4. BlockAllDynamic

 - 움직이는 객체의 충돌을 막고 고정된 객체와는 충돌하지 않음

ex) 플레이어랑만 충돌 등

5. OverlapAllDynamic

 - 움직이는 객체와 겹쳐지며 Overlap Event 발생

ex) 아이템, 센서 등

6. Pawn

 - 플레이어나 AI처럼 Pawn 타입 객체와만 충돌

ex) 플레이어, AI 등 캐릭터 전용

7. Custom

 - 직접 설정

Collision Enabled

1. NoCollision

 - 충돌 비활성

2. Query Only

 - 이벤트만 감지, 물리 충돌은 없음(아이템용)

3. Physics Only

 - 물리 충돌만 일어나며, 이벤트는 발생하지 않음

4. Query and Physics

 - 충돌 및 이벤트 둘 다 활성화

3. 아이템 클래스 충돌 구현

MineItem

설명 - 주석처리

// MineItem.h

#pragma once

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

UCLASS()
class SPARTA_API AMineItem : public ABaseItem
{
    GENERATED_BODY()

public:
    AMineItem();

protected:
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Item|Component")
    USphereComponent* ExplosionCollision;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mine")
    float ExplosionDelay;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mine")
    float ExplosionRadius;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mine")
    int ExplosionDamage;
    
    // 타이머 관리
    // 지뢰가 발동되면 이 핸들을 이용해서 일정 시간 뒤에
    // Explode() 함수가 실행되도록 설정
    FTimerHandle ExplosionTimerHandle;

    virtual void ActivateItem(AActor* Activator) override;

    void Explode();
};
// MineItem.cpp

#include "MineItem.h"
#include "Components/SphereComponent.h"

AMineItem::AMineItem()
{	
	// 지뢰 초기값 설정
    ExplosionDelay = 5.0f;
    ExplosionRadius = 300.0f;
    ExplosionDamage = 30.0f;
    ItemType = "Mine";

    // 폭발 범위 감지용 충돌 컴포넌트 생성
    ExplosionCollision = CreateDefaultSubobject<USphereComponent>(TEXT("ExplosionCollision"));
    // 폭발 범위 설정
    ExplosionCollision->InitSphereRadius(ExplosionRadius);
    // 폭발 범위 Overlap 상태 감지 설정
    ExplosionCollision->SetCollisionProfileName(TEXT("OverlapAllDynamic"));
    // 루트 컴포넌트에 부착
    ExplosionCollision->SetupAttachment(Scene);
}

void AMineItem::ActivateItem(AActor* Activator)
{	
    // 플레이어가 지뢰 범위에 들어오면 실행되는 함수
    // 타이머를 시작해서 일정 시간 뒤 Explode() 함수가 실행되도록 설정
    GetWorld()->GetTimerManager().SetTimer(ExplosionTimerHandle, this, &AMineItem::Explode, ExplosionDelay);
}

void AMineItem::Explode()
{	
    // 폭발 범위에 누가 있는지 배열로 액터들을 가져옴
    // 범위 내에 누가 있는지 검사
    TArray<AActor*> OverlappingActors;
    ExplosionCollision->GetOverlappingActors(OverlappingActors);
    
    // 폭발 범위 내에 Player 태그가 붙어있는 액터만 골라냄
    for (AActor* Actor : OverlappingActors)
    {
        if (Actor && Actor->ActorHasTag("Player"))
        {
            // 폭발 범위 내에 Player 태그가 붙어있는 액터가 있으면 
            // 화면에 데미지 메시지 출력
            GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, FString::Printf(TEXT("Player damaged %d by MineItem"), ExplosionDamage));
        }
    }

    DestroyItem();
}

HealingItem

설명 - 주석처리

// HealingItem.h

#pragma once

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

UCLASS()
class SPARTA_API AHealingItem : public ABaseItem
{
    GENERATED_BODY()

public:
    AHealingItem();

protected:
    // 회복량
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Healing")
    int32 HealAmount;

    virtual void ActivateItem(AActor* Activator) override;
};
// HealingItem.cpp

#include "HealingItem.h"

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

void AHealingItem::ActivateItem(AActor* Activator)
{
    if (Activator && Activator->ActorHasTag("Player"))
    {
        // 범위 내에 Player 태그가 붙어있는 액터가 있으면 
        // 화면에 체력회복 메시지 출력
        GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, FString::Printf(TEXT("Player gained %d HP!"), HealAmount));

        DestroyItem();
    }
}

CoinItem

설명 - 주석처리

// CoinItem.h

#pragma once

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

UCLASS()
class SPARTA_API ACoinItem : public ABaseItem
{
    GENERATED_BODY()

public:
    ACoinItem();

protected:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
    int32 PointValue;

    virtual void ActivateItem(AActor* Activator) override;
};
// CoinItem.cpp


#include "CoinItem.h"

ACoinItem::ACoinItem()
{
    // 점수 기본값을 0으로 설정
    PointValue = 0;
    ItemType = "DefaultCoin";
}

void ACoinItem::ActivateItem(AActor* Activator)
{
    if (Activator && Activator->ActorHasTag("Player"))
    {
        // 범위 내에 Player 태그가 붙어있는 액터가 있으면 
        // 화면에 점수 획득 메시지 출력
        GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, FString::Printf(TEXT("Player gained %d points!"), PointValue));

        DestroyItem();
    }
}

SmallCoinItem

설명 - 주석처리

// SmallCoinItem.h

#pragma once

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

UCLASS()
class SPARTA_API ASmallCoinItem : public ACoinItem
{
    GENERATED_BODY()

public:
    ASmallCoinItem();

    virtual void ActivateItem(AActor* Activator) override;
};
// SmallCoinItem.cpp

#include "SmallCoinItem.h"

ASmallCoinItem::ASmallCoinItem()
{
    PointValue = 10;
    ItemType = "SmallCoin";
}

void ASmallCoinItem::ActivateItem(AActor* Activator)
{
    // 부모의 기본 점수 획득 로직 사용
    Super::ActivateItem(Activator);

    // 스몰 코인만의 별도 동작은 여기에 추가
}
// BigCoinItem.h

#pragma once

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

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

public:
    ABigCoinItem();

    virtual void ActivateItem(AActor* Activator) override;
};
// BigCoinItem.cpp

#include "BigCoinItem.h"

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

void ABigCoinItem::ActivateItem(AActor* Activator)
{
    // 부모의 기본 점수 획득 로직 사용
    Super::ActivateItem(Activator);

    // 빅 코인만의 추가 동작(이펙트, 사운드 재생 등)을 여기서 추가
}

 

관련글 더보기