RigidBody

리지드 바디(rigid body)란?

리지드 바디는 물리적 개체의 행동을 시뮬레이션 하기 위해 물리 엔진으로 직접 다루는 바디입니다. 바디의 모양을 정의하려면 하나 이상의 Shape 개체가 지정되어 있어야 합니다. 이러한 모양의 위치를 설정하면 바디의 무게 중심에 영향을 미칩니다.

리지드 바디를 제어하는 방법

리지드 바디의 동작은 마찰, 질량, 바운스 등의 속성을 설정하여 변경할 수 있습니다. 이러한 속성은 인스펙터나 코드를 통해 설정할 수 있습니다. 속성과 그 효과의 전체 목록은 RigidBody를 참고하세요.

원하는 용도에 따라 리지드 바디의 움직임을 제어하는 몇 가지 방법이 있습니다.

예를 들어, 초기 위치를 설정하기 위해 리지드 바디를 한 번만 배치해야 된다면 set_global_transform() 또는 look_at()과 같은 Spatial 노드가 제공하는 메서드를 사용할 수 있습니다. 그러나 이 메서드들이 모든 프레임을 호출하지 못하거나 물리 엔진이 바디 상태를 정확하게 시뮬레이션 할 수 없을 것입니다. 예를 들어, 다른 물체를 가리키도록 회전할 리지드 바디를 고려하는것이 있습니다. 이런 행동을 시행할 때 흔히 저지르는 실수는 look_at()을 모든 프레임에 사용하는 것인데 이것은 물리학적 시뮬레이션을 깨뜨리게 됩니다. 아래에서는, 이를 올바르게 구현하는 방법을 시연합니다.

set_global_transform()이나 look_at()의 방법을 사용할 수 없다는 사실이 리지드 바디를 완전히 통제할 수 없다는 것을 의미하지는 않습니다. 대신 _integrate_forces() 콜백을 사용하여 제어할 수 있습니다. 이 기능에서 원하는 이동을 달성하기 위해 forces를 추가하거나 impulses를 적용하거나 velocity를 설정할 수 있습니다.

"look at" 메서드

위에서 설명한 것처럼, Spatial 노드의 look_at()을 각 프레임에 사용하여 대상을 따라가도록 할 수는 없습니다. 다음은 리지드 바디에서 안정적으로 작동하는 커스텀 look_at() 함수입니다:

extends RigidBody

func look_follow(state, current_transform, target_position):
    var up_dir = Vector3(0, 1, 0)
    var cur_dir = current_transform.basis.xform(Vector3(0, 0, 1))
    var target_dir = (target_position - current_transform.origin).normalized()
    var rotation_angle = acos(cur_dir.x) - acos(target_dir.x)

    state.set_angular_velocity(up_dir * (rotation_angle / state.get_step()))

func _integrate_forces(state):
    var target_position = $my_target_spatial_node.get_global_transform().origin
    look_follow(state, get_global_transform(), target_position)
class Body : RigidBody
{
    private void LookFollow(PhysicsDirectBodyState state, Transform currentTransform, Vector3 targetPosition)
    {
        var upDir = new Vector3(0, 1, 0);
        var curDir = currentTransform.basis.Xform(new Vector3(0, 0, 1));
        var targetDir = (targetPosition - currentTransform.origin).Normalized();
        var rotationAngle = Mathf.Acos(curDir.x) - Mathf.Acos(targetDir.x);

        state.SetAngularVelocity(upDir * (rotationAngle / state.GetStep()));
    }

    public override void _IntegrateForces(PhysicsDirectBodyState state)
    {
        var targetPosition = GetNode<Spatial>("my_target_spatial_node").GetGlobalTransform().origin;
        LookFollow(state, GetGlobalTransform(), targetPosition);
    }
}

이 함수는 바디를 회전시키기 위해 리지드 바디의 set_angular_velocity() 메서드를 사용합니다. 먼저 현재와 원하는 각도의 차이를 계산한 다음 한 프레임의 시간에 해당 양만큼 회전하는 데 필요한 속도를 추가합니다.

주석

리지드 바디에서 이 스크립트는 바디의 회전을 잠그는 character 모드이면 작동하지 않을 것입니다. 이 경우 표준 Spatial 메서드를 사용하여 연결된 메시 노드를 회전해야 합니다.