XNA JigLibX Vehicle Class Modifications by Nikescar

Proper Hand Brake
       The standard vehicle class has a hand brake that locks the rear wheels, thereby creating some drag and slowing the car down. That part is realistic. What isn't realistic is the rear wheels still have full traction. If you've ever pulled a hand brake in a car while moving you've notice that the rear end loses traction and wants to swing around causing a spin. It can be useful for making tight 180 degree turns, orienting your car coming into a turn and for good 'ol fashioned fun.

We'll have to start out by adding to Car.cs (changes/additions commented "new")

namespace JigLibX.Vehicles
{

    public class Car
    {
        enum WheelId
        {
            WheelBR = 0,
            WheelFR = 1,
            WheelBL = 2,
            WheelFL = 3,
            MaxWheels = 4
        }
        #region private fields
        private Chassis chassis;
        private List wheels; 

        private bool fWDrive;
        private bool bWDrive;
        private float maxSteerAngle;
        private float steerRate;
        private float wheelFSideFriction; // new
        private float wheelRSideFriction; // new
        private float wheelFwdFriction;
        private float wheelRwdFriction; // new
        private float wheelTravel;
        private float wheelRadius;
        private float wheelZOffset;
        private float wheelRestingFrac;
        private float wheelDampingFrac;
        private int wheelNumRays;
        private float driveTorque;
        private float gravity;

        // control stuff
        private float destSteering = 0.0f; // +1 for left, -1 for right
        private float destAccelerate = 0.0f; // +1 for acc, -1 for brake

        private float steering = 0.0f;
        private float accelerate = 0.0f;
        private float hBrake = 0.0f;

        #endregion

        /// On construction the physical/collision objects are created, but
        /// not registered
        // new
        public Car(bool FWDrive, bool RWDrive, float maxSteerAngle, float steerRate, float wheelFSideFriction, float wheelRSideFriction,
             float wheelFwdFriction, float wheelRwdFriction, float wheelTravel, float wheelRadius, float wheelZOffset, float wheelRestingFrac,
             float wheelDampingFrac, int wheelNumRays, float driveTorque, float gravity)
        // new
        {
            this.fWDrive = FWDrive;
            this.bWDrive = RWDrive;
            this.maxSteerAngle = maxSteerAngle;
            this.steerRate = steerRate;
            this.wheelFSideFriction = wheelFSideFriction; // new
            this.wheelRSideFriction = wheelRSideFriction; // new
            this.wheelFwdFriction = wheelFwdFriction;
            this.wheelRwdFriction = wheelRwdFriction; // new
            this.wheelTravel = wheelTravel;
            this.wheelRadius = wheelRadius;
            this.wheelZOffset = wheelZOffset;
            this.wheelRestingFrac = wheelRestingFrac;
            this.wheelDampingFrac = wheelDampingFrac;
            this.wheelNumRays = wheelNumRays;
            this.driveTorque = driveTorque;
            this.gravity = gravity;

            chassis = new Chassis(this);

            SetupDefaultWheels();
        }


More changes...

wheels[(int)WheelId.WheelBR].Setup(this,
                          BRPos,
                          axis,
                          spring,
                          wheelTravel,
                          inertia,
                          wheelRadius,
                          wheelRSideFriction, // new
                          wheelRwdFriction, // new
                          damping,
                          wheelNumRays);

            wheels[(int)WheelId.WheelFR].Setup(this,
                          FRPos,
                          axis,
                          spring,
                          wheelTravel,
                          inertia,
                          wheelRadius,
                          wheelFSideFriction,
                          wheelFwdFriction,
                          damping,
                          wheelNumRays);

            wheels[(int)WheelId.WheelBL].Setup(this,
                          BLPos,
                          axis,
                          spring,
                          wheelTravel,
                          inertia,
                          wheelRadius,
                          wheelRSideFriction, // new
                          wheelRwdFriction, // new
                          damping,
                          wheelNumRays);

            wheels[(int)WheelId.WheelFL].Setup(this,
                          FLPos,
                          axis,
                          spring,
                          wheelTravel,
                          inertia,
                          wheelRadius,
                          wheelFSideFriction,
                          wheelFwdFriction,
                          damping,
                          wheelNumRays);
        }


and some more additions...

wheels[(int)WheelId.WheelBL].Lock = (hBrake > 0.5f);
            wheels[(int)WheelId.WheelBR].Lock = (hBrake > 0.5f);          

            // new
            if (hBrake > 0.5f)
            {
                wheels[(int)WheelId.WheelBL].Side = 2.0f;
                wheels[(int)WheelId.WheelBR].Side = 2.0f;
            }
            else
            {
                wheels[(int)WheelId.WheelBL].Side = this.wheelRSideFriction;
                wheels[(int)WheelId.WheelBR].Side = this.wheelRSideFriction;
            }
            // new

I'll talk about the 2.0f later.


Now for some similar changes in CarObject.cs

namespace JiggleGame.PhysicObjects
{
    class CarObject : PhysicObject
    {

        private Car car;
        private Model wheel;

        public CarObject(Game game, Model model,Model wheels, bool FWDrive,
                       bool RWDrive,
                       float maxSteerAngle,
                       float steerRate,
                       float wheelFSideFriction, // new
                       float wheelRSideFriction, // new
                       float wheelFwdFriction,
                       float wheelRwdFriction, // new
                       float wheelTravel,
                       float wheelRadius,
                       float wheelZOffset,
                       float wheelRestingFrac,
                       float wheelDampingFrac,
                       int wheelNumRays,
                       float driveTorque,
                       float gravity)
            : base(game, model)
        {
            // new
            car = new Car(FWDrive, RWDrive, maxSteerAngle, steerRate,
                wheelFSideFriction, wheelRSideFriction, wheelFwdFriction,  
                wheelRwdFriction, wheelTravel, wheelRadius,
                wheelZOffset, wheelRestingFrac, wheelDampingFrac,
                wheelNumRays, driveTorque, gravity);
            // new

            this.body = car.Chassis.Body;
            this.collision = car.Chassis.Skin;
            this.wheel = wheels;

            SetCarMass(100.0f);
        }


And the Wheel.cs

public bool Lock
        {
            get { return locked; }
            set { locked = value; }
        }
        // new
        public float Side
        {
            get { return sideFriction; }
            set { sideFriction = value; }
        }
        // new

That should almost do it. Get some speed then turn hard and press 'b' (or whatever you have it mapped to) to see the improved hand brake.


Adding Tuning Capabilities 
       A bonus to all this work for the hand brake is you now have a lot more freedom to fine tune your car. Instead of having to change friction of all four tires you can change the front and rear seperately to get a car that drifts or handles however you want.

Open JiggleGame.cs and paste the following in place of the old variables

carObject = new CarObject(this, carModel, wheelModel, true, true, 30.0f, 5.0f, 3.6f, 2.6f,
                .5f, 1f, 0.3f, 0.4f, -0.10f, 0.5f,
                0.9f, 1, 400.0f, physicSystem.Gravity.Length());

These settings should be a fun place to start. You'll also notice that some of these settings give the car body roll which not only looks better but is more realistic.

This setup is a little more drift car like:

carObject = new CarObject(this, carModel, wheelModel, true, true, 30.0f, 5.0f, 3.6f, 3.0f,
                .5f, 1f, 0.20f, 0.4f, 0.05f, 0.5f,
                0.9f, 1, 400.0f, physicSystem.Gravity.Length());

Keep in mind that you likely won't be able to keep a drift if you're using the keyboard.

3.6f is the front lateral friction and 2.6f is the rear. These settings will make the rear slide out when taking a corner to fast. If they are even the car will never spin out.

.5f is the front longitudinal (I think that's what it's called or acceleration, should've gone to college) friction and 1f is the rear. Having a bigger number in the rear let's you keep a drift around corners.

Both these settings are proportional between the front and rear so 4f in front and 3f in rear will handle pretty similar to 5f in front and 3.75f in rear. Play with these till you get them where you want.

Now back to the 2.0f. This adjusts the lateral friction everytime the hand brake is activated letting the rear end slide around. Since it doesn't adjust the longitudinal friction the locked tires still create the same amount of drag as before.

Next time I'll go into what all the CarObject settings do as well as a few new tweaks to the car class.


I hope this helps someone.