void FixedUpdate()
    {
        // see if there is a controller script active and if so take input from it
        float inputX = 0.0f;
        float inputY = 0.0f;
        float inputR = 0.0f;
        float inputH = 0.0f;

        if (userInput != null)
        {
            if (userInput.enabled)
            {
                inputX = userInput.ControllerInputX;
                inputY = userInput.ControllerInputY;
                inputR = userInput.ControllerInputReverse;
                inputH = userInput.ControllerInputHandBrake;
            }
        }

        // calculate vehicle velocity in the forward direction
        vel = transform.InverseTransformDirection(rB.velocity).z;

        // update aerodynamic drag and lift
        aeroDynamics.ApplyAeroDrag(vel);
        aeroDynamics.ApplyAeroLift(vel);

        // update steering angle due to input, correct for ackermann and apply steering (if we have a steering script)
        steerAngle       = steering.SteerAngle(vel, inputX, steerAngle);
        wC[2].steerAngle = steering.AckerAdjusted(steerAngle, suspension.GetWheelBase, suspension.GetTrackFront, true);
        wC[3].steerAngle = steering.AckerAdjusted(steerAngle, suspension.GetWheelBase, suspension.GetTrackFront, false);


        // update lateral load transfer from anti-roll bars (sway bars)
        suspension.ApplyLLT();

        // if automatic, select gear appropriate for vehicle speed (unless reverse requested)
        if (transmission.GetAutomatic)
        {
            if (inputR > 0.1)
            {
                transmission.SelectReverse();
            }
            else
            {
                transmission.SetGear(suspension.GetNoSlipWheelRPM(vel), engine.GetEngineRPMMaxPower);
            }
        }

        // update engine rpm and available torque
        float transmissionRatio   = 1.0f;
        float engineClutchLockRPM = 0.0f;
        float engineTorque        = 0.0f;

        transmissionRatio   = transmission.GetTransmissionRatio();
        engineClutchLockRPM = transmission.GetEngineClutchLockRPM;
        engine.UpdateEngineSpeedRPM(suspension.GetNoSlipWheelRPM(vel), inputY, transmissionRatio, engineClutchLockRPM);
        engineTorque = engine.GetMaxEngineTorque();

        // get requested engine torque
        if (inputY > 0.2f)
        {
            engineTorque = engineTorque * inputY;
        }
        else
        {
            engineTorque = 0.0f;
        }

        // get requested wheel torques
        float[] wheelTorques = transmission.GetWheelTorques(engineTorque);

        // get traction control torque updates
        // if you want to add a traction control module, this would be a good place to use it

        // get requested brake torques
        float[] brakeTorques = brakes.GetBrakeTorques(inputY);

        // if handbrake is on, brake rear wheels
        if (inputH > 0.1f)
        {
            brakes.ApplyHandbrake(brakeTorques);
        }

        // Calculate a wheel rpm limit based on engine limit and transmission
        float wheelRPMLimit = Mathf.Abs(engine.GetEngineRPMMax / transmission.GetTransmissionRatio()) * 1.01f;

        // check if wheel should be hitting engine rpm limit, if so, cut power to prevent over revving of wheel
        int iDrivenWheelID;

        for (int j = 0; j < transmission.GetDrivenWheels.Count; j++)
        {
            iDrivenWheelID = transmission.GetDrivenWheels[j];
            if (wC[transmission.GetDrivenWheels[j]].rpm > wheelRPMLimit)
            {
                wheelTorques[iDrivenWheelID] = 0.0f;
            }
        }

        // update brake and motor torques on wheel colliders
        // RL RR FL FR
        // initialise all to 0.0f
        for (int i = 0; i < 4; i++)
        {
            wC[i].brakeTorque = brakeTorques[i];
            wC[i].motorTorque = wheelTorques[i];
        }
    }