엔티티에 물리 적용하기 

# 학습 과정 소개

물리 법칙을 엔티티에 적용하고 물리 엔티티끼리 충돌할 수 있게 만들어 봅시다. 월드에 물리를 만드는 방법은 [물리 사용하기](/docs?postId=757%7B%22target%22:%22_self%22%7D)를 참고하세요.

# PhysicsRigidbodyComponent

Entity에 PhysicsRigidbodyComponent를 추가하면 Entity가 물리 엔진에 의해 제어됩니다. 또한 엔티티의 저항 계수, 마찰 계수, 질량 등 물리 연산에 영향을 주는 값을 설정할 수 있습니다. Entity가 PhysicsRigidbodyComponent와 PhysicsColliderComponent를 함께 포함하고 있어야 물리 법칙을 따르는 다른 엔티티와 충돌할 수 있습니다. PhysicsRigidbodyComponent의 주요 프로퍼티는 아래와 같습니다.

[{"프로퍼티":"BodyType","설명":"Static: 질량이 무한히 큰 엔티티로 취급되며 Dynamic 타입과 충돌할 수 있습니다.Dynamic: 엔티티가 물리 법칙에 따라 동작합니다. 물리 충돌이 가능한 다른 Entity와 충돌할 수 있습니다.Kinematic: 질량이 무한히 큰 엔티티로 취급되나 Static 타입과 다르게 속도를 지정해 움직일 수 있습니다"},{"프로퍼티":"Mass","설명":"질량 값을 설정합니다. Collider의 넓이와 질량의 값을 이용해 밀도 값을 계산합니다."},{"프로퍼티":"Friction","설명":"마찰 계수를 결정합니다. 값이 작을수록 잘 미끄러집니다."},{"프로퍼티":"Restitution","설명":"Entity의 반발 계수를 설정합니다. 0이면 완전 비탄성 충돌, 1이면 완전 탄성 충돌에 가깝게 충돌합니다."},{"프로퍼티":"AngularDamping","설명":"엔티티가 원운동을 할 때 각속도(회전 속도)의 변화에 대한 저항 계수를 설정합니다. 값이 클수록 각속도 변화에 더 많은 힘이 필요합니다."},{"프로퍼티":"LinearDamping","설명":"선형 운동을 할 때 선형 속도 변화에 대한 저항 계수를 설정합니다. 값이 클수록 선형 속도 변화에 더 많은 힘이 필요합니다."},{"프로퍼티":"CollisionDetectionMode","설명":"물리 충돌의 감지 방식을 설정합니다.Discrete: 충돌을 비연속적으로 확인합니다. 물체의 속도와 크기에 따라 충돌을 감지하지 못할 수 있습니다. 속도가 빠르거나, 크기가 작을수록 충돌을 감지하지 못하고 통과할 가능성이 있습니다.Continuous: 충돌을 연속적으로 확인합니다. 물체가 충돌하지 못하고 통과하는 상황을 막습니다. 연산에 더 많은 자원이 필요합니다."},{"프로퍼티":"FixedRotation","설명":"true일 경우 물체가 물리 상호작용에 의한 회전을 하지 않습니다."},{"프로퍼티":"GravityScale","설명":"엔티티가 PhysiecsSimulatorComponent의 Gravity 값에 영향을 받는 정도를 설정합니다. Gravity 값이 (0,-10)일 때 GravityScale 값이 1이라면 엔티티가 받는 중력 값은 (0,-10)이고,GravityScale 값이 2라면 (0,-20)만큼의 중력을 받게 됩니"},{"프로퍼티":"SleepingMode","설명":"수면 모드를 설정합니다.StartAwake: 깨어있는 상태로 시작하나, 수면 상태로 전환할 수 있습니다.StartAsleep: 수면 상태로 시작하나, 충돌 시 깨어납니다.NeverSleep: 수면 상태로 전환되지 않습니다."}]

> 더 알아보기
> 
>   * 반발 계수: 충돌한 두 물체의 충돌 전후 상대 속도의 비
>   * 비탄성 충돌: 충돌 시 역학적 에너지가 손실됩니다.
>   * 완전 비탄성 충돌: 충돌 시 역학적 에너지가 손실되며 충돌 후 두 물체가 하나가 되어 운동합니다.
>   * 완전 탄성 충돌: 충돌 시 역학적 에너지가 보존되는 충돌입니다.
> 


# 함수 설명

PhysicsRigidbodyComponent 함수에 따라 엔티티에 특정 방향으로 힘을 가해 움직이게 하거나, 원운동(회전운동)을 할 수 있게 만들 수 있습니다. ApplyForce 계열 함수와 ApplyImpulse 계열 함수는 해당 Entity에 대응하는 물리 강체의 질량 값에 영향을 받습니다. SetVelocity 계열의 속도 설정 함수는 질량 값과 관계 없이 속도를 지정할 수 있습니다.

#### 힘을 가하는 함수

`ApplyForce()`, `ApplyTorque()` 함수는 지속적인 힘을 가할 수 있습니다. 특정 Key를 눌러 지속적으로 특정 방향으로 힘 가하고 싶을 때가 해당됩니다. 매개 변수 force는 힘을 의미합니다. 해당 Entity에 대응하는 물리 강체의 질량 값에 영향을 받습니다.

#### 충격량을 적용하는 함수

`ApplyAngularImpulse()`, `ApplyLinearImpulse()` 함수는 일시적으로 짧은 충격을 가할 수 있습니다. 대포 발파, 방망이 휘두르기 같은 짧은 충격을 주는 동작이 해당됩니다. 해당 Entity에 대응하는 물리 강체의 질량 값에 영향을 받습니다. 매개 변수 Impulse는 충격량을 의미하며 일시적으로 짧은 충격을 가할 때 사용합니다.

#### 속도 설정 함수

`SetAngularVelocity()`, `SetLinearVelocity()` 함수는 질량 값과 관계 없이 엔티티의 속도를 설정할 수 있습니다.

# PhysicsColliderComponent

엔티티의 충돌체 크기를 정하고, 오프셋을 설정할 수 있습니다. 주로 PhysicsRigidbodyComponent와 함께 사용하지만, PhysicsRigidbodyComponent 없이 사용하는 엔티티는 Static 타입으로 취급됩니다. 충돌체의 타입, 크기, 오프셋 등을 설정하는 방법은 [엔티티의 충돌](/docs/?postId=175%7B%22target%22:%22_self%22%7D)을 참고하세요.

[{"프로퍼티":"ColliderType","설명":"분류에 따라 충돌체의 형태를 다르게 설정할 수 있습니다. Circle: 원형 충돌체를 만듭니다. Box: 사각형 모양 충돌체를 만듭니다.Polygon: 다각형 충돌체를 만듭니다."},{"프로퍼티":"Collider","설명":"Edit 버튼을 눌러, 충돌체 크기를 설정할 수 있습니다."},{"프로퍼티":"CollisionGroup","설명":"충돌 여부를 결정할 수 있는 충돌 그룹을 설정합니다. 새로운 충돌 그룹을 만들어 설정할 수 있습니다."},{"프로퍼티":"Density","설명":"연결된 PhysicsRigidbodyComponent의 UseDensity가 true일 경우 사용할 밀도 값을 설정합니다."},{"프로퍼티":"UseCustomPhysicalProperties","설명":"Friction과 Restituion 값이 물리 강체에 적용됩니다. false일 경우 연결된 PhysicsRigidbodyComponent의 값을 사용합니다."},{"프로퍼티":"EnableContactEvent","설명":"PhysicsContactBeginEvent와 PhysicsContactEndEvent 발생 여부를 설정합니다. false일 경우 두 Event가 발생하지 않습니다."},{"프로퍼티":"IsSensor","설명":"true일 경우 물리적인 상호작용이 일어나지 않지만, 충돌 이벤트는 발생합니다."},{"프로퍼티":"ClientOnly","설명":"true일 경우 Client에서 물리 연산이 일어나며, Client 공간에서 함수 사용 및 Property 변경이 가능합니다. 물리 연산 결과가 다른 Clients와 동기화 되지 않습니다. false일 경우 Server 공간에서 함수 사용 및 Property 변경이 가능합니다. 물리 연산 결과가 다른 Clients와 동기화 됩니다."}]

#### 실행 공간별 물리 연산 차이

PhysicsRigidbodyComponent의 대부분의 Property와 Function은 PhysicsColliderComponent의 ClientOnly 프로퍼티의 값에 따라 사용, 접근 가능한 실행 공간이 나뉘게 됩니다. ClientOnly에 따라 각각의 물리 World에서 연산되며, 이에 따라 서로 충돌하거나 영향을 주지 않습니다.

  * ClientOnly가 True일 때: 해당 Entity의 물리 강체는 Client에서만 생성되고 물리 연산은 각각의 Client에서 계산됩니다. 다른 Client와 결과가 동기화되지 않습니다. Client에서만 관련 함수 사용 및 대부분의 Property 변경이 가능합니다.
  * ClientOnly가 False일 때: 해당 Entity의 물리 강체는 Server와 Client에서 생성되고 물리 연산 결과에 따른 물리 강체의 위치가 Server 및 모든 Client간 동기화됩니다.Server에서만 관련 함수 사용 및 대부분의 Property 변경이 가능합니다.



# 충돌 그룹 설정하기

충돌 그룹을 설정해 물리 법칙을 적용한 엔티티끼리의 충돌 여부를 크리에이터의 의도에 따라 설정할 수 있습니다. PhysicsColliderComponent의 CollisionGroup을 지정하고, 그룹끼리의 충돌 여부를 선택합니다. 맵에 중력을 만들고, 다양한 탄성력을 가진 Dynatic 타입인 물리 엔티티를 맵의 위쪽에 배치한 후 월드를 시작하면, 엔티티들이 하강하며 부딪혀 서로 튕겨나갑니다. 자세한 충돌 그룹 설정 방법은 [충돌 그룹 만들기](/docs?postId=754%7B%22target%22:%22_self%22%7D)를 확인하세요.

# 활용 예제

PhysicsSimulatorComponent와 TileMapComponent의 PhysicsInteractable를 활용해 월드에 물리를 적용해야 예제를 확인할 수 있습니다.

#### 바닥에 있는 물체 공중으로 던지기

J 키를 눌렀을 때 지면에 배치한 엔티티를 공중으로 던져봅시다. 떠오른 엔티티는 중력을 받아 밑으로 떨어질 것입니다. [gif](16601123764643cfe3adec2534fb68a22b98573a3713c)

  1. PhysicsRigidbodyComponent, PhysicsColliderComponent를 추가한 오브젝트를 씬에 배치합니다.
  2. 새로운 스크립트 컴포넌트를 생성한 뒤 아래와 같이 작성해 J를 눌렀을 때 오브젝트가 입력한 위치로 힘을 받아 이동합니다.


    
    
    @Component
    script JumpController extends Component
        method void Jump()
        self.Entity.PhysicsRigidbodyComponent:ApplyLinearImpulse(Vector2(0,10))
        end
    
        @EventSender("Service", "InputService")
        handler HandleKeyDownEvent(KeyDownEvent event)
        --------------- Native Event Sender Info ----------------
        -- Sender: InputService
        -- Space: Client
        ---------------------------------------------------------
    
        -- Parameters
        -- local key = event.key
        ---------------------------------------------------------
    
        if key == KeyboardKey.J then
            self:Jump()
        end
        end
    end
    

#### 충돌 그룹을 활용한 물리 엔티티 충돌

  1. PhysicsRigidbodyComponent, PhysicsColliderComponent를 추가한 오브젝트를 여러개 배치하고, 각각의 Mass, Restitution 값을 다르게 설정합니다.
  2. CollisionGroup에 새로운 물리 그룹을 추가하고 아래와 같이 서로 충돌할 수 있게 설정합니다. [png](16601112357375799a6ba9d5e4f17b1d7096d2d0e02ba)
  3. 시작을 눌러 엔티티끼리 충돌하는지 확인합니다. [gif](16601137220417735c37efe64470ab00e710e1c460242)



##### 참고 가이드

  * [물리 사용하기](/docs?postId=757%7B%22target%22:%22_self%22%7D)
  * [충돌 그룹 만들기](/docs?postId=754%7B%22target%22:%22_self%22%7D)
  * [다양한 물리 joint 활용하기](/docs?postId=760%7B%22target%22:%22_self%22%7D)