[2025_12_31] Unity 게임 배속 증가 시 Projectile 충돌 감지 실패 해결
2025. 12. 31. 22:19ㆍTIL
문제 상황
증상
- 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와 모바일의 근본적인 차이
- 프레임 독립적 로직의 중요성
"점-점 충돌"에서 "경로 기반 충돌"로 사고를 전환하면:
- 프레임레이트 독립적인 게임 개발 가능
- 크로스 플랫폼 호환성 향상
- 플레이어 경험 일관성 보장
'TIL' 카테고리의 다른 글
| [2026_01_06] 비대칭 디버깅(같은 로직인데 한 쪽에서만 작동) (0) | 2026.01.06 |
|---|---|
| [2026_01_02] 중간 발표 (0) | 2026.01.02 |
| [2025_12_30] Unity UI 이벤트 구독/해제 (0) | 2025.12.30 |
| [2025_12-29] 유닛 떨림 현상 해결 - 유닛 회피 시스템 (0) | 2025.12.29 |
| [2025_12_26] 공격 범위 계산 버그 - 좌표 기준점 설정의 중요점 (0) | 2025.12.26 |