이전 시간에 오일러 방법으로 물체의 이동을 구현했었다. 이번 시간에서는 이전 시간에 이어서 Tick 내의 Physics pipeline 중 충돌 처리에 대해서 다뤄보자.
void APlayable::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
AddGravity();
Integration(DeltaTime);
HandleCollision(DeltaTime);
UpdatePosition(DeltaTime);
}
지난 게시글의 Tick 함수 내부에 보면 Integration과 UpdatePosition 사이에 HandleCollision 이라는 함수가 있는데 이 함수에서 물체의 충돌을 관리할 것이다.
이번 구현의 목표는 단순히 물체가 이동할때 콜라이더를 가진 객체를 관통(Penetrate)하지 못하게만 하는 것이 목표이고, 따로 Impulse는 다루지 않기 때문에 코드 자체는 간단하다.
Integration에서 업데이트 된 Velocity를 기반으로 다음위치로 예상되는 지점에 SweepMultiByChannel을 사용하여 현재 부착된 캡슐 콜라이더(기능은 사용하지 않음)와 동일한 크기의 캡슐 콜라이더를 생성해 충돌을 검출한다.
TArray<FHitResult> HitResults;
FCollisionQueryParams CollisionParams;
CollisionParams.AddIgnoredActor(this);
float Radius = CapsuleComponent->GetScaledCapsuleRadius();
float HalfHeight = CapsuleComponent->GetScaledCapsuleHalfHeight();
// 적분 과정에서 업데이트 된 속도로 다음 위치 예측
FVector NextPosition = GetActorLocation() + Velocity * DeltaTime;
// Sweep 수행
bool bHit = GetWorld()->SweepMultiByChannel(
HitResults,
NextPosition,
NextPosition,
GetActorQuat(),
ECollisionChannel::ECC_Visibility,
FCollisionShape::MakeCapsule(Radius, HalfHeight),
CollisionParams
);
이때 충돌이 검출되었으면 속도 벡터에서 충돌 표면의 수직 성분을 제거하여 표면에 평행한 성분만 남겨 다음 위치가 충돌한 물체에 관통되지 않도록 하고, 충돌 표면이 지면 방향과 어느정도 일치할경우 바닥에 있는 것으로 간주한다.
만약 충돌이 검출되지 않으면 공중에 떠있는 것으로 간주한다.
for (const FHitResult &HitResult : HitResults) {
FVector ImpactNormal = HitResult.ImpactNormal;
float DotProduct = FVector::DotProduct(Velocity, ImpactNormal);
if (DotProduct < 0)
{
// 속도를 충돌 표면에 평행한 방향으로 조정
Velocity -= DotProduct * ImpactNormal;
}
if (FMath::IsNearlyEqual(FVector::DotProduct(FVector(0, 0, -1), HitResult.ImpactNormal), -1.0f, 0.1f))
{
bIsGround = true;
if (Velocity.Z < 0)Velocity.Z = 0;
}
}
// 다음 위치에 아무것도 충돌하지 않으면 공중에 떠있는 것으로 간주
if (!bHit) {
bIsGround = false;
}
이런 TimeStep을 기반으로 이산적인 위치로만 충돌을 검출하는 방식은 구현이 쉽고 대부분의 상황에서는 안정적이지만, 물체의 속도가 매우 빠르거나 물체의 두께가 충분하지 않을시에는 터널링이 발생한다.
이러한 물체가 이동하는 연속적인 궤적까지 상정해서 충돌을 구현하는 것을 CCD(Continuous Collision Detection)이라고 하는데 여러가지 방법이 있지만 계산 비용도 크고 구현하기 어렵기 때문에 본 게시물에서는 다루지 않도록 하겠다.
혹시나 관심이 있는 사람은 아래 유니티에서 CCD에 대해 설명하는 링크를 참조하길 바란다.
연속 충돌 검사(CCD) - Unity 매뉴얼
CCD는 빠르게 움직이는 바디가 오브젝트를 지나치거나 통과하지 않고 충돌하도록 합니다. Unity는 다음의 CCD 메서드를 제공합니다.
docs.unity3d.com
'Unreal 5 > Study' 카테고리의 다른 글
1. [Unreal 5 / C++] 2D 절차적 맵 생성 알고리즘 (미로 생성 알고리즘) (0) | 2025.02.21 |
---|---|
[Unreal 5 / C++] 3. Pawn 클래스로 3D 캐릭터 만들기 - 이동 및 비행체 (0) | 2025.01.31 |
[Unreal 5 / C++] 1. Pawn 클래스로 3D 캐릭터 만들기 - Physics base (0) | 2025.01.27 |
[Unreal 5/C++] 회전 발판과 움직이는 장애물 퍼즐 스테이지 (0) | 2025.01.22 |
[Unreal 5] 언리얼 엔진 C++ 개발 환경 설정과 기본 구조 익히기 (0) | 2025.01.20 |