충돌 채널과 프로파일 설정
이전 장에서 우리는 언리얼 엔진의 월드와 씬을 구성하는 요소들, 그리고 C++와 블루프린트 간의 효율적인 협업 방식에 대해 알아보았습니다. 이제 게임플레이에서 가장 중요하고 빈번하게 발생하는 상호작용 중 하나인 충돌(Collision) 에 대해 깊이 있게 다룰 시간입니다. 액터들이 서로 부딪히거나 겹쳤을 때 어떤 일이 발생할지 정의하는 것은 게임의 물리적 상호작용과 게임플레이 로직의 핵심입니다. 이를 위해 언리얼 엔진은 강력한 충돌 채널(Collision Channel) 과 충돌 프로파일(Collision Profile) 시스템을 제공합니다.
충돌(Collision)이란 무엇인가요?
3D 게임에서 충돌은 두 개 이상의 오브젝트(액터 또는 컴포넌트)가 서로의 공간을 침범했을 때 발생하는 물리적인 접촉 또는 겹침 현상을 감지하는 것을 의미합니다. 언리얼 엔진은 이 충돌을 감지하고, 그 결과에 따라 다양한 반응을 일으킬 수 있도록 설계되어 있습니다.
충돌은 크게 두 가지 유형으로 나눌 수 있습니다.
- 블록(Block): 두 오브젝트가 서로의 통과를 완전히 막는 물리적인 충돌입니다. (예: 캐릭터가 벽에 부딪히는 것)
- 오버랩(Overlap): 두 오브젝트가 서로의 공간을 침범했지만, 물리적으로 막지는 않고 겹쳤다는 사실만 감지하는 것입니다. (예: 플레이어가 아이템을 줍기 위해 아이템 위에 서는 것)
충돌 채널 (Collision Channel)
언리얼 엔진은 게임 내의 다양한 오브젝트들을 충돌 채널이라는 논리적인 그룹으로 분류합니다. 각 채널은 특정 유형의 오브젝트를 나타내며, 이 채널들을 사용하여 어떤 오브젝트가 다른 어떤 오브젝트와 충돌할지, 그리고 어떻게 반응할지 정의할 수 있습니다.
기본적으로 언리얼 엔진은 다음과 같은 내장 충돌 채널을 제공합니다.
WorldStatic
: 움직이지 않는 월드 지오메트리 (벽, 바닥, 천장 등)WorldDynamic
: 움직이는 월드 오브젝트 (문, 엘리베이터 등)Pawn
: 플레이어 캐릭터나 AI 폰PhysicsBody
: 물리 시뮬레이션되는 오브젝트 (부서지는 상자 등)Vehicle
: 차량CharacterMesh
: 캐릭터의 스켈레탈 메시
커스텀 충돌 채널 생성
게임에 필요한 특정 유형의 오브젝트가 있다면, 직접 커스텀 충돌 채널을 생성할 수 있습니다. 예를 들어, "총알", "폭발 범위", "상호작용 오브젝트"와 같은 채널을 만들 수 있습니다.
생성 방법
언리얼 에디터 메뉴에서 Edit
> Project Settings
를 엽니다.
왼쪽 패널에서 Engine
> Collision
을 선택합니다.
New Collision Channel
버튼을 클릭합니다.
새로운 채널의 이름(예: Bullet
, ExplosionArea
)을 입력하고, 기본 반응(Default Response)을 Ignore
, Overlap
, Block
중 하나로 설정합니다.
Ignore
: 기본적으로 이 채널의 모든 오브젝트를 무시합니다.Overlap
: 기본적으로 이 채널의 모든 오브젝트와 오버랩을 감지합니다.Block
: 기본적으로 이 채널의 모든 오브젝트를 블록합니다.
Accept
를 클릭하여 채널을 생성합니다.
이렇게 생성된 커스텀 채널은 이제 게임의 모든 충돌 설정에서 사용할 수 있습니다.
충돌 프로파일 (Collision Profile)
충돌 프로파일은 특정 오브젝트가 다른 충돌 채널의 오브젝트들과 어떻게 상호작용할지(즉, Ignore
, Overlap
, Block
중 어떤 반응을 보일지)를 정의하는 사전 설정된 규칙들의 집합입니다. 충돌 프로파일을 사용하면 각 컴포넌트마다 일일이 충돌 반응을 설정하는 대신, 미리 정의된 프로파일을 적용하여 일관성과 효율성을 높일 수 있습니다.
충돌 프로파일 설정 방법
Project Settings
> Collision
섹션에서 Collision Presets
를 찾습니다.
언리얼 엔진은 BlockAll
, OverlapAll
, Pawn
, PhysicsActor
등 여러 기본 프로파일을 제공합니다.
New Preset
버튼을 클릭하여 새로운 충돌 프로파일을 생성할 수 있습니다.
새 프로파일의 이름(예: PlayerWeapon
, EnemyHitBox
)을 지정하고, Type
을 Block
또는 Overlap
으로 설정합니다.
가장 중요한 부분은 Collision Responses
섹션입니다. 여기서는 방금 만든 프로파일이 각 충돌 채널에 대해 어떤 반응을 보일지 설정합니다.
- 예를 들어,
PlayerWeapon
프로파일을 만들었다면Pawn
채널에 대해서는Ignore
(자신과 충돌하지 않음)WorldStatic
채널에 대해서는Block
(벽에 막힘)EnemyHitBox
채널에 대해서는Overlap
(적의 히트박스와 겹칠 때 데미지 처리)Bullet
채널에 대해서는Ignore
(총알은 총에 맞지 않음)- 등등, 게임의 논리에 맞게 각 채널에 대한 반응을 설정합니다.
액터/컴포넌트에 충돌 프로파일 적용
액터나 컴포넌트가 충돌을 감지하려면, 먼저 해당 액터/컴포넌트에 충돌 컴포넌트(Collision Component) 가 부착되어 있어야 합니다. (예: UCapsuleComponent
, UBoxComponent
, USphereComponent
, UStaticMeshComponent
, USkeletalMeshComponent
).
C++에서 적용
C++ 코드에서 충돌 컴포넌트를 생성하고 설정할 때, SetCollisionProfileName()
함수를 사용하여 미리 정의된 충돌 프로파일을 적용할 수 있습니다.
#include "Components/CapsuleComponent.h" // UCapsuleComponent를 위해
AMyCharacter::AMyCharacter()
{
// ACharacter의 기본 루트 컴포넌트는 UCapsuleComponent입니다.
UCapsuleComponent* CapsuleComp = GetCapsuleComponent();
if (CapsuleComp)
{
// "Pawn" 충돌 프로파일 적용
// 이 프로파일은 Project Settings -> Collision Preset에서 정의되어야 합니다.
CapsuleComp->SetCollisionProfileName(TEXT("Pawn"));
// 또는 직접 충돌 반응 설정 (프로파일 적용 대신)
// CapsuleComp->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics); // 쿼리 및 물리 충돌 활성화
// CapsuleComp->SetCollisionObjectType(ECollisionChannel::ECC_Pawn); // 이 컴포넌트의 오브젝트 타입 설정
// 특정 채널에 대한 반응 설정 (예: Bullet 채널은 Block)
// CapsuleComp->SetCollisionResponseToChannel(ECollisionChannel::ECC_GameTraceChannel1, ECollisionResponse::ECR_Block);
// ECC_GameTraceChannel1은 Project Settings에서 정의한 커스텀 채널 (예: Bullet)
}
// 캐릭터의 메시 컴포넌트 (USkeletalMeshComponent)
USkeletalMeshComponent* MeshComp = GetMesh();
if (MeshComp)
{
// "CharacterMesh" 충돌 프로파일 적용
MeshComp->SetCollisionProfileName(TEXT("CharacterMesh"));
// MeshComp->SetCollisionEnabled(ECollisionEnabled::QueryOnly); // 쿼리만 감지 (물리적 블록은 안 함)
}
}
SetCollisionProfileName(TEXT("ProfileName"))
: 가장 권장되는 방법입니다.Project Settings
에서 정의한 충돌 프로파일을 적용합니다.SetCollisionEnabled()
: 충돌 감지 자체를 활성화/비활성화합니다.NoCollision
: 충돌 없음.QueryOnly
: 오버랩/히트 감지(쿼리)만 가능, 물리적 블록은 안 함.PhysicsOnly
: 물리적 블록만 가능, 오버랩/히트 쿼리는 안 함.QueryAndPhysics
: 오버랩/히트 쿼리 및 물리적 블록 모두 가능.
SetCollisionObjectType()
: 이 컴포넌트가 어떤 충돌 채널에 속하는지 정의합니다.SetCollisionResponseToChannel()
: 특정 채널에 대해 개별적인 반응을 설정할 때 사용합니다.
블루프린트에서 적용
블루프린트 클래스를 열고, 충돌 컴포넌트(예: CapsuleComponent
, Mesh
)를 선택한 후, 디테일 패널의 Collision
섹션에서 Collision Presets
드롭다운 메뉴를 통해 원하는 프로파일을 선택할 수 있습니다. 여기서 Custom
을 선택하면 각 채널에 대한 반응을 수동으로 조절할 수도 있습니다.
충돌 이벤트 감지 (Overlap / Hit Events)
충돌이 발생했을 때 이를 감지하고 특정 로직을 실행하려면, 충돌 컴포넌트에서 이벤트를 활성화하고 해당 이벤트에 함수를 바인딩해야 합니다.
C++에서 이벤트 바인딩
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyTriggerVolume.generated.h"
class UBoxComponent; // UBoxComponent를 미리 선언
UCLASS()
class MYPROJECT_API AMyTriggerVolume : public AActor
{
GENERATED_BODY()
public:
AMyTriggerVolume();
protected:
virtual void BeginPlay() override;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Collision")
UBoxComponent* TriggerBox; // 트리거 볼륨 컴포넌트
// 오버랩 시작 이벤트 함수
UFUNCTION()
void OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
// 오버랩 종료 이벤트 함수
UFUNCTION()
void OnOverlapEnd(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
};
#include "MyTriggerVolume.h"
#include "Components/BoxComponent.h" // UBoxComponent를 위해
AMyTriggerVolume::AMyTriggerVolume()
{
PrimaryActorTick.bCanEverTick = false;
TriggerBox = CreateDefaultSubobject<UBoxComponent>(TEXT("TriggerBox"));
RootComponent = TriggerBox; // 루트 컴포넌트로 설정
// 충돌 프로파일 설정 (예: "OverlapAllDynamic" 또는 커스텀 프로파일)
TriggerBox->SetCollisionProfileName(TEXT("OverlapAllDynamic"));
// 오버랩 이벤트 활성화
TriggerBox->SetGenerateOverlapEvents(true);
// BeginPlay에서 이벤트 바인딩
// TriggerBox->OnComponentBeginOverlap.AddDynamic(this, &AMyTriggerVolume::OnOverlapBegin);
// TriggerBox->OnComponentEndOverlap.AddDynamic(this, &AMyTriggerVolume::OnOverlapEnd);
}
void AMyTriggerVolume::BeginPlay()
{
Super::BeginPlay();
// 생성자에서 바인딩해도 되지만, BeginPlay에서 하는 것이 더 안전합니다.
// 컴포넌트가 완전히 초기화된 후 바인딩하는 것이 좋습니다.
TriggerBox->OnComponentBeginOverlap.AddDynamic(this, &AMyTriggerVolume::OnOverlapBegin);
TriggerBox->OnComponentEndOverlap.AddDynamic(this, &AMyTriggerVolume::OnOverlapEnd);
}
void AMyTriggerVolume::OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
// 자신과 겹친 액터가 플레이어인지 확인 (예시)
if (OtherActor && OtherActor != this && OtherActor->IsA(APawn::StaticClass()))
{
UE_LOG(LogTemp, Warning, TEXT("Player entered trigger volume!"));
// 여기에 게임플레이 로직 구현 (예: 아이템 획득, 문 열기 등)
}
}
void AMyTriggerVolume::OnOverlapEnd(UPrimitiveComponent* OverlappedComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
if (OtherActor && OtherActor != this && OtherActor->IsA(APawn::StaticClass()))
{
UE_LOG(LogTemp, Warning, TEXT("Player exited trigger volume!"));
}
}
SetGenerateOverlapEvents(true)
: 해당 컴포넌트가 오버랩 이벤트를 발생시키도록 설정합니다.OnComponentBeginOverlap
/OnComponentHit
: 언리얼 엔진의Delegate
시스템입니다.AddDynamic()
함수를 사용하여 특정 함수를 이 델리게이트에 바인딩함으로써 이벤트가 발생했을 때 해당 함수가 호출되도록 합니다. 바인딩할 함수는 반드시UFUNCTION()
으로 선언되어야 합니다.OnComponentHit
: 물리적인 블록 충돌이 발생했을 때 호출되는 델리게이트입니다.OnComponentBeginOverlap
과 유사한 방식으로 바인딩하여 사용합니다.
이제 언리얼 엔진의 충돌 채널과 프로파일 시스템을 이해하고, 이를 통해 액터 간의 충돌 상호작용을 어떻게 정의하고 감지하는지 파악하셨을 것입니다. 이 시스템은 게임의 물리적 상호작용을 구현하는 데 있어 매우 유연하고 강력한 기반을 제공합니다.