Exemplo n.º 1
0
        public void ApplyExternalForce(IRigidBody rigidBody, float timeStep)
        {
            Vector3 currentGravity;
            rigidBody.GetGravity(out currentGravity);

            Vector3 buoyancy;
            Vector3.Negate(ref currentGravity, out buoyancy);

            var volume = rigidBody.CollisionBounds.Volume;
            buoyancy *= (Density * volume);

            rigidBody.ApplyForce(ref buoyancy);

            // 抗力 (D: Drag)
            //
            // D = (1 / 2) * P * V^2 * S * Cd
            //
            // P: 流体の密度 (浮力で用いる流体の密度と同じなので、このクラスでは Density)
            // V: 物体と流体の相対速度
            // S: 物体の代表面積 (ここでは簡易にするために衝突形状の全体の面積で代用)
            // Cd: 抗力係数 (算出が大変なようなので、このクラスでは任意の設定値として調整)

            Vector3 rigidBodyVelocity;
            rigidBody.GetVeclocity(out rigidBodyVelocity);

            // 相対速度
            //var relativeVelocity = Velocity - rigidBodyVelocity;
            var relativeVelocity = rigidBodyVelocity - Velocity;

            // 相対速度の二乗 (速度ベクトルの大きさの二乗)
            var v2 = relativeVelocity.LengthSquared();

            // 抗力
            var drag = Density * v2 * rigidBody.CollisionBounds.SurfaceArea * DragCoefficient;

            // 抗力の方向 (単位ベクトル)
            var direction = Velocity;
            if (direction.LengthSquared() != 0)
            {
                direction.Normalize();
            }
            var dragVector = direction * drag;

            rigidBody.ApplyForce(ref dragVector);
        }
        public void ApplyExternalForce(IRigidBody rigidBody, float timeStep)
        {
            Vector3 velocity;
            rigidBody.GetVeclocity(out velocity);

            // 重力方向に対して衝突があるかどうかを判定します。
            Vector3 gravity;
            character.RigidBody.GetGravity(out gravity);
            bool isStanding = character.CollisionBounds.IsCollidedForDirection(ref gravity);

            if (isStanding)
            {
                // 現在の速度から desiredVelocity までの速度の変化量。
                var dv = desiredVelocity - velocity;

                // 時間 accelerationInterval で速度 dv に到達するために必要な加速度。
                var acceleration = new Vector3();
                acceleration.X = dv.X / accelerationInterval;
                acceleration.Y = dv.Y / accelerationInterval;
                acceleration.Z = dv.Z / accelerationInterval;

                // 加速度と質量によりかかる力。
                var targetForce = rigidBody.Mass * acceleration;

                rigidBody.ApplyForce(targetForce);
            }
            else
            {
                if (!desiredVelocity.IsZero())
                {
                    // delta velocity
                    var dv = desiredVelocity - velocity;
                    // acceleration
                    var acceleration = new Vector3();
                    acceleration.X = dv.X / accelerationInterval;
                    acceleration.Z = dv.Z / accelerationInterval;

                    //
                    // 速度ベクトルが同じ方向であるほどに通常の加速度
                    // 反対方法であるほどに若干のブレーキをかける
                    //
                    Vector3 tryMoveVelocityUnit;
                    Vector3Extension.NormalizeSafe(ref desiredVelocity, out tryMoveVelocityUnit);
                    Vector3 currentVelocity = velocity;
                    Vector3 currentVelocityUnit;
                    Vector3Extension.NormalizeSafe(ref currentVelocity, out currentVelocityUnit);

                    float dot;
                    Vector3.Dot(ref tryMoveVelocityUnit, ref currentVelocityUnit, out dot);

                    //
                    // dot [-1, 1] -> factor [brake, 1] (brake < 1)
                    //
                    const float brake = 0.01f;
                    //
                    // dot の範囲を長さ 1 へ変更
                    //      dot / (1 - (-1))
                    // それを factor の範囲の長さへ変更
                    //      (dot / 2) * (1 - brake)
                    // その原点を factor の中心へ移動
                    //      (dot / 2) * (1 - brake) + (1 - (1 - brake) / 2)
                    // ゆえに
                    //      (dot * (1 - brake) + (1 + brake)) / 2
                    //
                    var factor = (dot * (1 - brake) + (1 + brake)) * 0.5f;
                    var targetForce = rigidBody.Mass * acceleration * factor;

                    // for jump
                    if (0 < desiredVelocity.Y)
                    {
                        var accelerationY = (desiredVelocity.Y - velocity.Y) / accelerationInterval;
                        targetForce.Y = rigidBody.Mass * accelerationY;
                    }

                    rigidBody.ApplyForce(targetForce);
                }
            }
        }