충돌 검사

언리얼 거토
|2025. 1. 24. 13:00

충돌 검사(Collision Detection)란?

  • 게임 내에서 두 오브젝트가 서로 닿았는지(충돌했는지) 확인하는 과정
  • 오브젝트 간 충돌을 감지하여 물리 반응을 적용하거나 이벤트를 발생시키는 것이 충돌 검사

충돌 검사의 종류 (Unreal Engine)

1. 물리 충돌 (Physics Collision)

  • 오브젝트가 물리적으로 부딪히는 것 감지
  • 충돌 시 물리 법칙에 따른 반응 (튕기거나 멈춤)
  • 예시: 플레이어가 벽에 부딪혀 멈춤
BoxComp->SetCollisionEnabled(ECollisionEnabled::PhysicsOnly);

2. 쿼리 충돌 (Query Collision)

  • 레이캐스트(Line Trace) 또는 오버랩(Overlap)으로 충돌 감지
  • 물리 반응 없이 충돌 여부 확인
  • 예시: 아이템 근처에서 'Press E' 메시지 표시
BoxComp->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
 
 

3. 관련 코드

1. 충돌 설정 활성화 함수

BoxComp->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
옵션 설명
NoCollision 충돌 비활성화 (충돌 검사 X, 물리 적용 X)
QueryOnly 충돌 검사만 활성화 (충돌 반응 없음, 물리 적용 X)
PhysicsOnly 물리 적용만 활성화 (충돌 검사 X, 물리 적용 O)
QueryAndPhysics 충돌 검사 + 물리 적용 모두 활성화 (충돌 O, 물리 O)

 

2. 오브젝트의 충돌 유형(Collision Object Type) 설정 함수

BoxComp->SetCollisionObjectType(ECollisionChannel::ECC_Pawn);
충돌 채널 설명
ECC_WorldStatic 고정된 지형, 벽 등 (움직이지 않는 오브젝트)
ECC_WorldDynamic 움직이는 오브젝트 (예: 물리 오브젝트)
ECC_Pawn 플레이어나 AI 캐릭터
ECC_PhysicsBody 물리 시뮬레이션이 적용되는 오브젝트
ECC_Vehicle 차량과 관련된 오브젝트
ECC_Visibility 라인트레이스(레이캐스트) 감지용

 

3. 다른 충돌 채널에 대한 반응 함수

// 모든 채널의 오브젝트와의 충돌을 막도록 설정
BoxComp->SetCollisionResponseToAllChannels(ECR_Block);

// 캐릭터(Pawn)와의 충돌을 무시하도록 설정
BoxComp->SetCollisionResponseToChannel(ECC_Pawn, ECR_Ignore);

// 정적 오브젝트와는 충돌을 막도록 설정
BoxComp->SetCollisionResponseToChannel(ECC_WorldStatic, ECR_Block);

// 동적 오브젝트와는 겹치도록 설정
BoxComp->SetCollisionResponseToChannel(ECC_WorldDynamic, ECR_Overlap);
옵션 설명
ECR_Ignore 충돌 무시 (아예 반응 X)
ECR_Overlap 겹쳐지지만 충돌하지 않음 (예: 트리거)
ECR_Block 충돌 발생 (움직임 차단)

Pawn의 점프 후 착지 여부 판별 방법

1. 오버랩(Overlap) :

기본 충돌 영역을 정의 해주는 루트 컴포넌트(예: UBoxComponent or UCapsuleComponent)를 만들고,
Pawn이 그 영역과 겹치는지(Overlap) 확인하는 방식

  • 장점: 성능 좋음 (이벤트 기반)
  • 단점: 콜리전 설정 필요
  • C++ 예제:
//생성자
/*BoxComp->OnComponentBeginOverlap.AddDynamic(this, &ASpartaPawn::OnOverlapBegin);*/

void ASpartaPawn::OnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, 
                                 UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, 
                                 bool bFromSweep, const FHitResult& SweepResult)
{
    if (OtherActor && OtherActor != this && OtherComp)
    {
        // 땅에 닿았는지 확인 (충돌 대상의 태그 등을 활용 가능)
        if (OtherActor->ActorHasTag(TEXT("Ground")))
        {
            bIsJumping = false;
            GetWorldTimerManager().ClearTimer(JumpTimerHandle); // 타이머 중지
        }
    }
}
 

2. 라인트레이스(Line Trace, Raycast):

플레이어의 발 아래로 짧은 Ray를 쏴서 땅과의 거리를 체크하는 방식

  • 장점: 정확한 거리 측정 가능
  • 단점: 잦은 호출 (CPU 부담)
  • C++ 구현 코드 :
void ASpartaPawn::StartJump(const FInputActionValue& value)
{
    if (value.Get<bool>()&&!bIsJumping) // 점프 중이 아닐 때만 실행
    {
        bIsJumping = true;
        JumpVelocity = InitialJumpVelocity;
        GetWorldTimerManager().SetTimer(JumpTimer, this, &ASpartaPawn::HandleJump, 0.016f, true);
    }
}

void ASpartaPawn::StopJump(const FInputActionValue& value)
{
    if (!value.Get<bool>())
    {
        // 점프 속도 즉시 감소 (짧게 누르면 낮은 점프)
        JumpVelocity *= 0.5f;
    }
}
void ASpartaPawn::HandleJump() 
{
    if (!bIsJumping) return;

    float DeltaTime = GetWorld()->GetDeltaSeconds();

    // 중력 적용
    CurrentJumpVelocity += Gravity * DeltaTime;

    FVector NewLocation = GetActorLocation();
    NewLocation.Z += CurrentJumpVelocity * DeltaTime;

    // 땅에 닿았는지 확인
    if (IsOnFoot()) 
    {
        bIsJumping = false;
        GetWorldTimerManager().ClearTimer(JumpTimerHandle); // 타이머 중지
    }

    SetActorLocation(NewLocation, true);
}
bool ASpartaPawn::IsOnFoot()
{
    FVector Start = GetActorLocation();
    FVector End = Start - FVector(0.0f, 0.0f, TraceLength); // TraceLength: 검사할 거리

    FHitResult HitResult; // 라인 트레이스의 결과를 담을 구조체 변수
    FCollisionQueryParams Params; // 트레이스의 옵션을 설정하는 객체
    Params.AddIgnoredActor(this); // 자신은 무시

    // 디버그 라인 그리기
    DrawDebugLine(GetWorld(), Start, End, FColor::Green, false, 1.0f, 0, 2.0f);
	
    //라인 트레이스 실행, 충돌 여부 검사
    bool bHit = GetWorld()->LineTraceSingleByChannel(HitResult, Start, End, ECC_Visibility, Params);

    if (bHit && HitResult.GetActor())
    {
        return true; // 땅에 닿았음
    }

    return false; // 땅에 닿지 않음
}
 
  • FHitResult HitResult
    • 목적: 라인 트레이스의 결과(충돌 정보)를 담는 구조체.
    • 내용: 충돌한 액터, 충돌 지점, 표면 법선 벡터 등의 정보를 포함.
  • FCollisionQueryParams Params
    • 목적: 라인 트레이스 실행 시 사용할 설정을 정의.
    • 내용: 충돌 무시 대상(예: 자신)을 설정하거나 특정 조건을 지정.
  • Params.AddIgnoredActor(this)
    • 목적: 자기 자신을 라인 트레이스에서 제외.
    • 내용: 트레이스가 현재 액터와 충돌하지 않도록 설정.
  • bool bHit = GetWorld()->LineTraceSingleByChannel(...)
    • 목적: 라인 트레이스를 실행하고 충돌 여부를 반환.
    • 내용:
      • Start에서 End까지 라인 트레이스를 수행.
      • 충돌 정보는 HitResult에 저장.
      • 반환값 bHit: 충돌 시 true, 아니면 false.
  • if (bHit && HitResult.GetActor())
    • 목적: 충돌 발생 여부와 충돌한 액터의 유효성 확인.
    • 내용:
      • bHit가 true이고, HitResult.GetActor()가 nullptr이 아니면 유효한 충돌로 간주.

최적의 조합

  • 기본: Overlap
  • 정확한 거리 측정 필요시: Raycast 보조적으로 사용

 

라인트레이스(RayCast)를 활용하여 구현한 예시: