リジットボディ(RigidBody/剛体)

リジッド ボディとは何ですか?

リジッド ボディは、物理オブジェクトの動作をシミュレートするために物理エンジンによって直接制御されるものです。ボディの形状を定義するには、1つ以上の Shape オブジェクトが割り当てられている必要があります。これらの形状の位置を設定すると、ボディの重心に影響することに注意してください。

リジッド ボディを制御する方法

リジッドボディの動作は、摩擦、質量、反発などのプロパティを設定することで変更できます。これらのプロパティは、インスペクタまたはコードを介して設定できます。プロパティとその効果の完全なリストについては、 RigidBody を参照してください。

目的のアプリケーションに応じて、リジットボディの動きを制御する方法がいくつかあります。

リジッド ボディを1回だけ配置する必要がある場合、たとえば最初の位置を設定する場合は、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() メソッドを使用して体を回転させます。最初に現在の角度と目的の角度の差を計算し、次に1フレームの時間内にその量だけ回転するのに必要な速度を追加します。

注釈

このスクリプトは、ボディの回転がロックされているため、character mode のリジッドボディでは動作しません。その場合、標準のSpatialメソッドを使用する代わりに、アタッチされたメッシュノードを回転する必要があります。