# 충돌 감지 문제 해결

**충돌 감지의 기본 개념**

충돌 감지는 물리 엔진에서 가장 기본적이면서 중요한 기능 중 하나이다. 객체가 물리적으로 상호작용하기 위해서는 서로의 충돌을 정확하게 감지해야 한다. 충돌 감지 문제의 원인은 다양할 수 있으며, 이를 해결하기 위한 다양한 방법이 필요하다.

**주요 충돌 감지 문제**

1. **오차 범위 문제**

   * 물리 엔진은 유한 정밀도의 부동 소수점 연산을 사용한다. 이로 인해 아주 작은 충돌을 정확하게 감지하지 못할 수 있다. 이러한 문제를 해결하려면 충돌 감지 오차 범위를 설정할 필요가 있다.

   ```pseudo
   if abs(distance(a, b) - (a.radius + b.radius)) < epsilon:
       handle_collision(a, b)
   ```
2. **시간 스텝 문제**

   * 물리 엔진은 일반적으로 이산 시간 스텝을 사용해 시뮬레이션을 진행한다. 매우 빠르게 이동하는 객체는 한 프레임에서 다른 프레임으로 이동할 때 충돌을 감지하지 못할 수 있다. 이를 해결하기 위한 방법 중 하나는 연속 충돌 감지(CD) 기법이다.

   ```pseudo
   Vector2 newPosA = a.position + a.velocity * deltaTime
   Vector2 newPosB = b.position + b.velocity * deltaTime

   if segmentIntersect(a.position, newPosA, b.position, newPosB):
       handle_collision(a, b)
   ```
3. **물체의 복잡한 형상 처리**

   * 단순한 구나 박스형 모델과 달리, 복잡한 폴리곤이나 메쉬 모델의 충돌을 감지하는 것은 더욱 어렵다. 복잡한 물체의 충돌을 처리하기 위해서는 꼭짓점, 모서리, 면 간의 충돌을 개별적으로 처리해야 한다.

   ```pseudo
   for each face in a.faces:
       for each face in b.faces:
           if polyhedronIntersect(faceA, faceB):
               handle_collision(a, b)
   ```
4. **물리적 특성 차이**

   * 물리적 특성이 다른 두 물체 간의 충돌 감지는 잘못된 결과를 낼 수 있다. 예를 들어, 두 물체의 질량, 탄성 계수, 마찰 계수 등이 다를 경우 이를 고려한 충돌 처리 로직이 필요하다.

   ```pseudo
   restitution = min(a.restitution, b.restitution)
   // 나머지 충돌 물리 계산...
   ```

**충돌 감지 문제 해결을 위한 기법**

1. **브로드 페이즈와 내로우 페이즈**

   * 충돌 감지는 일반적으로 두 단계로 나뉜다: 브로드 페이즈와 내로우 페이즈. 브로드 페이즈에서는 잠재적인 충돌 쌍을 빠르게 찾아내고, 내로우 페이즈에서는 실제 충돌 여부를 정밀하게 검사한다.

   ```pseudo
   broadPhasePairs = broadPhase(objects)
   for (a, b) in broadPhasePairs:
       if narrowPhase(a, b):
           handle_collision(a, b)
   ```
2. **AABB 충돌 상자 조합**

   * 객체를 Axis-Aligned Bounding Box (AABB)로 감싸서, 간단한 상자 충돌만 검출하는 방식은 계산량을 줄이는 데 유용하다.

   ```pseudo
   if aabbIntersect(a.AABB, b.AABB):
       if complexShapeIntersect(a, b):
           handle_collision(a, b)
   ```
3. **GJK 알고리즘**

   * Convex shapes의 충돌을 감지하는 데 특화된 알고리즘으로, 매우 효율적이다.

   ```pseudo
   if GJK(a.shape, b.shape):
       handle_collision(a, b)
   ```
4. **EPA 알고리즘**

   * GJK 알고리즘과 함께 사용되는 알고리즘으로, 각 물체의 깊이 및 충돌 지점을 계산하는 데 사용된다.

   ```pseudo
   depth, contactPoint = EPA(a.shape, b.shape)
   resolve_collision(a, b, depth, contactPoint)
   ```

**디버깅 기법**

1. **시각화**

   * 충돌 감지 디버깅에서는 문제가 발생한 부분을 시각적으로 확인하는 것이 중요하다. 물체의 AABB, 충돌 지점, 노멀 벡터 등을 화면에 렌더링해 문제를 직관적으로 파악할 수 있다.

   ```pseudo
   renderAABB(a.AABB)
   renderAABB(b.AABB)
   renderContactPoint(contactPoint)
   ```
2. **로그 출력**

   * 디버깅 로그를 통해 시간 스텝별로 발생하는 이벤트, 객체의 속성 값 등 다양한 디버깅 정보를 텍스트로 출력하여 확인할 수 있다.

   ```pseudo
   log("Collision detected between object A and object B at time step 5")
   log("Object A position:", a.position)
   log("Object B position:", b.position)
   ```

**테스트 기법**

1. **유닛 테스트**

   * 물리 엔진의 각 기능을 개별적으로 테스트할 수 있는 유닛 테스트를 작성하라. 충돌 감지, 반발력 계산 등 특정 기능이 올바르게 작동하는지 확인한다.

   ```pseudo
   function testCollisionDetection():
       a = createObject(...)
       b = createObject(...)
       assert(detectCollision(a, b) == expectedResult)
   ```
2. **시나리오 테스트**

   * 실제 게임 시나리오를 기반으로 테스트한다. 다양한 상황에서 물리 엔진이 올바르게 동작하는지 확인한다.

   ```pseudo
   function testScenario():
       setupComplexScenario()
       simulateSteps()
       assert(objectsInExpectedState())
   ```
3. **경계 조건 테스트**

   * 아주 작은 오차 또는 극단적인 상황에서 물리 엔진이 어떻게 반응하는지 테스트한다. 예를 들어, 매우 큰 속도로 이동하는 객체나 아주 작은 크기의 객체 등이 있다.

   ```pseudo
   function testBoundaryConditions():
       a = createObjectWithHighVelocity(...)
       b = createTinyObject(...)
       simulateCollision(a, b)
       assert(resultsAreWithinTolerance())
   ```
4. **프로파일링 테스트**

   * 물리 엔진의 성능을 측정하고 최적화 방안을 모색하기 위해 프로파일링을 수행한다. 성능 병목 구간을 찾아내고 개선한다.

   ```pseudo
   startProfiling()
   runPhysicsSimulation()
   stopProfiling()
   analyzeProfilingResults()
   ```

**문제 해결 예시**

* **사례 1: A와 B의 충돌이 감지되지 않음**

  * 원인: 너무 작은 충돌 오차 범위 설정.
  * 해결: 충돌 감지 오차 범위를 늘림.

  ```pseudo
  if abs(distance(a, b) - (a.radius + b.radius)) < increasedEpsilon:
      handle_collision(a, b)
  ```
* **사례 2: 빠르게 이동하는 C가 D를 관통**

  * 원인: 연속 충돌 감지 미사용.
  * 해결: 연속 충돌 감지 기법 도입.

  ```pseudo
  if segmentIntersect(c.position, newPosC, d.position, newPosD):
      handle_collision(c, d)
  ```
* **사례 3: 폴리곤 E와 F 간의 충돌 감지 실패**

  * 원인: 복잡한 형태의 충돌 처리 미흡.
  * 해결: GJK 또는 EPA 알고리즘 사용.

  ```pseudo
  if GJK(e.shape, f.shape):
      handle_collision(e, f)
  ```
* **사례 4: 충돌 계산 후 물체가 비정상적으로 튀어오름**

  * 원인: 잘못된 탄성 계수 사용.
  * 해결: 충돌 시 사용되는 탄성 계수 재검토 및 수정.

  ```pseudo
  restitution = min(e.restitution, f.restitution)
  handle_collision_with_restitution(e, f, restitution)
  ```

\#---

충돌 감지 문제는 물리 엔진을 디버깅하고 테스트하는 데 상당히 중요한 부분을 차지한다. 다양한 디버깅 및 테스트 기법을 활용하여 문제를 찾아내고 해결하는 것이 중요하다. 유닛 테스트와 시나리오 테스트를 통해 구체적인 문제를 재현하고 해결하여, 물리 엔진의 신뢰성을 높일 수 있다.
