충돌 이벤트로 획득되는 아이템 구현하기

이전 포스팅에서는 클래스 구조만 짜고 로직은 비여있던 상태.
이전 포스팅: [Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]
인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]
인터페이스 기반 아이템 클래스 설계하기 인터페이스 이해하기1️⃣ 인터페이스란?인터페이스 (Interface)란 클래스 (또는 오브젝트)가 반드시 구현해야 할 함수 목록만을 미리 정의해 두고, 실제
devcol.tistory.com
충돌 (Collision) 이벤트로 획득되는 아이템 구현하기
1️⃣ 충돌 (Collision) 이벤트 기반 아이템 획득 방식 이해하기
언리얼 엔진에서 아이템을 “플레이어가 가까이 다가가기만 해도 자동으로 획득”시키고 싶다면, 보통 콜리전 (충돌) 이벤트를 사용합니다. 충돌 영역을 설정해두면, 플레이어가 그 영역 안에 들어오거나 나갈 때 자동으로 이벤트를 발생시켜주기 때문에 별도의 함수 호출 없이도 간편하게 처리할 수 있습니다.

- 충돌 영역 (Collision Volume)
- 아이템 액터 주변에 SphereComponent나 BoxComponent 같은 충돌 컴포넌트를 붙여둡니다.
- 플레이어가 이 영역 안에 들어오면 Overlap 이벤트가 발생하고, 이를 감지해 아이템 획득 로직을 실행할 수 있습니다.
- Overlap 이벤트 vs. Hit 이벤트
- Overlap 이벤트: 물리적으로 부딪히는 것 없이 액터들이 서로 “겹치기 시작”했을 때 발생합니다. 아이템 획득, 트리거 존 감지 같은 경우에 주로 사용합니다.
- 겹쳤다가 빠져 나갔을 때 등등의 이벤트도 구현되어 있습니다.
- Hit 이벤트: 실제 물리 충돌이 일어날 때 발생합니다 (예: 탄환이 벽에 부딪히는 장면). 아이템 획득처럼 “겹침”만 감지하면 되는 경우에는 Overlap 이벤트가 더욱 적합합니다.
- Overlap 이벤트: 물리적으로 부딪히는 것 없이 액터들이 서로 “겹치기 시작”했을 때 발생합니다. 아이템 획득, 트리거 존 감지 같은 경우에 주로 사용합니다.
- 아이템 획득 처리
- 충돌 영역 안에 플레이어가 들어오면 (Overlap 시작 시점), 아이템이 즉시 사라지거나(DestroyItem()), 점수를 올리거나 체력을 회복하는 등 다양한 로직을 실행할 수 있습니다.
- 초중급 개발에서 많이 쓰이는 방식으로, 한 번 제대로 설정해두면 매우 편하게 사용할 수 있습니다.
2️⃣ItemInterface 인터페이스 함수 시그니처 수정
- 아이템들이 모두 가져야 할 최소한의 동작을 위한 인터페이스에 Overlap 이벤트 처리에 바인딩할 함수를 수정하도록 합니다.
- OnItempOverlap과 OnItemEndOverlap 매개변수를 수정합니다.
ItemInterface.h
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "ItemInterface.generated.h"
// This class does not need to be modified.
UINTERFACE(MinimalAPI)
class UItemInterface : public UInterface
{
GENERATED_BODY()
};
class BC_CH3_ASSIGNMENT_5_API IItemInterface
{
GENERATED_BODY()
public:
// 구현할 아이템 종류 지뢰 , 힐링, 코인
// 힐링, 코인: 즉시 발동형 | 오버랩
// 지뢰: 5초뒤 발동 | 범위 내에 오버랩
// 플레이어가 이 아이템의 범위에 들어왔을 때 호출
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;
// 이 아이템의 유형(타입)을 반환 (예: "Coin", "Mine" 등)
virtual FName GetItemType() const = 0;
};
- UPrimitiveComponent* OverlappedComp: // 자기 자신 (원형) // 현재: 아이템
- AActor* OtherActor: // 부딪힌 Actor // 현재: 플레이어
- UPrimitiveComponent* OtherComp: // 부딪힌 Actor에 붙어있던 1차적으로 충돌을 일으킨 원인인 컴포넌트
UFUNCTION(): 의 경우 Interface 에 만 선언해두면 이후에 받아서 구현하는 클래스는 생략해도됩니다.
3️⃣기본 아이템 클래스(BaseItem)에 충돌 컴포넌트와 메시 컴포넌트 추가
- BaseItem 클래스는 모든 아이템(코인, 포션, 무기 등)에 공통으로 필요한 기능을 담는 부모 클래스입니다. 여기에는 다음과 같은 컴포넌트와 함수를 포함합니다.
- SceneComponent* Scene;
- 액터(아이템)의 루트 컴포넌트로 사용합니다.
- USphereComponent* Collision;
- 플레이어가 범위 안에 들어오면 Overlap 이벤트를 발생시킬 충돌 컴포넌트입니다.
- UStaticMeshComponent* StaticMesh;
- 아이템이 월드에 표시될 때, 시각적인 모습을 담당합니다.
- SceneComponent* Scene;
- CollisionComponent->InitSphereRadius(100.0f);
- 테스트용으로 100.0f를 사용했습니다. 실사용 시 적절한 범위로 조정하세요.
- CollisionComponent->SetCollisionProfileName(TEXT("OverlapAllDynamic"));
- SphereComponent가 다른 액터와 겹칠 때만 Overlap 이벤트를 발생시키도록 설정합니다. 물리적인 충돌(Hit)은 발생하지 않습니다.
- OnComponentBeginOverlap.AddDynamic(this, &ABaseItem::OnItemOverlap);
- 플레이어가 범위 안에 들어올 때 자동으로 OnItemOverlap을 호출합니다.
원래는 Collision->OnComponentBeginOverlap() ; 인데 문제는 이렇게 할경우 매게변수가 매우 길어서 불편하기 때문에 AddDynamic를 사용.
- Delegate 에 Binding 하는 함수
- 관련 UE 공식문서: https://dev.epicgames.com/documentation/unreal-engine/dynamic-delegates-in-unreal-engine?lang=ko
Dynamic Delegates in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community
Delegates that can be serialized and support reflection.
dev.epicgames.com
Event Binding의 장점
런타임 상에서 이벤트 바인딩이 이뤄지기 때문에 그런 동적으로 연결해서 여러 상황들에 대비가 가능합니다.
BaseItem.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ItemInterface.h" // 만들어둔 인터페이스 헤더 포함
#include "BaseItem.generated.h"
class USphereComponent;
UCLASS()
class BC_CH3_ASSIGNMENT_5_API ABaseItem : public AActor, public IItemInterface
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ABaseItem();
protected:
// 아이템 유형(타입)을 편집 가능하게 지정
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
FName ItemType;
// 루트 컴포넌트 (씬)
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item|Component")
USceneComponent* Scene;
// 충돌 컴포넌트 (플레이어 진입 범위 감지용)
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item|Component")
USphereComponent* Collision;
// 아이템 시각 표현용 스태틱 메시
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item|Component")
UStaticMeshComponent* StaticMesh;
virtual void OnItemOverlap(
UPrimitiveComponent* OverlappedComp,
AActor* OtherActor,
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;
// 아이템을 제거하는 공통 함수 (추가 이펙트나 로직을 넣을 수 있음)
virtual 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);
// 메시가 불필요하게 충돌을 막지 않도록 하기 위해, 별도로 NoCollision 등으로 설정할 수 있음.
// Overlap 이벤트 바인딩
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)
{
// OtherActor가 플레이어인지 확인 ("Player" 태그 활용)
if (OtherActor && OtherActor->ActorHasTag("Player"))
{
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, FString::Printf(TEXT("Overlap!!!")));
// 아이템 사용 (획득) 로직 호출
ActivateItem(OtherActor);
}
}
void ABaseItem::OnItemEndOverlap(
UPrimitiveComponent* OverlappedComp,
AActor* OtherActor,
UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex)
{
}
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();
}
아이템 Blueprint 생성 및 콜리전/메시 설정하기
1️⃣ 아이템 Blueprint 생성 및 Static Mesh 설정
- C++ 클래스 기반 블루프린트 생성
- C++로 작성한 클래스들을 (BigCoinItem, SmallCoinItem, MineItem, HealingItem 4개만 해당) 언리얼 에디터에서 우클릭 → Create Blueprint Class based on…을 선택해 Blueprint를 생성합니다.
- 각 아이템들 블루프린트로 상속해서 만들기: BP_BigCoinItem, BP_SmallCoinItem, BP_MineItem, BP_HealingItem

- Static Mesh 및 머티리얼 설정
- Components 패널에서 StaticMesh (UStaticMeshComponent)를 선택하세요.
- Details 패널에서 Static Mesh를 원하는 에셋으로 설정합니다.
- 메시를 선택한 상태에서 Details 패널을 보면, Material 항목이 있습니다. 원하는 머티리얼을 적용할 수 있습니다.
2️⃣ 콜리전 범위 (Sphere Radius) 조정
- Components 패널에서 SphereComponent를 선택하세요. 기본적으로 ABaseItem 클래스 내에서 충돌 컴포넌트가 생성되어 있을 것이며, 이는 BP 상속 시 그대로 노출됩니다.
- Details 패널에서 크기 조정
- Sphere Radius (또는 Box의 경우 Box Extent) 값을 변경하면 충돌 범위를 직관적으로 조절할 수 있습니다.
- 범위를 키우거나 줄일 때, 바로 뷰포트 상에서 확인 가능하므로 적절한 크기로 맞추세요.
3️⃣ 아이템 액터의 콜리전 프리셋 설정
- 콜리전 컴포넌트 설정 확인
- 생성한 BP (예: BP_BigCoin, BP_HealingItem 등)를 더블클릭하여 열고, Components 패널에서 SphereComponent(또는 BoxComponent)를 선택합니다.
- Details 패널에서 Collision 섹션을 찾습니다.
- Collision Presets가 어떤 값으로 설정되어 있는지 확인합니다. 부모 클래스(ABaseItem)에서 OverlapAllDynamic로 설정해두었습니다.
- 콜리전 프리셋 (Collision Preset)
- 언리얼 엔진은 여러 가지 콜리전 프리셋을 제공합니다. 이 프리셋을 통해 어떤 액터 (또는 채널)와 충돌을 Block할지, Overlap할지, Ignore할지를 손쉽게 설정할 수 있습니다.
- 주요 프리셋 옵션
- NoCollision
- 충돌을 전혀 감지하지 않으므로, Overlap 또는 Hit 이벤트가 발생하지 않습니다.
- 사용 예시: 단순 배경 오브젝트(하늘, 장식용 액터 등).
- BlockAll
- 모든 객체와 충돌하여 막게 됩니다. 물리적으로 충돌하지만, Overlap 이벤트는 발생하지 않습니다.
- 사용 예시: 벽, 바닥 같은 고정된 장치.
- OverlapAll
- 모든 객체와 Overlap 이벤트를 발생시킵니다.
- 사용 예시: 트리거 존, 감지 센서, 투명한 오브젝트.
- BlockAllDynamic
- 움직이는 (Dynamic) 객체만 충돌을 막습니다. 고정된 객체와는 충돌하지 않습니다.
- 사용 예시: 움직이는 플레이어나 물리 오브젝트와 상호작용하는 문, 벽. 고정된 환경 요소와는 무관하게 작동.
- OverlapAllDynamic
- 움직이는 (Dynamic) 객체와 Overlap 이벤트를 발생시킵니다.
- 사용 예시: 플레이어가 근처에 있는지 확인하는 아이템, 센서. Overlap 이벤트가 필요하지만, 물리 충돌이 필요 없는 경우.
- Pawn
- 플레이어나 AI처럼 Pawn 타입 객체를 대상으로 충돌을 감지하거나 막습니다.
- 사용 예시: 플레이어 전용 문, AI 전용 센서.
- Custom
- 각 채널에 대해 충돌 응답(Overlap, Block, Ignore)을 객체별로 세부적으로 설정할 수 있습니다.
- 보통은: 물리 반응 여부 (Collision Enabled)
- 충돌이 켜져 있어도 물리적 반응이 없는 “Query Only”인지, 물리적인 반응까지 하는 “Query and Physics”인지 구분할 수 있습니다.
- NoCollision: 충돌 비활성화
- Query Only: Overlap, Hit 등 충돌 이벤트는 감지하지만, 물리적으로 튕기거나 밀리는 반응은 없음.
- Physics Only: 물리 반응만 일어나고, 이벤트 (Overlap/Hit)는 발생하지 않음.
- Query and Physics: 충돌 이벤트 + 물리 반응 모두 활성화
- NoCollision
콜리전 관련 UE 공식문서: https://dev.epicgames.com/documentation/unreal-engine/collision-response-reference-in-unreal-engine?lang=ko
Collision Response Reference in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community
Reference guide to the Collision Presets section in Unreal Engine.
dev.epicgames.com
4️⃣ 캐릭터 태그 부여 및 콜리전 프리셋 설정
- 플레이어 클래스에 “Player” 태그 부여
- Details 패널에서 플레이어 캐릭터를 선택하고, Actor 섹션의 Tags 항목에 "Player"를 추가합니다.
- C++ 코드에서 OtherActor->ActorHasTag("Player")를 통해 플레이어인지 간단히 판별할 수 있습니다.

- 플레이어 클래스 콜리전 채널 확인
- BP_SpartaCharacter의 Capsule Component를 선택하고, Details 패널의 Collision 섹션을 살펴보세요.
- Collision Presets가 Pawn으로 설정되어 있으며, 이는 “OverlapAllDynamic”와 대체로 호환되어 Overlap 이벤트를 발생시킵니다.
- 만약 Overlap 이벤트가 작동하지 않는다면, Project Settings > Collision 탭에서 Pawn 채널과 OverlapAllDynamic 채널의 상호작용을 재확인하거나 수정해야 합니다.
아이템 클래스 충돌 처리 구현하기
이제 아이템 클래스에서 실제로 Overlap 이벤트가 발생했을 때 어떤 로직을 수행할지 살펴봅시다. 예를 들어 코인 아이템이라면 점수를 주고, 힐링 아이템이라면 체력을 회복시키며, 지뢰 아이템이라면 폭발 타이머를 돌려서 데미지를 주는 등의 동작을 구현할 수 있습니다.
1️⃣ CoinItem 코인 아이템 공통 부모 클래스 충돌 처리
- CoinItem은 “코인 아이템이 가져야 할 공통 기능(점수)”을 정의하고, 실제 점수 획득은 ActivateItem 함수에서 처리합니다.
#pragma once
#include "CoreMinimal.h"
#include "BaseItem.h"
#include "CoinItem.generated.h"
UCLASS()
class BC_CH3_ASSIGNMENT_5_API ACoinItem : public ABaseItem
{
GENERATED_BODY()
public:
ACoinItem();
protected:
// 코인 획득 시 얻을 점수 (자식 클래스에서 상속받아 값만 바꿔줄 예정)
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item")
int32 PointValue;
// 부모 클래스에서 상속받은 ActivateItem 함수를 오버라이드
virtual void ActivateItem(AActor* Activator) override;
};
#include "CoinItem.h"
ACoinItem::ACoinItem()
{
// 점수 기본값을 0으로 설정
PointValue = 0;
ItemType = "DefaultCoin";
}
void ACoinItem::ActivateItem(AActor* Activator)
{
// 플레이어 태그 확인
if (Activator && Activator->ActorHasTag("Player"))
{
// 점수 획득 디버그 메시지
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, FString::Printf(TEXT("Player gained %d points!"), PointValue));
// 부모 클래스 (BaseItem)에 정의된 아이템 파괴 함수 호출
DestroyItem();
}
}
2️⃣ BigCoinItem 빅 코인 아이템 충돌 처리
- “빅 코인” 클래스는 CoinItem을 상속받아 점수만 50으로 설정해주면 됩니다.
#include "BigCoinItem.h"
ABigCoinItem::ABigCoinItem()
{
// 상위 CoinItem의 PointValue를 50으로 덮어쓰기
PointValue = 50;
ItemType = "BigCoin";
}
void ABigCoinItem::ActivateItem(AActor* Activator)
{
// 부모의 기본 점수 획득 로직 사용
Super::ActivateItem(Activator);
// 빅 코인만의 추가 동작(이펙트, 사운드 재생 등)을 여기서 추가할 수 있음
}
3️⃣ SmallCoinItem 스몰 코인 아이템 충돌 처리
- “스몰 코인” 클래스도 CoinItem을 상속받아 점수를 10으로 지정합니다.
#include "SmallCoinItem.h"
ASmallCoinItem::ASmallCoinItem()
{
PointValue = 10;
ItemType = "SmallCoin";
}
void ASmallCoinItem::ActivateItem(AActor* Activator)
{
// 부모의 기본 점수 획득 로직 사용
Super::ActivateItem(Activator);
// 스몰 코인만의 별도 동작은 여기에 추가
}
4️⃣ HealingItem 힐링 아이템 충돌 처리
#pragma once
#include "CoreMinimal.h"
#include "BaseItem.h"
#include "HealingItem.generated.h"
UCLASS()
class SPARTAPROJECT_API AHealingItem : public ABaseItem
{
GENERATED_BODY()
public
AHealingItem();
protected:
// 회복량
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Healing")
int32 HealAmount;
virtual void ActivateItem(AActor* Activator) override;
};
#include "HealingItem.h"
AHealingItem::AHealingItem()
{
HealAmount = 20.0f;
ItemType = "Healing";
}
void AHealingItem::ActivateItem(AActor* Activator)
{
if (Activator && Activator->ActorHasTag("Player"))
{
// 회복 디버그 메시지
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Green,
//FString::Printf(TEXT("Player Gained %d HP!"), HealAmount));
FString::Printf(TEXT("Player Gained %i HP!"), HealAmount));
DestroyItem();
}
}
- 이후 Activator가 캐릭터라는 전제하에, 플레이어의 체력 변수 혹은 함수를 호출해 직접 체력 회복을 처리하는 구현을 해야합니다 (예: PlayerCharacter->Heal(HealAmount)).
5️⃣ MineItem (지뢰 아이템) 충돌 처리
- 이번에는 플레이어가 지뢰 범위에 들어오면 타이머를 시작하고, 일정 시간이 지난 후 폭발 범위 내 액터에게 데미지를 주는 지뢰 아이템입니다.
- 플레이어가 지뢰 발동 범위에 들어가면 지뢰가 활성화되고 타이머가 시작됩니다.
- 발동 후 5초가 지나면 폭발하며, 폭발 범위 내에 있는 액터를 확인합니다.
- 폭발 범위 내에 있는 액터 중 발동 범위에 남아 있던 액터에게만 데미지를 입힙니다.
- 지뢰는 폭발 후 사라집니다.
#pragma once
#include "CoreMinimal.h"
#include "BaseItem.h"
#include "MineItem.generated.h"
UCLASS()
class BC_CH3_ASSIGNMENT_5_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;
// 지뢰 발동 여부
FTimerHandle ExplosionTimerHandle;
virtual void ActivateItem(AActor* Activator) override;
void Explode();
};
- bIsActivated: 이미 지뢰가 발동되었는지 여부를 체크하기 위한 불리언 변수입니다.
- ActivateItem: 발동 이후 타이머를 설정하고, 폭발 함수를 스케줄링합니다.
- Explode: 타이머가 만료되었을 때 실제 폭발 처리를 담당합니다.
#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);
ExplosionCollision->SetCollisionProfileName(TEXT("OverlapAllDynamic"));
ExplosionCollision->SetupAttachment(Scene);
}
void AMineItem::ActivateItem(AActor* Activator)
{
// 5초 후 폭발 실행
GetWorld()->GetTimerManager().SetTimer(ExplosionTimerHandle, this, &AMineItem::Explode, ExplosionDelay);
}
void AMineItem::Explode()
{
TArray<AActor*> OverlappingActors;
ExplosionCollision->GetOverlappingActors(OverlappingActors);
for (AActor* Actor : OverlappingActors)
{
if (Actor && Actor->ActorHasTag("Player"))
{
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, FString::Printf(TEXT("Player damaged %d by MineItem"), ExplosionDamage));
}
}
// 지뢰 제거
DestroyItem();
}
- ActivateItem
- GetWorld()->GetTimerManager().SetTimer를 사용해 5초 후 Explode()가 자동 실행되도록 지연 호출 (Delayed Call)합니다.
- Explode()
- 폭발이 일어날 때 주변 액터를 검사해, 지뢰 범위(ExplosionRadius) 안에 있고 지뢰 콜리전 컴포넌트와 여전히 Overlap 상태인 플레이어에게 데미지를 주는 예시입니다.
- 폭발 처리 후 DestroyItem()을 호출해 지뢰 아이템 자체를 제거합니다.
아이템 배치 및 충돌 체크하기
1️⃣ 콜리전 비주얼 디버깅
- 언리얼 에디터에서 Alt + C (기본 단축키)로 콜리전 디버그 모드를 켜면, Capsule Component뿐 아니라 Sphere, Box 같은 다른 콜리전 영역도 시각적으로 확인할 수 있습니다.
- 콜리전이 비정상적으로 설정되어 있을 경우, 이 기능을 통해 빠르게 확인해 보세요.
UE Collistion 관련 더 괜찮은 방식
현재는 ActorHasTag로 되어있어서, 중간에 Tag 변경, 오타, BP 에 잘못입력 등 실수하거나 확장성에 있어서 안좋기 때문에 추후에는 아래의 방식이 더 선호됩니다.
void ABaseItem::OnItemOverlap(
UPrimitiveComponent* OverlappedComp,
AActor* OtherActor,
UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex,
bool bFromSweep,
const FHitResult& SweepResult)
{
/*
추가 팁: 인터페이스(Interface) 활용하기만약 플레이어뿐만 아니라 '데미지를 입을 수 있는 모든 대상'을 판별하고 싶다면,
Cast 대신 언리얼 인터페이스(UInterface)를 사용해 OtherActor->Implements<UMyDamageInterface>() 형태로 판별하는 것이 아키텍처 관점에서 훨씬 깔끔합니다.
// 싱글 플레이어 게임이거나 0번 로컬 플레이어를 판별할 때 가장 간단하고 직관적인 방법입니다. 충돌한 액터가 현재 월드의 플레이어 폰과 같은지 메모리 주소를 직접 비교합니다.
// 단점: 멀티플레이어 환경(다른 클라이언트의 플레이어 캐릭터)에서는 작동하지 않을 수 있습니다.
if (OtherActor && OtherActor == GetWorld()->GetFirstPlayerController()->GetPawn())
{
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Blue, FString::Printf(TEXT("플레이어가 충돌했습니다!!!")));
}
// 멀티플레이어 환경에서 적 플레이어, 아군 플레이어 구분 없이 '유저가 잡고 있는 캐릭터'를 모두 판별해 냅니다.
// AI 캐릭터(IsBotControlled)는 자동으로 걸러집니다.
// #include "GameFramework/Pawn.h" // 다른 곳에서 선언된거랑 가능한한 여기서도 선언해두자
if (OtherActor)
{
// 우선 APawn으로 캐스팅 (모든 캐릭터는 폰의 일종입니다)
APawn* TouchedPawn = Cast<APawn>(OtherActor);
// 폰이 맞고, 현재 플레이어 컨트롤러가 빙의(Possess)한 상태인지 확인
if (TouchedPawn && TouchedPawn->IsPlayerControlled())
{
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Red, FString::Printf(TEXT("플레이어가 조종 중인 액터입니다!!!")));
}
}
// 플레이어와 AI를 동시에 분기 처리하기
// 하나의 충돌 함수 안에서 플레이어와 AI를 나누어 각각 다른 로직
// (예: 플레이어면 UI 연출, AI면 데미지만 처리)을 실행하고 싶다면 다음과 같이 작성합니다.
if (OtherActor)
{
APawn* TouchedPawn = Cast<APawn>(OtherActor);
if (TouchedPawn)
{
if (TouchedPawn->IsPlayerControlled())
{
// 실제 플레이어 전용 로직
UE_LOG(LogTemp, Log, TEXT("플레이어 충돌"));
}
else if (TouchedPawn->IsBotControlled())
{
// AI 봇 전용 로직
UE_LOG(LogTemp, Log, TEXT("AI 캐릭터 충돌"));
}
}
}
*/
// OtherActor가 플레이어인지 확인 ("Player" 태그 활용)
if (OtherActor && OtherActor->ActorHasTag("Player"))
{
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, FString::Printf(TEXT("Overlap!!!")));
// 아이템 사용 (획득) 로직 호출
ActivateItem(OtherActor);
}
}
Conclustion
추천
[Unreal Engine/UE 기초] - 인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]
인터페이스 기반 아이템 클래스 설계하기 | [언리얼 엔진 C++ (Unreal Engine C++)]
인터페이스 기반 아이템 클래스 설계하기 인터페이스 이해하기1️⃣ 인터페이스란?인터페이스 (Interface)란 클래스 (또는 오브젝트)가 반드시 구현해야 할 함수 목록만을 미리 정의해 두고, 실제
devcol.tistory.com
콜리전 관련 UE 공식문서: https://dev.epicgames.com/documentation/unreal-engine/collision-response-reference-in-unreal-engine?lang=ko
Collision Response Reference in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community
Reference guide to the Collision Presets section in Unreal Engine.
dev.epicgames.com
AddDynamic 함수 관련 UE 공식문서: https://dev.epicgames.com/documentation/unreal-engine/dynamic-delegates-in-unreal-engine?lang=ko
Dynamic Delegates in Unreal Engine | Unreal Engine 5.7 Documentation | Epic Developer Community
Delegates that can be serialized and support reflection.
dev.epicgames.com
[페이지] Unreal Engine | 언리얼 엔진