티스토리 뷰

🟩 오늘의 목표

  • IItemInterface의 함수 시그니처를 언리얼 오버랩 이벤트 규격에 맞게 확장한다.
  • ABaseItem에서 컴포넌트 구조(Scene → Collision → StaticMesh)를 설정하고 이벤트를 바인딩한다.
  • 코인, 힐링, 지뢰 각 아이템의 특성에 맞는 실전 로직(점수 추가, 체력 회복, 지연 폭발)을 완성한다.

🟧 1. 인터페이스 및 부모 클래스 설계

🟦 IItemInterface : 이벤트 바인딩을 위한 규격 수정

  • 오버랩 이벤트는 엔진에서 정해진 매개변수 형식이 있다. 이를 인터페이스에도 그대로 반영해야 한다.
#pragma once

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

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

class SPARTAPROJECT_API IItemInterface
{
    GENERATED_BODY()

public:
    // 엔진 오버랩 이벤트와 바인딩하기 위해 UFUNCTION() 필수
    UFUNCTION()
    virtual void OnItemOverlap(
        UPrimitiveComponent* OverlappedComp,
        AActor* OtherActor,
        UPrimitiveComponent* OtherComp,
        int32 OtherBodyIndex,
        bool bFromSweep,
        const FHitResult& SweepResult) = 0;

    UFUNCTION()
    virtual void OnItemEndOverlap(
        UPrimitiveComponent* OverlappedComp,
        AActor* OtherActor,
        UPrimitiveComponent* OtherComp,
        int32 OtherBodyIndex) = 0;

    virtual void ActivateItem(AActor* Activator) = 0;
    virtual FName GetItemType() const = 0;
};

 

🟦 ABaseItem : 아이템의 물리적 구조와 이벤트 연결

  • 생성자에서 컴포넌트를 계층 구조로 배치하고, OverlapAllDynamic 프리셋을 통해 감지 영역을 설정한다.
// BaseItem.cpp 핵심 로직
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);

    // 델리게이트 바인딩: 충돌 시 함수 자동 호출
    Collision->OnComponentBeginOverlap.AddDynamic(this, &ABaseItem::OnItemOverlap);
    Collision->OnComponentEndOverlap.AddDynamic(this, &ABaseItem::OnItemEndOverlap);
}

void ABaseItem::OnItemOverlap(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
    // "Player" 태그가 붙은 액터가 들어왔을 때만 실행
    if (OtherActor && OtherActor->ActorHasTag("Player"))
    {
        GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, TEXT("Item Overlap Detected!"));
        ActivateItem(OtherActor); // 실제 아이템 효과 발동
    }
}

🟧 2. 아이템별 특화 로직 구현 (주석 내용 반영)

🟦 코인 및 힐링 아이템 : 즉시 발동형

  • 획득 즉시 디버그 메시지를 띄우고(이후 실제 수치 증가 로직 추가 가능) 액터를 제거한다.
// ACoinItem::ActivateItem
void ACoinItem::ActivateItem(AActor* Activator)
{
    if (Activator && Activator->ActorHasTag("Player"))
    {
        // 실제 구현: 플레이어의 점수 변수를 PointValue만큼 증가시키는 로직이 들어갈 자리
        GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Cyan, FString::Printf(TEXT("Player Gained %d Points!"), PointValue));
        DestroyItem(); // 획득 후 제거
    }
}

// AHealingItem::ActivateItem
void AHealingItem::ActivateItem(AActor* Activator)
{
    if (Activator && Activator->ActorHasTag("Player"))
    {
        // 실제 구현: Activator를 캐릭터로 캐스팅하여 체력을 HealAmount만큼 회복
        GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, FString::Printf(TEXT("Player Healed %d HP!"), HealAmount));
        DestroyItem();
    }
}

 

🟦 지뢰 아이템 (AMineItem) : 지연 발동 및 범위 검사

  • 가장 핵심적인 부분으로, FTimerHandle을 통한 지연 실행과 GetOverlappingActors를 이용해 범위 내 타격 판정을 구현한다.
// AMineItem.cpp
AMineItem::AMineItem()
{
    ExplosionDelay = 5.0f;
    ExplosionRadius = 300.0f;
    ExplosionDamage = 30;
    ItemType = "Mine";

    // 폭발 범위를 시각화하거나 계산할 별도의 콜리전
    ExplosionCollision = CreateDefaultSubobject<USphereComponent>(TEXT("ExplosionCollision"));
    ExplosionCollision->InitSphereRadius(ExplosionRadius);
    ExplosionCollision->SetCollisionProfileName(TEXT("OverlapAllDynamic"));
    ExplosionCollision->SetupAttachment(Scene);
}

void AMineItem::ActivateItem(AActor* Activator)
{
    // 5초(ExplosionDelay) 후 Explode 함수가 실행되도록 타이머 예약
    GetWorld()->GetTimerManager().SetTimer(ExplosionTimerHandle, this, &AMineItem::Explode, ExplosionDelay, false);
}

void AMineItem::Explode()
{
    TArray<AActor*> OverlappingActors;
    ExplosionCollision->GetOverlappingActors(OverlappingActors); // 현재 범위 내 모든 액터 수집

    for (AActor* Actor : OverlappingActors)
    {
        if (Actor && Actor->ActorHasTag("Player"))
        {
            // 실제 구현: 플레이어에게 ExplosionDamage만큼의 데미지 전달
            GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, FString::Printf(TEXT("BOOM! Player damaged by %d"), ExplosionDamage));
        }
    }
    DestroyItem(); // 폭발 후 지뢰 제거
}

 


🟧 3. 에디터 설정 및 검증 방법

  • 콜리전 프리셋 : 아이템은 보통 OverlapAllDynamic을 사용하여 물리적 저항 없이 겹침만 감지하도록 설정한다.
  • 쿼리 전용(Query Only) : 물리적으로 캐릭터를 밀어낼 필요가 없다면 Collision Enabled를 Query Only로 설정하여 CPU 부하를 줄인다.
  • 디버그 팁 : 게임 실행 중 Alt + C를 눌러 콜리전 영역이 적절한 크기로 설정되어 있는지 확인한다.

🟧 핵심 요약 및 주의사항

  • UFUNCTION()의 중요성 : 델리게이트(AddDynamic)에 등록할 함수는 엔진이 찾을 수 있도록 반드시 UFUNCTION() 매크로가 선언되어 있어야 한다.
  • 태그 기반 판정 : ActorHasTag("Player")를 활용하면 복잡한 캐스팅 없이도 대상이 플레이어인지 빠르게 판별할 수 있다.
  • 타이머 핸들 : FTimerHandle을 통해 예약된 함수는 액터가 파괴되기 전에 실행되거나, 필요시 ClearTimer로 취소할 수 있도록 관리해야 한다.

'내일배움캠프 Unreal_7기 > 본캠프' 카테고리의 다른 글

TIL - 45일차  (0) 2026.01.30
TIL - 44일차  (0) 2026.01.29
TIL - 42일차  (0) 2026.01.27
TIL - 41일차  (0) 2026.01.26
TIL - 40일차  (0) 2026.01.23