Пример #1
0
        //--------------------------------------------------------------
        #region Creation & Cleanup
        //--------------------------------------------------------------

        public WheelConstraint(ConstraintWheel wheel)
        {
            _wheel = wheel;

            _suspensionSpringConstraint = new Constraint1D();
            _suspensionLimitConstraint  = new Constraint1D();
            _sideConstraint             = new Constraint1D();
            _forwardConstraint          = new Constraint1D();
        }
Пример #2
0
    //--------------------------------------------------------------
    #region Creation & Cleanup
    //--------------------------------------------------------------

    public WheelConstraint(ConstraintWheel wheel)
    {
      _wheel = wheel;

      _suspensionSpringConstraint = new Constraint1D();
      _suspensionLimitConstraint = new Constraint1D();
      _sideConstraint = new Constraint1D();
      _forwardConstraint = new Constraint1D();
    }
Пример #3
0
        /// <summary>
        /// Sets the steering angles for a standard 4 wheel car.
        /// </summary>
        /// <param name="steeringAngle">The steering angle.</param>
        /// <param name="frontLeft">The front left wheel.</param>
        /// <param name="frontRight">The front right wheel.</param>
        /// <param name="backLeft">The back left wheel.</param>
        /// <param name="backRight">The back right wheel.</param>
        /// <remarks>
        /// In a real car, the steerable front wheels do not always have the same steering angle. Have a
        /// look at http://www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.html
        /// (section "Curves") for an explanation. The steering angle defines the angle of the inner
        /// wheel. The outer wheel is adapted. This works only for 4 wheels in a normal car setup.
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="frontLeft"/>, <paramref name="frontRight"/>, <paramref name="backLeft"/>, or
        /// <paramref name="backRight"/> is <see langword="null"/>.
        /// </exception>
        public static void SetCarSteeringAngle(float steeringAngle, ConstraintWheel frontLeft, ConstraintWheel frontRight, ConstraintWheel backLeft, ConstraintWheel backRight)
        {
            if (frontLeft == null)
            {
                throw new ArgumentNullException("frontLeft");
            }
            if (frontRight == null)
            {
                throw new ArgumentNullException("frontRight");
            }
            if (backLeft == null)
            {
                throw new ArgumentNullException("backLeft");
            }
            if (backRight == null)
            {
                throw new ArgumentNullException("backRight");
            }

            backLeft.SteeringAngle  = 0;
            backRight.SteeringAngle = 0;

            if (Numeric.IsZero(steeringAngle))
            {
                frontLeft.SteeringAngle  = 0;
                frontRight.SteeringAngle = 0;
                return;
            }

            ConstraintWheel inner, outer;

            if (steeringAngle > 0)
            {
                inner = frontLeft;
                outer = frontRight;
            }
            else
            {
                inner = frontRight;
                outer = frontLeft;
            }

            inner.SteeringAngle = steeringAngle;

            float backToFront = backLeft.Offset.Z - frontLeft.Offset.Z;
            float rightToLeft = frontRight.Offset.X - frontLeft.Offset.X;

            float innerAngle = Math.Abs(steeringAngle);
            float outerAngle = (float)Math.Atan2(backToFront, backToFront / Math.Tan(innerAngle) + rightToLeft);

            outer.SteeringAngle = Math.Sign(steeringAngle) * outerAngle;
        }
Пример #4
0
        private static void UpdateWheelContactInfo(ConstraintWheel wheel, ContactSet contactSet)
        {
            if (contactSet != null && contactSet.HaveContact && contactSet.Count > 0)
            {
                // ----- Ray has contact.
                var contact = contactSet[0];

                wheel.HasGroundContact = true;
                wheel.GroundPosition   = contact.Position;
                if (wheel.CollisionObject == contactSet.ObjectA)
                {
                    wheel.GroundNormal = -contact.Normal;
                    wheel.TouchedBody  = contactSet.ObjectB.GeometricObject as RigidBody;
                }
                else
                {
                    wheel.GroundNormal = contact.Normal;
                    wheel.TouchedBody  = contactSet.ObjectA.GeometricObject as RigidBody;
                }

                // If the ray is nearly parallel to the ground, then the contact is not
                // useful and we ignore it.
                Vector3F up          = wheel.Vehicle.Chassis.Pose.Orientation.GetColumn(1);
                float    normalDotUp = Vector3F.Dot(wheel.GroundNormal, up);
                if (Numeric.IsGreater(normalDotUp, 0))
                {
                    wheel.Tag = 1; // Tag = 1 means that this wheel has a useful ground contact.

                    float hitDistance = contact.PenetrationDepth;
                    wheel.SuspensionLength = Math.Max(hitDistance - wheel.Radius, wheel.MinSuspensionLength);

                    wheel.Constraint.BodyB   = wheel.TouchedBody ?? wheel.Vehicle.Simulation.World;
                    wheel.Constraint.Enabled = true;

                    wheel.GroundRight   = wheel.Vehicle.Chassis.Pose.ToWorldDirection(Matrix33F.CreateRotationY(wheel.SteeringAngle) * Vector3F.UnitX);
                    wheel.GroundForward = Vector3F.Cross(wheel.GroundNormal, wheel.GroundRight).Normalized;
                }
            }
            else
            {
                // -----  The wheel is in the air.
                wheel.Constraint.Enabled = false;
                wheel.Constraint.BodyB   = wheel.Vehicle.Simulation.World;
                wheel.HasGroundContact   = false;
                wheel.TouchedBody        = null;
                wheel.SuspensionLength   = wheel.SuspensionRestLength;
            }
        }
Пример #5
0
    /// <summary>
    /// Sets the steering angles for a standard 4 wheel car.
    /// </summary>
    /// <param name="steeringAngle">The steering angle.</param>
    /// <param name="frontLeft">The front left wheel.</param>
    /// <param name="frontRight">The front right wheel.</param>
    /// <param name="backLeft">The back left wheel.</param>
    /// <param name="backRight">The back right wheel.</param>
    /// <remarks>
    /// In a real car, the steerable front wheels do not always have the same steering angle. Have a
    /// look at http://www.asawicki.info/Mirror/Car%20Physics%20for%20Games/Car%20Physics%20for%20Games.html
    /// (section "Curves") for an explanation. The steering angle defines the angle of the inner
    /// wheel. The outer wheel is adapted. This works only for 4 wheels in a normal car setup.
    /// </remarks>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="frontLeft"/>, <paramref name="frontRight"/>, <paramref name="backLeft"/>, or
    /// <paramref name="backRight"/> is <see langword="null"/>.
    /// </exception>
    public static void SetCarSteeringAngle(float steeringAngle, ConstraintWheel frontLeft, ConstraintWheel frontRight, ConstraintWheel backLeft, ConstraintWheel backRight)
    {
      if (frontLeft == null)
        throw new ArgumentNullException("frontLeft");
      if (frontRight == null)
        throw new ArgumentNullException("frontRight");
      if (backLeft == null)
        throw new ArgumentNullException("backLeft");
      if (backRight == null)
        throw new ArgumentNullException("backRight");

      backLeft.SteeringAngle = 0;
      backRight.SteeringAngle = 0;

      if (Numeric.IsZero(steeringAngle))
      {
        frontLeft.SteeringAngle = 0;
        frontRight.SteeringAngle = 0;
        return;
      }

      ConstraintWheel inner, outer;
      if (steeringAngle > 0)
      {
        inner = frontLeft;
        outer = frontRight;
      }
      else
      {
        inner = frontRight;
        outer = frontLeft;
      }

      inner.SteeringAngle = steeringAngle;

      float backToFront = backLeft.Offset.Z - frontLeft.Offset.Z;
      float rightToLeft = frontRight.Offset.X - frontLeft.Offset.X;

      float innerAngle = Math.Abs(steeringAngle);
      float outerAngle = (float)Math.Atan2(backToFront, backToFront / Math.Tan(innerAngle) + rightToLeft);

      outer.SteeringAngle = Math.Sign(steeringAngle) * outerAngle;
    }
Пример #6
0
    private static void UpdateWheelVelocity(float deltaTime, ConstraintVehicle vehicle, ConstraintWheel wheel)
    {
      if (wheel.Tag == 1)
      {
        wheel.Tag = 0;

        if (Numeric.IsZero(wheel.BrakeForce))
        {
          // We set the angular velocity, so that the wheel matches the moving underground.
          Vector3F relativeContactVelocity = vehicle.Chassis.GetVelocityOfWorldPoint(wheel.GroundPosition)
                                             - wheel.TouchedBody.GetVelocityOfWorldPoint(wheel.GroundPosition);
          float forwardVelocity = Vector3F.Dot(relativeContactVelocity, wheel.GroundForward);
          wheel.AngularVelocity = forwardVelocity / wheel.Radius;
          wheel.RotationAngle += wheel.AngularVelocity * deltaTime;
        }
        else
        {
          // Braking wheels do not rotate.
          wheel.AngularVelocity = 0;
        }
      }
      else
      {
        // To keep it simple: The wheel continues spinning in the same direction.
        // Damp angular velocity and update rotation angle.
        wheel.AngularVelocity *= 0.99f;
        wheel.RotationAngle += wheel.AngularVelocity * deltaTime;
      }
    }
Пример #7
0
    private static void UpdateWheelContactInfo(ConstraintWheel wheel, ContactSet contactSet)
    {
      if (contactSet != null && contactSet.HaveContact && contactSet.Count > 0)
      {
        // ----- Ray has contact.
        var contact = contactSet[0];

        wheel.HasGroundContact = true;
        wheel.GroundPosition = contact.Position;
        if (wheel.CollisionObject == contactSet.ObjectA)
        {
          wheel.GroundNormal = -contact.Normal;
          wheel.TouchedBody = contactSet.ObjectB.GeometricObject as RigidBody;
        }
        else
        {
          wheel.GroundNormal = contact.Normal;
          wheel.TouchedBody = contactSet.ObjectA.GeometricObject as RigidBody;
        }

        // If the ray is nearly parallel to the ground, then the contact is not
        // useful and we ignore it.
        Vector3F up = wheel.Vehicle.Chassis.Pose.Orientation.GetColumn(1);
        float normalDotUp = Vector3F.Dot(wheel.GroundNormal, up);
        if (Numeric.IsGreater(normalDotUp, 0))
        {
          wheel.Tag = 1; // Tag = 1 means that this wheel has a useful ground contact.

          float hitDistance = contact.PenetrationDepth;
          wheel.SuspensionLength = Math.Max(hitDistance - wheel.Radius, wheel.MinSuspensionLength);

          wheel.Constraint.BodyB = wheel.TouchedBody ?? wheel.Vehicle.Simulation.World;
          wheel.Constraint.Enabled = true;

          wheel.GroundRight = wheel.Vehicle.Chassis.Pose.ToWorldDirection(Matrix33F.CreateRotationY(wheel.SteeringAngle) * Vector3F.UnitX);
          wheel.GroundForward = Vector3F.Cross(wheel.GroundNormal, wheel.GroundRight).Normalized;
        }
      }
      else
      {
        // -----  The wheel is in the air.          
        wheel.Constraint.Enabled = false;
        wheel.Constraint.BodyB = wheel.Vehicle.Simulation.World;
        wheel.HasGroundContact = false;
        wheel.TouchedBody = null;
        wheel.SuspensionLength = wheel.SuspensionRestLength;
      }
    }
Пример #8
0
        private static void UpdateWheelVelocity(float deltaTime, ConstraintVehicle vehicle, ConstraintWheel wheel)
        {
            if (wheel.Tag == 1)
            {
                wheel.Tag = 0;

                if (Numeric.IsZero(wheel.BrakeForce))
                {
                    // We set the angular velocity, so that the wheel matches the moving underground.
                    Vector3F relativeContactVelocity = vehicle.Chassis.GetVelocityOfWorldPoint(wheel.GroundPosition)
                                                       - wheel.TouchedBody.GetVelocityOfWorldPoint(wheel.GroundPosition);
                    float forwardVelocity = Vector3F.Dot(relativeContactVelocity, wheel.GroundForward);
                    wheel.AngularVelocity = forwardVelocity / wheel.Radius;
                    wheel.RotationAngle  += wheel.AngularVelocity * deltaTime;
                }
                else
                {
                    // Braking wheels do not rotate.
                    wheel.AngularVelocity = 0;
                }
            }
            else
            {
                // To keep it simple: The wheel continues spinning in the same direction.
                // Damp angular velocity and update rotation angle.
                wheel.AngularVelocity *= 0.99f;
                wheel.RotationAngle   += wheel.AngularVelocity * deltaTime;
            }
        }