[2025_12_31] Unity 게임 배속 증가 시 Projectile 충돌 감지 실패 해결

2025. 12. 31. 22:19TIL

문제 상황

증상

  • PC (60fps): 1배속에서 정상 작동 
  • PC (60fps): 3배속에서 정상 작동
  • 모바일 (30fps): 1배속에서 정상 작동
  • 모바일 (30fps): 2배속에서 정상 작동
  • 프레임 드랍 시: 충돌 감지 실패 빈도 증가

원인 분석

1. Time.deltaTime의 이중 변수

Time.deltaTime은 두 가지 요인에 영향을 받습니다:

Time.deltaTime = (실제 경과 시간) × (Time.timeScale)
                     ↑                    ↑
                 프레임레이트          게임 배속

 

프레임레이트에 따른 Time.deltaTime 차이

 
PC (60fps, 1배속):
  실제 경과 시간 = 1/60 = 0.0167초
  Time.deltaTime = 0.0167 × 1 = 0.0167초
  이동 거리 = 5 × 0.0167 = 0.083 유닛 

모바일 (30fps, 1배속):
  실제 경과 시간 = 1/30 = 0.033초
  Time.deltaTime = 0.033 × 1 = 0.033초
  이동 거리 = 5 × 0.033 = 0.165 유닛 
  
모바일 (30fps, 3배속):
  실제 경과 시간 = 1/30 = 0.033초
  Time.deltaTime = 0.033 × 3 = 0.099초
  이동 거리 = 5 × 0.099 = 0.495 유닛 
  → 충돌 반경(0.3)보다 훨씬 큼!

 

 

기존 충돌 감지 방식의 문제

 
csharp
// 기존 방식: 현재 위치만 체크
private void CheckCollisionWithTarget()
{
    float distance = Vector3.Distance(transform.position, target.position);
    
    if (distance <= collisionRadius)
    {
        OnHit();
    }
}
```

문제점:
- 현재 프레임의 위치만 검사
- 1프레임 동안 이동한 경로는 무시
- 프레임레이트가 낮을수록 (이동 거리가 클수록) 문제 심각
- PC에서는 괜찮아도 모바일에서 실패


다이어그램:

기존 방식 (점-점 충돌):
PC (60fps, 작은 이동):
  ●──●──●──●──●타겟●──●──●
  프레임마다 조금씩 이동 → 충돌 감지 쉬움 

모바일 (30fps, 큰 이동):
  ●─────●─────●타겟●─────●
  프레임 간격 큼 → 타겟 건너뛸 위험 ⚠

모바일 (30fps, 3배속):
  ●────────────────●타겟●
                    ↑
            건너뜀! 
```

---

#해결 방법

핵심 아이디어

점-점 충돌 → 선분-점 충돌

- 프레임레이트와 관계없이 작동
- 이전 위치 → 현재 위치 사이의 모든 경로 검사
- 선분과 점 사이의 최단거리 계산
- 최단거리가 충돌 반경 이내면 충돌!

왜 프레임 독립적인가?

PC (60fps, 작은 이동):
  선분 길이: 0.083
  → 경로 전체 검사 

모바일 (30fps, 큰 이동):
  선분 길이: 0.165
  → 경로 전체 검사 
  → 길이가 달라도 같은 로직!

프레임 드랍 (10fps, 매우 큰 이동):
  선분 길이: 0.5
  → 경로 전체 검사 
  → 여전히 작동!

수학적 원리: 선분-점 최단거리
선분 AB와 점 P가 있을 때:
1. 벡터 정의
   AB = B - A  (선분의 방향 벡터)
   AP = P - A  (A에서 P로 가는 벡터)

2. P를 AB 선분에 투영 (Projection)
   t = dot(AP, AB) / dot(AB, AB)
   
   t의 의미:
   - t = 0: 가장 가까운 점은 A
   - t = 0.5: 가장 가까운 점은 AB의 중간
   - t = 1: 가장 가까운 점은 B

3. t를 0~1 범위로 제한 (선분 내부로)
   t = Clamp(t, 0, 1)

4. 선분 위에서 P에 가장 가까운 점 계산
   ClosestPoint = A + AB * t

5. 최단거리 계산
   Distance = |ClosestPoint - P|

시각적 설명:

새로운 방식 (선분-점 충돌):

PC (60fps, 작은 선분):
  이전●──X──●현재
        │
        ●타겟
  선분이 작아도 체크 

모바일 (30fps, 큰 선분):
  이전●──────X──────●현재
            │
            ●타겟
  선분이 커도 체크 

프레임 드랍 (10fps, 매우 큰 선분):
  이전●──────────X──────────●현재
                │
                ●타겟
  선분이 매우 커도 체크 
  
→ 선분 길이와 무관하게 정확한 충돌 감지!

 

배운 점

크로스 플랫폼 개발 시 필수 고려사항

  • PC에서 테스트만 하면 모바일 버그 놓칠 수 있음
  • 낮은 프레임레이트에서 테스트 필수
  • 프레임 독립적인 로직 설계 중요

 수학적 원리 실전 활용

csharp
// 투영 계산에 핵심
float t = Vector3.Dot(AP, AB) / abLengthSq;
  • 두 벡터의 방향 유사도 측정
  • 투영(Projection) 계산에 필수

벡터 투영 (Projection):

  • 한 벡터를 다른 벡터 방향으로 투영
  • 선분 위에서 가장 가까운 점 찾기
  • 프레임레이트와 무관하게 작동

3. Unity Time 시스템 이해

csharp
// Update() - 프레임마다 다름
Time.deltaTime // 60fps: 0.0167, 30fps: 0.033

// FixedUpdate() - 고정
Time.fixedDeltaTime // 항상 0.02 (50fps)
```

Time.timeScale 영향:
- Time.deltaTime: 영향 받음
- Time.unscaledDeltaTime: 영향 안 받음
- 배속 시스템 구현 시 주의 필요

 4. 충돌 감지의 근본 원리

점-점 충돌의 한계:
- 특정 순간의 위치만 검사
- 빠른 이동 시 누락 가능
- 프레임레이트 의존적

경로 기반 충돌의 장점:**
- 이동 경로 전체 검사
- 속도와 무관하게 정확
- 프레임레이트 독립적
- Raycast 없이도 구현 가능

 5. 크로스 플랫폼 테스트의 중요성

테스트 체크리스트:
 PC 60fps 테스트
 PC 30fps 강제 테스트 (Application.targetFrameRate = 30)
 실제 모바일 기기 테스트
 저사양 기기 테스트
 배속 1~5배 모두 테스트
 프레임 드랍 시뮬레이션

 


결론

  • 두 요소가 복합적으로 작용
  • PC와 모바일의 근본적인 차이
  • 프레임 독립적 로직의 중요성

"점-점 충돌"에서 "경로 기반 충돌"로 사고를 전환하면:

  • 프레임레이트 독립적인 게임 개발 가능
  • 크로스 플랫폼 호환성 향상
  • 플레이어 경험 일관성 보장