충돌 검사(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)를 활용하여 구현한 예시:
'TIL > C++와 UE' 카테고리의 다른 글
비행체 움직임 (0) | 2025.01.28 |
---|---|
회전 관련 함수 및 Pawn 클래스 Look 함수 (1) | 2025.01.27 |
Pawn 클래스 다루기 (0) | 2025.01.23 |
언리얼 엔진 클래스 계층 구조 (0) | 2025.01.22 |
액터 Transform을 위한 좌표계와 부동 소수점 연산 (0) | 2025.01.21 |