Skip to main content

[Unreal] 언리얼 충돌 처리 방법, 월드 트레이싱 함수




충돌체를 만들자! #

  • 충돌체는 다음과 같은 방법 중 하나로 만들 수 있다.
충돌체 제작 방법 설명
StaticMesh Asset StaticMesh 에셋에 콜리전 영역을 심는다.
StaticMesh 컴포넌트에서 비주얼과 충돌, 두 가지 기능을 설정할 수 있게 된다.
기본 도형(Primitive) 컴포넌트 구체, 박스, 캡슐의 기본 도형을 사용해서 충돌 영역을 지정하는 방법이다.
StaticMesh와 별도의 충돌 영역을 제작한다.
스켈레탈 메시를 움직일 때 주로 사용한다.
Physics Asset 특정 상황에서 캐릭터의 각 관절이 흐느적거리는 헝겊 인형(Rag Doll)효과를 구현할 때 사용한다.
캐릭터의 각 부위에 기본 도형으로 충돌 영역을 설정하고 이를 연결해 캐릭터의 물리를 설정한다.
스켈레탈 메시에서만 사용할 수 있다.



콜리전 채널을 만들자! #

  • 제작된 충돌체는 반드시 하나의 콜리전 채널을 설정해야 한다.
  • 콜리전 채널의 종류는 크게 두 가지로 나뉜다.
콜리전 채널 종류 설명
Object Channel 콜리전 영역에 지정하는 채널이다.
WorldStatic, WorldDynamic, Pawn, PhysicsBody, Vehicle, Destructible가 기본 제공된다.
Trace Channel 어떤 행동에 설정하는 채널이다.
Visibility, Camera가 기본 제공된다.



프로필을 만들자! #

  • 콜리전 채널 별로 여러가지 프로필(Preset)을 만들 수 있다.
  • 기본적으로 제공되는 프로필들은 다음과 같다.
기본 제공 Preset 종류 속한 채널 설명
OverlapAll WorldStatic 모든 액터와 겹친다.
OverlapAllDynamic WorldDynamic 모든 액터와 겹친다.
IgnoreOnlyPawn WorldDynamic Pawn과의 충돌만 무시한다.
OverlapOnlyPawn WorldDynamic Pawn에만 Overlap 이벤트가 발생한다.
Spectator Pawn 외부 관중과의 충돌을 설정한다.
CharacterMesh Pawn 캐릭터 메시에 사용한다.
RagDoll Physics Body 스켈레탈메시의 피직스 에셋 물리를 가동하기 위한 오브젝트에 사용한다.
보통 흐느적 거리는 랙돌 구현을 위해 사용된다.
Trigger WorldDynamic 지정한 영역에 물체가 들어오면 이벤트를 발생시킨다.
UI WorldDynamic UI요소에 사용한다.

  • 프로필을 만들 때는 아래와 같은 요소를 추가로 설정해주어야 한다.
  • 이제 충돌체에 프로필을 할당하면, 다른 충돌체와의 충돌 관계가 생긴다!

CollisionEnabled 설정 #

  • 콜리전에 켜질 항목을 설정한다.
설정값 이름 설명
Query Only 두 물체의 충돌 영역이 서로 겹치는지(Overlap) 체크한다.
겹치면 관련 컴포넌트에 BeginOverlap 이벤트가 발생한다. (Generates Overlap Events 옵션을 켜야한다)
레이캐스트(Raycast)나 스윕(Sweep) 기능도 여기에 속한다.
Physics 물리적인 시뮬레이션을 사용한다.
Query and Physics 위의 두 기능을 모두 사용한다.
계산량이 많아지겠다.

Collision Responses 설정 #

  • 다른 채널과의 상호작용을 설정한다.
설정값 이름 설명
무시(Ignore) 콜리전이 있어도 아무일도 일어나지 않는다.
겹침(Overlap) 무시와 동일하게 물체가 뚫고 지나가만, BeginOverlap 이벤트를 발생시킨다.
블록(Block) 물체가 뚫고 지나가지 못하며, Hit 이벤트를 발생시킨다.
Generates Overlap Events 옵션이 양쪽 다 켜져 있다면 BeginOverlap 이벤트도 발생시킨다.



[예시] 공격 판정을 위한 충돌체 설정 #

  • 공격 판정을 위한 트레이스 채널을 하나 만들어보자!
  • 이름은 ABAction 으로 하고, 기본 반응은 Ignore로 한다.

새로운 트레이스 채널 생성


  • 캐릭터의 캡슐 컴포넌트에 할당할 프로필도 만들어보자!
  • 이름은 ABCapsule 으로 하고, 속한 채널은 Pawn이다.
  • ABAction과의 반응은 Block이다.

새로운 프로필 생성



월드 트레이싱 함수로 충돌을 체크하자! #

  • 월드가 제공하는 충돌 판정 서비스이다.
  • 다음과 같은 세 가지 카테고리를 통해서 원하는 함수를 사용할 수 있다.
{처리방법}{대상}{처리설정}

처리방법 #

종류 설명
LineTrace 선을 쏜다.
Hit 이벤트이므로, 반응은 Block이어야 한다.
Sweep 도형을 쏜다.
Hit 이벤트이므로, 반응은 Block이어야 한다.
Overlap 범위를 설정한다.
Overlap 이벤트이며, ImpactPoint 같은 값을 얻어올 수는 없다.

대상 #

종류 설명
Test 무언가 감지되었는지 아닌지 여부를 테스트한다.
Single / AnyTest 감지된 단일 물체 정보를 반환한다.
Multi 감지된 모든 물체 정보를 배열로 반환한다.

처리설정 #

종류 설명
ByChannel 채널 정보를 사용해서 감지한다.
ByObjectType 물체에 지정된 물리 타입 정보를 사용해서 감지한다.
ByProfile 프로필 정보를 사용해서 감지한다.



[예시] SweepSingleByChannel 사용해서 공격 판정하기 #

  • Sweep → 구체를 특정 거리만큼 투사해서 감지할 것이다.
  • Single → 하나의 물체만 감지할 것이다.
  • ByChannel → 트레이스 채널을 사용할 것이다.

채널 값 가져오기 #

  • 이전 예시에서 만든 ABAction 채널의 값은 언리얼 엔진에서 정의한 ECollisionChannel 열거형에서 가져올 수 있다.
  • 언리얼 엔진은 총 32개의 콜리전 채널을 제공하는 데, 그 중에 8개는 언리얼 엔진이 기본으로 사용하고, 6개는 엔진에서 다른 용도로 사용하도록 예약되어 있다. 따라서 우리가 만드는 게임 프로젝트에서는 나머지 18개만 사용할 수 있다.
  • 우리가 만든 Attack 채널이 ECollisionChannel::ECC_GameTraceChannel1 ~ ECollisionChannel::ECC_GameTraceChannel18 중에 어떤 값을 배정받았는지 알아야 한다.
  • 프로젝트 Config 폴더의 DefaultEngine.ini에서 확인할 수 있다.

  • ABAction 채널의 값은 ECC_GameTraceChannel1 이다.
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Ignore,bTraceType=True,bStaticObject=False,Name="ABAction")

함수 사용하기 #

void AABCharacterBase::AttackHitCheck()
{
    // 충돌 결과가 담기는 구조체
    FHitResult OutHitResult;
    
    // 탐색 방법에 대한 설정 값을 모아둔 구조체
    FCollisionQueryParams Params(
        SCENE_QUERY_STAT(Attack), // 충돌을 분석할 때 구분할 식별자 정보 (태그)
        false,                    // 복잡한 형태의 충돌체도 감지할 것인가?
        this                      // 무시할 액터. 자기 자신을 무시하도록 한다.
    );

    const float AttackRange = 40.0f;
    const float AttackRadius = 50.0f;
    const float AttackDamage = 30.0f;

    // 정면에 있는 캡슐 끝지점에서 시작한다. 
    const FVector Start = GetActorLocation() + GetActorForwardVector() * GetCapsuleComponent()->GetScaledCapsuleRadius();
    // 40cm 앞에서 끝난다. 
    const FVector End = Start + GetActorForwardVector() * AttackRange;

    bool HitDetected = GetWorld()->SweepSingleByChannel(
        OutHitResult,          // 충돌 결과가 담긴다. 
        Start,                 // 투사 시작 지점
        End,                   // 투사 끝 지점
        FQuat::Identity,       // 구체의 회전 값
        ECC_GameTraceChannel1, // 우리가 만든 Trace Channel의 이름 
        FCollisionShape::MakeSphere(AttackRadius), // 탐색에 사용할 기본 도형(구체, 캡슐, 박스) 정보. 반지름이 50cm인 구체를 생성한다. 
        Params
    );

    if (true == HitDetected)
    {
        // TO DO 
    }
}



References #