Unreal Engine - 아이템 만들기 (+충돌 처리)

2025. 2. 6. 18:13·Unreal Engine

1. 목표


게임상에서 캐릭터와 아이템 간의 충돌이 발생하면 특정 이벤트가 발생하도록 구현해야 한다.

구현해야 할 것은 아래와 같다.

  • 아이템 클래스와 그것을 상속받은 여러 자식 아이템 클래스들
  • 아이템 (actor)와 캐릭터의 충돌 감지

전체적인 구조

  • 인터페이스 클래스
    • base item 클래스
      • coin item 클래스
        • big coin item 클래스
        • small coin item 클래스
      • healing item 클래스
      • mine item 클래스

 

 

2. 아이템 클래스 만들기


2 - 1. 인터페이스 클래스 만들기

우리가 C++에서 순수 가상 함수를 가지는 추상 클래스를 만들었던 것처럼 언리얼 엔진에서도 인터페이스를 만들어 계층 구조를 구현할 수 있다.

  • 인터페이스 클래스
    • 반드시 구현해야할 함수 목록만을 미리 정의해두고, 실제 함수의 동작은 상속받는 클래스에서 구현하는 것
    • 언리얼 C++에서는 UInterface를 상속받아서 구현하게 된다. (아래 사진의 언리얼 인터페이스)

  • 인터페이스와 상속의 차이점
    • 상속
      • 부모 클래스의 모든 속성과 기능을 자식 클래스가 물려받는 것
      • 부모 클래스의 로직을 자식이 사용할 수도 있고, 오버라이딩해서 재정의 할 수도 있다.
    • 인터페이스
      • 인터페이스에는 반드시 만들어야 하는 함수의 원형들만 정의되어 있다.
      • 해당 함수들의 동작은 자식 클래스에서 작성해야 한다.
    • 즉, 상속은 부모의 구현을 가져다 쓰는 것이고 인터페이스는 함수의 틀만 자식이 가져와서 구현하는 것이다.

 

2 - 2. 언리얼 C++ 인터페이스 코드

  • UInterface를 상속받아서 클래스를 만들면, 아래와 같은 구조를 가지게 된다.
    • UINTERFACE가 붙어있는 UItemInterface 클래스
      • 리플렉션을 위해 자동으로 만들어진 부분
      • 언리얼 내부의 동작을 한다.
    • IItemInterface 클래스
      • 실제 우리가 코드를 작성해야 하는 부분
      • 순수 가상 함수를 이 부분에 작성하면 된다.
  • 인터페이스 클래스라서 cpp 파일, 즉 구현부는 필요가 없지만 언리얼 내부 동작에 문제가 생길수도있으니 빈 cpp파일 그대로 두는 것이 좋다.
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "ItemInterface.generated.h"

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

class SCC_PROJECT_API IItemInterface
{
	GENERATED_BODY()
    
public:
}
  • 모든 아이템들이 해야하는 동작을 순수가상함수 형태로 구현한 모습
    • OnItemOverlap 함수와 OnItemEndOverlap 함수는 아래에서 추가로 설명할 예정
      • 이때 이 함수들을 UFUNCTION 매크로를 통해 리플렉션에 등록해 주어야한다.
      • 위 함수들을 추후에 AddDynamic을 통해 런타임 바인딩 해줄 것이기 때문
      • 만약 인터페이스 클래스에서 등록해준 경우 상속받은 자식 클래스에서는 자동으로 등록된다. (자식 클래스에서는 UFUNCTION 안써도 괜찮다)
    • 참고) type을 return 하는 함수에서 return 값을 FName으로 한 이유는 FName이 FString보다 빠르기 때문이다.
class SCC_PROJECT_API IItemInterface
{
	GENERATED_BODY()
    
public:
	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;
};

 

2 - 3. 인터페이스 클래스를 상속 받은 최상위 부모 클래스

  • 구현 내용
    • 인터페이스 클래스를 include 한 후, 상속을 해주어야 한다.
    • 인터페이스 클래스의 모든 순수 가상 함수를 구현해주어야 한다.
    • 추가적으로 모든 아이템 클래스에 필요한 컴포넌트를 추가해 주면 된다.
//BaseItem.h

#pragma once

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

class USphereComponent;

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

protected:
	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();

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "item")
	FName ItemType;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Item|Component")
	TObjectPtr<USceneComponent> SceneComp;
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Item|Component")
	TObjectPtr<USphereComponent> CollisionComp;
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Item|Component")
	TObjectPtr<UStaticMeshComponent> StaticMeshComp;
};

 

2 - 4. 최상위 부모 클래스를 상속받은 자식 클래스들

  • 맨 위에서 언급한 구조대로 클래스들을 추가해 주었다.
  • 생각할 점
    • 인터페이스 클래스가 아니라 BaseItem 클래스(최상위 부모 클래스) 를 상속하면 된다.
    • 부모 클래스의 함수 중, 필요한 함수를 재정의 혹은 사용하면 된다.
  • Coin 클래스 코드 예시
    • BaseItem을 상속하였고,
    • ActivateItem 함수를 override 하였다.
//CoinItem.h

#pragma once

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

UCLASS()
class SCC_PROJECT_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()
	:PointValue(0)
{	
	ItemType = "Default Coin";
}

void ACoinItem::ActivateItem(AActor* Activator)
{
	if (Activator && Activator->ActorHasTag("Player"))
	{
		GEngine->AddOnScreenDebugMessage(-1, 1.f, FColor::Yellow, FString::Printf(TEXT("Player gain coins: %d"), PointValue));
		DestroyItem();
	}
}
  • SmallCoinItem 클래스 코드 예시
    • CoinItem 클래스를 상속하였고,
    • CoinItem 클래스의 ActivateItem을 오버라이드하고, Super를 통해 부모의 함수를 call했다.
//SmallCoinItem.cpp

#include "SmallCoinItem.h"

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

void ASmallCoinItem::ActivateItem(AActor* Activator)
{
	Super::ActivateItem(Activator);
}

 

 

3. 충돌 처리


3 - 1. Collision

  • 언리얼 엔진에서 Static Mesh를 더블클릭해서 들어간 후, 단순 콜리전을 표시하면 아래 사진처럼 Mesh 자체적으로 가지고 있는 콜리젼을 볼 수 있다.

  • 그러나 우리가 게임을 구현할 때 충돌 처리를 위해서는 Static Mesh를 감싸는 추가적인 Collision을 만들어 주는 것 이 좋다. (아래 사진 참고)

  • Collision에는 크게 두가지 방식이 있다.
    • 오버랩
      • 물리적으로 부딪히는 것 없이 액터들이 서로 겹치는지를 체크하는 것
      • 아이템 획득, 트리거 존 감지 등에 사용할 수 있다.
    • 히트
      • 실제 물리 충돌이 일어날 때 발생하는 것 (막히고, 충돌하는 등)
      • 총알이 벽에 부딪히는 경우 등에 사용할 수 있다.

 

3 - 2. Collision Preset

위에서 언급한 오버랩과 히트를 위해 어떤 것을 오버랩하고 어떤 것을 히트할지 정하는 것이 Collision Preset이다.

  • 주요 Collision Preset
    • NoCollision
      • 충돌 감지x
      • overlap과 hit 모두 발생하지 않음
      • 단순 장식용 오브젝트(구름)에 사용
    • BlockAll
      • 모든 객체와 충돌
      • overlap 이벤트는 발생하지 않음
      • 벽이나 바닥 등
    • OverlapAll
      • 모든 객체와 Overlap 이벤트 발생
      • 트리거 존, 감지 센서, 투명 오브젝트에 사용
    • BlockAllDynamic
      • 움직이는 객체만 충돌
      • 플레이어와 물리 오브젝트간의 상호작용
      • 아이템과 아이템의 충돌을 막아서, 성능을 향상
    • OverlapAllDynamic (우리가 구현할 아이템 클래스)
      • 움직이는 객체와 Overlap 발생
      • 플레이어가 근처에 있는지 확인하는 아이템, 센서 등
      • 충돌을 하지 않는 Overlap 발생시킬 때
    • Pawn
      • 플레이어나 AI와 같은 Pawn 을 상속받은 대상들의 충돌 감지
    • Custom
      • 개발자가 직접 만들 수 있다.

 

3 - 3. Collision Enabled

충돌이 켜져 있다면, 물리적인 처리를 하는지 하지 않는지를 체크하는 부분이다.

  • No Collision : 충돌 비활성화
  • Query Only : Overlap, Hit등 충돌 이벤트는 감지하지만, 물리적 처리는 안함
  • Physics Only : 물리처리만 진행하고, Overlap, Hit 이벤트는 발생안함
  • Query and Physics : 충돌 이벤트 + 물리 처리 둘 다 진행

 

3 - 4. C++로 콜리전 프리셋 설정

  • SetCollisionProfileName 함수로 설정
  • 캐릭터는 기본적으로 "Pawn" 으로 설정되어 있다.
//BaseItem.cpp

ABaseItem::ABaseItem()
{
	...
	CollisionComp->SetCollisionProfileName(TEXT("OverlapAllDynamic"));
	...
}

 

3 - 5. OnComponentBeginOverlap & OnComponentEndOverlap

이 함수들을 통해서 overlap 체크를 할 수 있다. 이벤트 바인딩을 통해 런타임에 바인딩을 하도록 한다.

  • 이벤트 바인딩
    • OnComponentBeginOverlap 이 함수를 통해 받아온 정보를 토대로 우리가 원하는 함수를 실행해 주는 것이다.
    • 주의할 점은 함수 시그니처를 잘 맞춰야 한다는 점이다.
  • 함수 시그니처
    • 각각 BeginOverlap과 EndOverlap에 바인딩 할 수 있는 함수의 시그니처 모습이다.
    • 매개변수 설명
      • OverlappedComp : 오버랩이 발생한 자기 자신의 컴포넌트
      • OtherActor : 오버랩이 발생한(충돌한) 다른 Actor (예를 들어 플레이어)
      • OtherComp : 충돌한 다른 Actor의 충돌 감지된 컴포넌트 (예를 들어 플레이어의 캡슐 컴포넌트)
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;
    
 
 //BaseItem.cpp
 ABaseItem::ABaseItem()
 {
 	...
    //이벤트 바인딩
    CollisionComp->OnComponentBeginOverlap.AddDynamic(this, &ABaseItem::OnItemOverlap);
    CollisionComp->OnComponentEndOverlap.AddDynamic(this, &ABaseItem::OnItemEndOverlap);
 }

 

3 - 6. 태그 시스템을 이용한 충돌 체크

언리얼 엔진에서도 Tag 시스템을 통해 충돌한 Actor의 Tag를 체크할 수 있다.

  • 플레이어 캐릭터를 선택 후 Actor 검색 후 아래에 "태그" 에서 원하는 이름으로 태그를 추가

  • C++에서는 아래와 같이 지정해 줄 수 있다.
//Player Character

APlayerCharacter::APlayerCharacter()
{
	...
	Tags.Add("Player");
    ...
}
  • C++에서 사용
    • ActorHasTag 함수를 통해 Tag를 검사할 수 있다.
//BaseItem.cpp 

void ABaseItem::OnItemOverlap(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	if (OtherActor && OtherActor->ActorHasTag("Player"))
	{
		ActivateItem(OtherActor);
	}
}

 

3 - 7. 추가 기억할 만한 구현들

  • GetOverlappingActors
    • 충돌된 액터들을 모두 가져와서 TArray 안에 넣어주는 함수
void AMineItem::Explode()
{
	TArray<AActor*> OverlappingActors;
	ExplosionCollisionComp->GetOverlappingActors(OverlappingActors);

	for (AActor* Actor : OverlappingActors)
	{
		if (Actor && Actor->ActorHasTag("Player"))
		{
			//폭발 시 처리
		}
	}
	DestroyItem();
}
  • 타이머
    • ExplosionDelay 뒤에 Explode 함수를 발동시킨다.
    • 마지막 파라메터를 false로 해서 반복을 안하도록 만들었다.
void AMineItem::ActivateItem(AActor* Activator)
{
	//타이머 핸들러
	GetWorld()->GetTimerManager().SetTimer(
		ExplosionTimerHandle
		, this
		, &AMineItem::Explode
		, ExplosionDelay
		, false //반복 안함
	);
}

 

'Unreal Engine' 카테고리의 다른 글

Unreal Engine - Game Loop  (0) 2025.02.09
Unreal Engine - 아이템 스폰 및 캐릭터와 연동  (0) 2025.02.07
Unreal Engine - Simple Niagara (with cpp)  (0) 2025.02.04
Unreal Engine - Data Table  (0) 2025.02.03
UE5 Issues : C++ 충돌 처리  (1) 2025.01.27
'Unreal Engine' 카테고리의 다른 글
  • Unreal Engine - Game Loop
  • Unreal Engine - 아이템 스폰 및 캐릭터와 연동
  • Unreal Engine - Simple Niagara (with cpp)
  • Unreal Engine - Data Table
gbleem
gbleem
gbleem 님의 블로그 입니다.
  • gbleem
    gbleem 님의 블로그
    gbleem
  • 전체
    오늘
    어제
    • 분류 전체보기 (176)
      • Unreal Engine (66)
      • C++ (19)
      • 알고리즘(코딩테스트) (26)
      • TIL (60)
      • CS (4)
      • 툴 (1)
  • 블로그 메뉴

    • 홈
    • 카테고리
  • 링크

    • 과제용 깃허브
    • 깃허브
    • velog
  • 공지사항

  • 인기 글

  • 태그

    gamestate
    템플릿
    C++
    상속
    const
    actor 클래스
    addonscreendebugmessage
    additive animation
    motion matching
    DP
    싱글턴
    매크로 지정자
    cin함수
    enhanced input system
    character animation
    BFS
    applydamage
    Vector
    map을 vector로 복사
    blend pose
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
gbleem
Unreal Engine - 아이템 만들기 (+충돌 처리)
상단으로

티스토리툴바