示例#1
0
        public WheelConstraint(ConstraintWheel wheel)
        {
            _wheel = wheel;

            _suspensionSpringConstraint = new Constraint1D();
            _suspensionLimitConstraint  = new Constraint1D();
            _sideConstraint             = new Constraint1D();
            _forwardConstraint          = new Constraint1D();
        }
示例#2
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;
        }
示例#3
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.
                Vector3 up          = wheel.Vehicle.Chassis.Pose.Orientation.GetColumn(1);
                float   normalDotUp = Vector3.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(Matrix.CreateRotationY(wheel.SteeringAngle) * Vector3.UnitX);
                    wheel.GroundForward = Vector3.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;
            }
        }
示例#4
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.
                    Vector3 relativeContactVelocity = vehicle.Chassis.GetVelocityOfWorldPoint(wheel.GroundPosition)
                                                      - wheel.TouchedBody.GetVelocityOfWorldPoint(wheel.GroundPosition);
                    float forwardVelocity = Vector3.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;
            }
        }