[Unreal] 언리얼 충돌 처리 방법, 월드 트레이싱 함수
Table of Contents
충돌체를 만들자! #
- 충돌체는 다음과 같은 방법 중 하나로 만들 수 있다.
충돌체 제작 방법 | 설명 |
---|---|
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
}
}