# 중력 및 충돌 처리

로봇 시뮬레이션에서 중력과 충돌 처리는 물리 기반 상호작용을 현실감 있게 구현하는 데 필수적인 요소이다. Unity는 강력한 물리 엔진을 제공하여 이러한 요소들을 손쉽게 다룰 수 있게 해준다. 이 장에서는 Unity에서 중력을 설정하고 충돌을 처리하는 방법에 대해 상세히 다루겠다.

#### 중력 설정

Unity의 물리 엔진은 기본적으로 중력을 지원하며, 이를 통해 로봇과 환경 간의 상호작용을 자연스럽게 구현할 수 있다. 중력은 `Physics` 설정을 통해 조절할 수 있다.

**중력의 기본 개념**

중력은 모든 물체에 작용하는 힘으로, 지구에서는 보통 $\mathbf{g} = \begin{pmatrix} 0 \ -9.81 \ 0 \end{pmatrix}$ m/s²의 값을 갖는다. Unity에서는 이 값을 통해 시뮬레이션 내의 모든 물체에 동일한 중력 효과를 적용한다.

**Unity에서 중력 설정 방법**

1. **Physics 설정 열기**:
   * 상단 메뉴에서 `Edit` > `Project Settings`를 선택한다.
   * 좌측 패널에서 `Physics`를 선택한다.
2. **중력 값 조정**:

   * `Gravity` 항목에서 $\mathbf{g}$ 값을 설정할 수 있다.
   * 기본값은 $\begin{pmatrix} 0 \ -9.81 \ 0 \end{pmatrix}$ 이지만, 필요에 따라 변경할 수 있다.

   ```csharp
   // 예제: 중력을 사용자 정의 값으로 설정
   Physics.gravity = new Vector3(0, -9.81f, 0);
   ```
3. **중력의 방향과 크기 변경**:

   * 중력의 방향을 변경하여 예를 들어, 수평 방향으로 중력을 적용할 수 있다.

   ```csharp
   // 수평 방향으로 중력 설정
   Physics.gravity = new Vector3(-9.81f, 0, 0);
   ```

**물체별 중력 적용**

기본적으로 모든 `Rigidbody` 컴포넌트가 중력의 영향을 받는다. 특정 물체에만 중력을 적용하거나 중력을 무시하려면 `Rigidbody` 설정을 조정해야 한다.

* **중력 무시하기**:

  ```csharp
  // Rigidbody 컴포넌트에서 중력 무시 설정
  Rigidbody rb = GetComponent<Rigidbody>();
  rb.useGravity = false;
  ```
* **중력 강도 조절**: 특정 물체에 대한 중력의 영향을 조절하려면 추가적인 스크립트를 작성하여 힘을 가할 수 있다.

  ```csharp
  void FixedUpdate()
  {
      Rigidbody rb = GetComponent<Rigidbody>();
      Vector3 customGravity = new Vector3(0, -4.905f, 0); // 절반 중력
      rb.AddForce(customGravity, ForceMode.Acceleration);
  }
  ```

#### 충돌 처리

충돌 처리는 로봇과 환경 간의 물리적 상호작용을 정의하며, 이를 통해 로봇의 움직임과 반응을 현실감 있게 시뮬레이션할 수 있다. Unity는 다양한 충돌 감지 메커니즘을 제공하여 이를 지원한다.

**충돌 감지의 기본 원리**

Unity에서는 `Collider`와 `Rigidbody` 컴포넌트를 통해 충돌을 관리한다. `Collider`는 물체의 형태를 정의하고, `Rigidbody`는 물리적 속성을 부여한다.

* **Collider 종류**:
  * **Box Collider**: 직육면체 형태
  * **Sphere Collider**: 구 형태
  * **Capsule Collider**: 캡슐 형태
  * **Mesh Collider**: 임의의 메시 형태
* **Rigidbody**:
  * 물리 엔진의 영향을 받는 물체에 부여
  * 중력, 질량, 마찰력 등을 설정 가능

**충돌 감지 설정**

1. **Collider 추가**:
   * 게임 오브젝트에 적절한 `Collider`를 추가한다.
   * 예를 들어, 로봇의 각 부위에 `Box Collider`를 추가하여 충돌을 감지할 수 있다.
2. **Rigidbody 추가**:
   * 충돌 반응을 원한다면 `Rigidbody` 컴포넌트를 추가한다.
   * `Rigidbody`의 `Is Kinematic` 속성을 설정하여 물리 엔진의 영향을 받을지 여부를 결정한다.
3. **충돌 감지 이벤트**:

   * 스크립트를 통해 충돌 이벤트를 처리할 수 있다.

   ```csharp
   void OnCollisionEnter(Collision collision)
   {
       // 충돌 시 처리할 로직
       Debug.Log("충돌 발생: " + collision.gameObject.name);
   }
   ```

**충돌 물리 설정**

충돌 시 물체 간의 반응을 조절하기 위해 물리적 속성을 설정할 수 있다.

* **마찰력(Friction)**:

  * 물체 표면 간의 마찰을 설정한다.
  * `Physic Material`을 생성하여 `Dynamic Friction`과 `Static Friction` 값을 조절한다.

  ```csharp
  // Physic Material 설정 예제
  PhysicMaterial mat = new PhysicMaterial();
  mat.dynamicFriction = 0.5f;
  mat.staticFriction = 0.5f;
  mat.frictionCombine = PhysicMaterialCombine.Average;

  // Collider에 Physic Material 적용
  Collider collider = GetComponent<Collider>();
  collider.material = mat;
  ```
* **탄성(Energy)**:

  * 충돌 시 물체가 반발하는 정도를 설정한다.
  * `Physic Material`의 `Bounciness` 값을 조절하여 반발력을 설정할 수 있다.

  ```csharp
  // 탄성 설정 예제
  mat.bounciness = 0.3f;
  mat.bounceCombine = PhysicMaterialCombine.Maximum;
  ```

**충돌 처리 최적화**

충돌 감지는 시뮬레이션의 성능에 큰 영향을 미칠 수 있으므로, 최적화가 필요하다.

* **충돌 체커 최소화**:
  * 불필요한 충돌 체커를 제거하고 필요한 부분에만 `Collider`를 추가한다.
* **충돌 레이어 사용**:

  * `Layer`를 설정하여 특정 레이어 간의 충돌을 비활성화할 수 있다.

  ```csharp
  // 레이어 충돌 설정
  // Edit > Project Settings > Physics > Layer Collision Matrix에서 설정
  ```
* **Collider 간소화**:
  * 복잡한 메시 콜라이더 대신 기본 도형 콜라이더를 사용하여 계산 부담을 줄이다.

**연속 충돌 감지 (Continuous Collision Detection)**

기본적으로 Unity의 물리 엔진은 **불연속 충돌 감지(Discrete Collision Detection)** 방식을 사용한다. 이는 프레임 간 물체의 위치를 확인하여 충돌을 감지하는 방식으로, 고속으로 이동하는 물체가 충돌을 놓칠 수 있는 단점이 있다. 이를 해결하기 위해 **연속 충돌 감지(Continuous Collision Detection)** 방식을 사용할 수 있다.

* **연속 충돌 감지의 필요성**:
  * 고속 물체의 충돌 누락 방지
  * 더 정확한 충돌 반응 구현
* **설정 방법**: `Rigidbody` 컴포넌트의 `Collision Detection` 속성을 변경하여 설정할 수 있다.

  ```csharp
  // Rigidbody의 충돌 감지 모드를 연속으로 설정
  Rigidbody rb = GetComponent<Rigidbody>();
  rb.collisionDetectionMode = CollisionDetectionMode.Continuous;
  ```
* **충돌 감지 모드**:
  * **Discrete**: 기본 설정, 성능은 좋으나 고속 물체에서 충돌 누락 가능
  * **Continuous**: 고속 물체의 충돌을 보다 정확하게 감지
  * **Continuous Dynamic**: 동적 물체에 대해 더욱 정밀한 충돌 감지
  * **Continuous Speculative**: 예측 기반 충돌 감지로 성능과 정확도의 균형을 맞춤

**트리거(Collider Trigger) 사용**

`Collider` 컴포넌트의 `Is Trigger` 속성을 활성화하면 해당 콜라이더는 물리적 충돌 대신 **트리거 이벤트**를 발생시킨다. 이는 물체가 충돌했을 때 물리적 반응을 일으키지 않고, 스크립트를 통해 특정 동작을 수행하고자 할 때 유용하다.

* **트리거의 활용 예**:
  * 로봇이 특정 영역에 진입했을 때 경고 표시
  * 아이템 수집
  * 자동 문 열림
* **설정 방법**: `Collider` 컴포넌트의 `Is Trigger` 체크박스를 활성화한다.

  ```csharp
  // 트리거 콜라이더 설정 예제
  Collider collider = GetComponent<Collider>();
  collider.isTrigger = true;
  ```
* **트리거 이벤트 처리**: 트리거 이벤트는 `OnTriggerEnter`, `OnTriggerStay`, `OnTriggerExit` 메서드를 통해 처리할 수 있다.

  ```csharp
  void OnTriggerEnter(Collider other)
  {
      Debug.Log("트리거에 진입한 오브젝트: " + other.gameObject.name);
      // 추가 로직 구현
  }

  void OnTriggerExit(Collider other)
  {
      Debug.Log("트리거에서 벗어난 오브젝트: " + other.gameObject.name);
      // 추가 로직 구현
  }
  ```

**충돌 레이어 및 충돌 매트릭스**

충돌 레이어를 사용하면 특정 레이어에 속한 물체 간의 충돌을 활성화하거나 비활성화할 수 있다. 이는 시뮬레이션의 성능을 최적화하고, 불필요한 충돌 계산을 줄이는 데 유용하다.

* **레이어 설정 방법**:
  1. **레이어 추가**:
     * 상단 메뉴에서 `Edit` > `Project Settings` > `Tags and Layers`로 이동한다.
     * 원하는 레이어를 추가한다.
  2. **게임 오브젝트에 레이어 할당**:
     * 게임 오브젝트를 선택하고, 인스펙터 창에서 `Layer` 드롭다운을 통해 할당한다.
* **충돌 매트릭스 설정**:

  * `Edit` > `Project Settings` > `Physics`에서 `Layer Collision Matrix`를 조정하여 어떤 레이어 간의 충돌을 활성화할지 설정할 수 있다.

  ![Layer Collision Matrix](https://3185889288-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FRLG1IioyolTsxQZZJ2xc%2Fuploads%2Fgit-blob-c57e402b42ab95057362ce996f08850d0538658c%2FLayerCollisionMatrix.png?alt=media)

  * 예를 들어, 로봇과 환경 레이어 간의 충돌만 활성화하고, 로봇 간의 충돌은 비활성화할 수 있다.

**물리 성능 최적화 팁**

* **단순한 콜라이더 사용**: 복잡한 메시 콜라이더 대신, 가능한 한 기본 도형 콜라이더(Box, Sphere, Capsule 등)를 사용하여 계산 부담을 줄이다.
* **콜라이더 수 최소화**: 필요한 부분에만 콜라이더를 추가하고, 불필요한 콜라이더는 제거한다.
* **물리 업데이트 주기 조절**: `Fixed Timestep`을 조정하여 물리 업데이트의 빈도를 최적화할 수 있다. 이는 `Edit` > `Project Settings` > `Time`에서 설정할 수 있다.
* **충돌 레이어 활용**: 위에서 설명한 레이어 매트릭스를 활용하여 불필요한 충돌 계산을 줄이다.
* **LOD(Level of Detail) 적용**: 물체의 거리에 따라 콜라이더의 복잡성을 조절하여 성능을 향상시킬 수 있다.

#### 예제: 로봇과 지면 간의 충돌 처리

로봇이 지면과 충돌하여 안정적으로 서 있을 수 있도록 설정하는 예제를 살펴보겠다.

1. **지면 설정**:
   * 평면(Plane) 게임 오브젝트를 생성하고, `Box Collider`를 추가한다.
   * `Rigidbody` 컴포넌트를 추가하되, `Is Kinematic`을 활성화하여 지면이 물리적 영향을 받지 않도록 설정한다.
2. **로봇 설정**:
   * 로봇 모델에 `Rigidbody`와 적절한 `Collider`를 추가한다.
   * `Rigidbody`의 `Mass`, `Drag`, `Angular Drag` 값을 설정하여 로봇의 물리적 특성을 조절한다.
3. **충돌 감지 스크립트 추가**:

   * 로봇에 스크립트를 추가하여 충돌 시 특정 동작을 수행하도록 설정한다.

   ```csharp
   using UnityEngine;

   public class RobotCollision : MonoBehaviour
   {
       void OnCollisionEnter(Collision collision)
       {
           if (collision.gameObject.CompareTag("Ground"))
           {
               Debug.Log("로봇이 지면과 충돌하였다.");
               // 추가 로직 구현
           }
       }
   }
   ```
4. **테스트 및 조정**:
   * 시뮬레이션을 실행하여 로봇이 지면에 안정적으로 서 있는지 확인한다.
   * 필요에 따라 `Rigidbody` 및 `Collider` 설정을 조정하여 원하는 동작을 구현한다.
