1. 오늘의 개발 개요
공간 인벤토리 시스템의 세 번째 파트입니다. 이전 파트에서 인벤토리 그리드 UI의 시각적 요소를 완성한 데 이어, 이번에는 게임 월드에 실제로 존재하는 아이템 클래스를 구현하고 캐릭터와의 충돌(Overlap) 감지 로직을 연결했습니다.

*식자는 프로젝트 이름을 설정할 때 오타를 내서 IntentorySystemCpp로 만들어버렸지만 나중에 알아버려서 이는 굳이 수정하지 않겠습니다.
2. 프로젝트 파일 구조
3. AItemBase — 아이템 부모 클래스
// ItemBase.h
UCLASS()
class INTENTORYSYSTEMCPP_API AItemBase : public AActor
{
GENERATED_BODY()
public:
AItemBase();
UPROPERTY(EditAnywhere)
UStaticMeshComponent* Mesh;
UPROPERTY(EditAnywhere)
USphereComponent* Sphere;
protected:
virtual void BeginPlay() override;
};
// ItemBase.cpp
AItemBase::AItemBase()
{
PrimaryActorTick.bCanEverTick = true;
Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
Sphere = CreateDefaultSubobject<USphereComponent>(TEXT("Sphere"));
Mesh->SetupAttachment(RootComponent); // Mesh를 루트에 부착
Sphere->SetupAttachment(Mesh); // Sphere는 Mesh에 부착
Mesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
// Mesh 자체 충돌은 OFF → Sphere로만 Overlap 처리
}
- CreateDefaultSubobject는 생성자(Constructor)에서만 호출 가능. 엔진이 클래스를 로드할 때 초기화되기 때문.
- BeginPlay는 게임이 실제로 시작될 때 호출되므로, 이 시점엔 서브오브젝트 생성 불가.
- 컴포넌트 부착(SetupAttachment), 콜리전 설정 등 구조적 초기화는 모두 생성자에서 처리해야 함.
4. 아이템 파생 클래스 (AK47 / Knife / Grenade)
각 아이템은 AItemBase를 상속한 독립적인 C++ 클래스로 정의합니다. 현재 단계에서는 클래스 계층 구조를 확립하는 것이 목적이므로, 고유 로직은 향후 추가될 예정입니다. 이 C++ 클래스를 기반으로 에디터에서 Blueprint 자식 클래스를 만들어 메시(Mesh)와 콜리전 크기를 아이템별로 설정합니다.
// IB_AK47.h
// IB_Knife.h / IB_Grenade.h (동일 구조)
UCLASS()
class INTENTORYSYSTEMCPP_API AIB_AK47 : public AItemBase
{
GENERATED_BODY()
};
- C++로 클래스 계층 구조(공통 로직)를 정의하고, Blueprint에서 에셋(메시, 사운드 등) 을 지정하는 패턴
- Blueprint 폴더를 별도로 만들어 BP_AK47, BP_Knife, BP_Grenade를 각각 생성
- 에디터에서 드래그&드롭으로 레벨에 배치 가능 → 빠른 레벨 디자인 이터레이션
5. OnBeginOverlap — 아이템 획득 감지
// IntentorySystemCppCharacter.h — UFUNCTION 선언
UFUNCTION()
void OnBeginOverlap(
class UPrimitiveComponent* HitComp,
class AActor* OtherActor,
class UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex,
bool bFromSweep,
const FHitResult& SweepResult
);
// IntentorySystemCppCharacter.cpp — 생성자에서 바인딩
// 생성자에서 CapsuleComponent에 Overlap 이벤트 연결
GetCapsuleComponent()->OnComponentBeginOverlap.AddDynamic(
this,
&AIntentorySystemCppCharacter::OnBeginOverlap
);
// IntentorySystemCppCharacter.cpp OnBeginOverlap 구현
void AIntentorySystemCppCharacter::OnBeginOverlap(
UPrimitiveComponent* HitComp,
AActor* OtherActor,
UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex,
bool bFromSweep,
const FHitResult& SweepResult)
{
AItemBase* Item = Cast<AItemBase>(OtherActor);
if (Item)
{
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red,
TEXT("Item is picked up"));
// 다음 파트: Item을 인벤토리 배열에 추가하는 로직 연결 예정
}
}
- UFUNCTION() 매크로가 없으면 AddDynamic 바인딩이 불가 → 반드시 선언 필요
- Cast<AItemBase>(OtherActor)가 성공하면 파생 클래스(AK47, Knife, Grenade) 모두 감지 가능 → 상속의 힘
- SphereComponent를 Mesh에 부착했으므로 감지 범위는 메시 주변의 구체 영역
6. 개발 중 직면한 문제 & 해결
① 물리 시뮬레이션 시 아이템이 바닥을 뚫고 떨어지는 문제
문제: Mesh에 Physics Simulation을 활성화했을 때, Mesh 자체 콜리전이 없어 다른 오브젝트를 통과하여 자유 낙하.
해결: Mesh->SetCollisionEnabled(ECollisionEnabled::NoCollision)로 Mesh 충돌을 OFF하고, 충돌 감지는 SphereComponent에만 위임. 물리 시뮬레이션은 Mesh가 아닌 SphereComponent에 적용하거나, 바닥 배치 아이템은 시뮬레이션을 비활성화.
② OnBeginOverlap이 호출되지 않는 문제
문제: UFUNCTION() 매크로 없이 AddDynamic으로 바인딩 시도 → 컴파일 에러 또는 무반응.
해결: 헤더에 UFUNCTION() 매크로를 반드시 선언. UE 리플렉션 시스템이 이 매크로를 통해 함수를 동적으로 등록하기 때문에 없으면 바인딩 자체가 불가능.
- UE5의 컴포넌트는 생성자에서만 CreateDefaultSubobject로 생성 — BeginPlay와 혼동 금지
- Overlap 이벤트 함수는 반드시 UFUNCTION() 매크로와 함께 선언해야 AddDynamic 바인딩 가능
- Cast<AItemBase> 한 줄로 모든 아이템 파생 클래스를 공통 처리 — C++ 다형성 + UE Cast의 조합
- Mesh 충돌 OFF + SphereComponent만 활성화 = 물리 간섭 없이 수집 감지만 정확하게
핵심 교훈
"UE5에서 아이템 클래스를 설계할 때는 C++로 계층 구조와 공통 로직을 잡고, Blueprint에서 에셋과 수치를 지정하는 역할 분리가 핵심이다. 특히 충돌 감지는 Mesh와 SphereComponent의 역할을 명확히 나눠야 물리 시뮬레이션과 Overlap이 서로 간섭하지 않는다."
'Unreal' 카테고리의 다른 글
| C++을 사용한 언리얼엔진 인벤토리 시스템 Part.5 (0) | 2026.03.18 |
|---|---|
| C++을 사용한 언리얼엔진 인벤토리 시스템 Part.4 (0) | 2026.03.13 |
| C++을 사용한 언리얼엔진 인벤토리 시스템 Part.2 (0) | 2026.03.10 |
| C++을 사용한 언리얼엔진 인벤토리 시스템 Part.1 (0) | 2026.03.09 |
| Unreal_8기_인벤토리 만들기(3) (0) | 2026.03.06 |