icon
5장 : 충돌, 물리, 인터랙션

충돌 채널과 프로파일 설정


이전 장에서 우리는 언리얼 엔진의 월드와 씬을 구성하는 요소들, 그리고 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)을 지정하고, TypeBlock 또는 Overlap으로 설정합니다.

가장 중요한 부분은 Collision Responses 섹션입니다. 여기서는 방금 만든 프로파일이 각 충돌 채널에 대해 어떤 반응을 보일지 설정합니다.

  • 예를 들어, PlayerWeapon 프로파일을 만들었다면
    • Pawn 채널에 대해서는 Ignore (자신과 충돌하지 않음)
    • WorldStatic 채널에 대해서는 Block (벽에 막힘)
    • EnemyHitBox 채널에 대해서는 Overlap (적의 히트박스와 겹칠 때 데미지 처리)
    • Bullet 채널에 대해서는 Ignore (총알은 총에 맞지 않음)
    • 등등, 게임의 논리에 맞게 각 채널에 대한 반응을 설정합니다.

액터/컴포넌트에 충돌 프로파일 적용

액터나 컴포넌트가 충돌을 감지하려면, 먼저 해당 액터/컴포넌트에 충돌 컴포넌트(Collision Component) 가 부착되어 있어야 합니다. (예: UCapsuleComponent, UBoxComponent, USphereComponent, UStaticMeshComponent, USkeletalMeshComponent).

C++에서 적용

C++ 코드에서 충돌 컴포넌트를 생성하고 설정할 때, SetCollisionProfileName() 함수를 사용하여 미리 정의된 충돌 프로파일을 적용할 수 있습니다.

AMyCharacter.cpp (생성자)
#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++에서 이벤트 바인딩

AMyTriggerVolume.h
#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);
};
AMyTriggerVolume.cpp
#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과 유사한 방식으로 바인딩하여 사용합니다.

이제 언리얼 엔진의 충돌 채널과 프로파일 시스템을 이해하고, 이를 통해 액터 간의 충돌 상호작용을 어떻게 정의하고 감지하는지 파악하셨을 것입니다. 이 시스템은 게임의 물리적 상호작용을 구현하는 데 있어 매우 유연하고 강력한 기반을 제공합니다.