I love the smell of UnrealEd crashing in the morning. – tarquin

Legacy:Manual Shift Car

From Unreal Wiki, The Unreal Engine Documentation Site

Jump to: navigation, search

Contents

Breakdown

This is a convertion of ONSWheeledCraft. This class allows for a stick shift or otherwise known as a manual transmission car. Why stick shift?

  • It doesn't cost much in terms of fps
  • Lets you rev it in neutral :)
  • Fun to drive
  • Will allow rear/front/all wheel drive
  • Holding the brake and the rear wheels keep spinning (no rear brakes)
  • I hope you can use what I (CIpen) have created

The Goods

To start the class off

class WheeledClutch_Brake extends ONSVehicle;

Critical variables

var() float             WheelSoftness;
var() float             WheelPenScale;
var() float             WheelPenOffset;
var() float             WheelRestitution;
var() float             WheelAdhesion;
var() float             WheelInertia;   // I believe this is how much to resist change in motion
 
    //I(CIpen) made these an array so we could have different slips on each surface
var() array<float>         WheelLongSlip; // I think this is so we can have the wheels slip when you take off
var() array<InterpCurve>   WheelLongFrictionFunc;//this is the curve for how slippery the wheels are allong the X axis(forwards slip)
var() array<InterpCurve>   WheelLatSlipFunc;//this is the curve for how slippery the wheels are allong the Y axis(left/right slip)
var() array<float>         WheelLongFrictionScale;  // quick way to change the ammount of friction without having to draw out
var() array<float>         WheelLatFrictionScale;   // a new friction curve
 
var() float                             WheelHandbrakeSlip;
var() float                             WheelHandbrakeFriction;
var() float                             WheelSuspensionTravel;
var() float                             WheelSuspensionOffset;
var() float                             WheelSuspensionMaxRenderTravel;   
var() float                             FTScale;
var() float                             ChassisTorqueScale;
var() float                             MinBrakeFriction;
var() InterpCurve                       MaxSteerAngleCurve; // degrees, this makes the wheels turn like real car wheels*
var() float                             GearRatios[8];  // 0 is reverse, 1-4 f
var() int                               NumForwardGears;
var() float                             TransRatio;   // Other(constant)gears  i.e. so we can have driveshaft ratio(if one applies)
var() float                             ChangeUpPoint;   //EngineRPM that signals gear up change
var() float                             ChangeDownPoint; //EngineRPM that signals gear down change
 
var   int                               bGearUp;
var   int                               bGearDown;
 
var() float                             LSDFactor;                                                                                    
var() float                             EngineBrakeFactor;
var() float                             EngineBrakeRPMScale;                                                                                     
var() float                             MaxBrakeTorque;
var() float                             SteerSpeed;         // How fast it turns         
var() float                             TurnDamping;                                                                                    
var() float                             StopThreshold;
var() float                             HandbrakeThresh;                                                                                     
var() float                             EngineInertia;     // Pre-gear box engine (piston mass)
var   bool                              bClutching;        // If holding the clutch
var   bool                              bOldClutching;  
var() float                             IdleRPM;              //RPM to idle at
var() float                             EngineRPMSoundRange;   //RPM sound range
var() name                              SteerBoneName;
var() EAxis                             SteerBoneAxis;
var() float                             SteerBoneMaxAngle; // degrees                                                                                     
 
var   float                             OutputBrake;    //How much we are braking
var   float                             OutputGas;      //How much are we giving gas
var   float                             OutputPitch;
var   bool                              OutputHandbrake;
 
var   int                               Gear;           //What gear we are in
var   float                             ForwardVel;
var   bool                              bIsInverted;
var   bool                              bIsDriving;
var   float                             NumPoweredWheels;
var   float                             NeutralRPM;
 
var   InterpCurve                       RPMtoGas;           // This is what I use to convert the current in gear RPM to the amount of gas so the RPM doesn't go to zero when we hit the clutch
var() InterpCurve                       TorqueCurve;        // Engine output torque
var() InterpCurve                       EngineS;
var() InterpCurve                       BrakeCurve;     //This simulates more lifelike braking, where you apply braking
 
var   float                             Gas, Gas2, hBrake;
 
var   float                             RPM2;    //Neutral RPM
var   float                             RPM;     //Neutral RPM
var   float                             NRPM;
var   bool                              bBraking;   //if we are braking
var   bool                              bThrot, bNThrot, bNoGas;
var   bool                              bInGear;          //if we are completly in gear
var   bool                              bRadians;
var   float                             TotalSpinVel;
var   float                             EngineRPM;
var   float                             WheelRPM;// used to get the wheel RPM at anytime(so we don't change EngineRPM which is what the engine sound is tied to)
var   float                             CarMPH;
var   float                             ETorque;
var   float                             ActualSteering;
var   float                             SteerBoneAngle;
var   float                             EnginePitch;
var   Vector                            worldForward;
var   Vector                            worldRight;
var   Vector                            worldUp;
var   Matrix                            carTM;
var   Rotator                           SteerRot;
var   bool                              bCurrentOnGround;
var   float                             DeltaPitch;
var   float                             DeltaHeading;
var   float                             DeltaRoll;
var   float                             VRate;
 
var   vector                            one, two, three;
var   vector                            Dist1, Dist2;     // unused but this was for doing the daredevil stuff
var   float                             Dist3;
var   bool                              bBrakeFrontWheelsOnly, bBrakeFrontWheels;
var   Vector                            UDForce, UDTorque;
var   Vector                            WForce, WTorque;
var   Coords                            WheelCoords;
var   Coords                            OldCoords;
var   Coords                            Coords;
var   Vector                            ForwardsInOldPlane;
var   Pawn                              OldDriver;        
 
struct native SCarState
{
          var vector                    ChassisPosition;                               
          var Quat                      ChassisQuaternion;                             
          var vector                    ChassisLinVel;                                 
          var vector                    ChassisAngVel;                                 
 
          var byte                      ServerHandbrake;                               
          var byte                      ServerBrake;                                   
          var byte                      ServerGas;                                     
          var byte                      ServerGear;                                    
          var byte                      ServerSteering;
          var int                       ServerViewPitch;
          var int                       ServerViewYaw;
};
 
var   byte                     FudgeByte;                                                                                     
var   SCarState                CarState;                                      
var   SCarState                OldCarState;
var   KRigidBodyState          ChassisState;                                  
var   bool                     bNewCarState;                                                                                    
var   bool                     bOldVehicleOnGround;
var   float                    TheDeltaTime;

Not so critical variables

var   class<CameraEffect>           myBlur;
var   myMotionBlur                  ClientMotionBlur;
 
var   array<ONSDirtSlipEffect>          Dust; // FL, FR, RL, RR
var() float                             DustSlipRate;
var() float                             DustSlipThresh;
var() float                         RevMeterPosX;
var() float                         RevMeterPosY;
var() float                         RevMeterScale;
var() float                         RevMeterSizeY;
 
var() bool                          bDoStuntInfo;
var() bool                          bAllowAirControl;
var() bool                          bAllowChargingJump;
var   bool                            bAllowBigWheels;
 
var   bool                            bPushDown; //jump is being charged
var   bool                          bOldPushDown;
var   bool                          bAllWheelsOnGround;
 
var() float                         MaxJumpForce;
var   float                         JumpForce;
var() float                         MaxJumpSpin;
var   float                         JumpSpin;
 
var() float                         JumpChargeTime;
var   float                           DesiredJumpForce; //used by AI
var   string                  JumpFeedbackForce;                             
 
var   sound                          JumpSound;
 
var() float                         JumpMeterOriginX;
var() float                         JumpMeterOriginY;
var() float                         JumpMeterWidth;
var() float                         JumpMeterHeight;
var() float                         JumpMeterSpacing;
var() color                         JumpMeterColor;
var() color                         SpinMeterColor;
var   Texture                        JumpMeterTexture;                              
 
var() float                         AirTurnTorque;
var() float                         AirPitchTorque;
var() float                         AirPitchDamping;
var() float                         AirRollTorque;
var() float                         AirRollDamping;
var() float                         MinAirControlDamping;                                                                                    
var   float                           FenderBenderSpeed;
 
var() bool                          bMakeBrakeLights;
var() vector                               BrakeLightOffset[2];                           
var   ONSBrakelightCorona              BrakeLight[2];                                 
var() Material                           BrakeLightMaterial;                            
 
var   Rotator                 OldRotation;
var   Vector                  LastOnGroundLocation;                          
var   float                           LastOnGroundTime;
 
var   float                           InAirSpin; // Degrees
var   float                           InAirPitch; // Degrees
var   float                           InAirRoll; // Degrees
var   float                           InAirTime; // Second
var   float                           InAirDistance; // Meters
var   int                             DaredevilPoints;
var   config int                    IntSteerBoneAngle;
 
var() float                         DaredevilThreshInAirSpin;                      
var() float                         DaredevilThreshInAirPitch;
var() float                         DaredevilThreshInAirRoll;
var() float                         DaredevilThreshInAirTime;
var() float                         DaredevilThreshInAirDistance;
var() class<LocalMessage>              DaredevilMessageClass;

Replication =

replication
{
        reliable if (Role == ROLE_Authority)
                CarState, FudgeByte;                       // make sure we get what we need to the client
        reliable if (bNetInitial && Role == ROLE_Authority)
                bAllowAirControl, bAllowChargingJump;        // showoff stuff
        reliable if (bNetInitial && bDoStuntInfo && Role == ROLE_Authority)
                DaredevilThreshInAirDistance, DaredevilThreshInAirTime, DaredevilThreshInAirSpin, DaredevilThreshInAirPitch, DaredevilThreshInAirRoll;
}

Functions

PostNetBeginPlay
simulated function PostNetBeginPlay()
{
        local int i;
        NumPoweredWheels = 0.0;
        for(i=0; i<=1; i++)
        {
                NumPoweredWheels += 1.0;
        }
       SVehicleUpdateParams();
       Super.PostNetBeginPlay();
}
PostNetReceive 
Here is were we deal with stuff coming from the server.
simulated function PostNetReceive()
{
        Super.PostNetReceive();
 
        if(OldCarState.ChassisPosition == CarState.ChassisPosition &&
                OldCarState.ChassisQuaternion.X == CarState.ChassisQuaternion.X &&
                OldCarState.ChassisQuaternion.Y == CarState.ChassisQuaternion.Y &&
                OldCarState.ChassisQuaternion.Z == CarState.ChassisQuaternion.Z &&
                OldCarState.ChassisQuaternion.W == CarState.ChassisQuaternion.W &&
                OldCarState.ChassisLinVel == CarState.ChassisLinVel &&
                OldCarState.ChassisAngVel == CarState.ChassisAngVel &&
                OldCarState.ServerHandbrake == CarState.ServerHandbrake &&
                OldCarState.ServerBrake == CarState.ServerBrake &&
                OldCarState.ServerGas == CarState.ServerGas &&
                OldCarState.ServerGear == CarState.ServerGear &&
                OldCarState.ServerSteering == CarState.ServerSteering &&
                OldCarState.ServerViewPitch == CarState.ServerViewPitch &&
                OldCarState.ServerViewYaw == CarState.ServerViewYaw)
                return;
 
        ChassisState.Position.X = CarState.ChassisPosition.X;
        ChassisState.Position.Y = CarState.ChassisPosition.Y;
        ChassisState.Position.Z = CarState.ChassisPosition.Z;
 
        ChassisState.Quaternion = CarState.ChassisQuaternion;
 
        ChassisState.LinVel.X = 0.1f * CarState.ChassisLinVel.X;
        ChassisState.LinVel.Y = 0.1f * CarState.ChassisLinVel.Y;
        ChassisState.LinVel.Z = 0.1f * CarState.ChassisLinVel.Z;
 
        ChassisState.AngVel.X = 0.001f * CarState.ChassisAngVel.X;
        ChassisState.AngVel.Y = 0.001f * CarState.ChassisAngVel.Y;
        ChassisState.AngVel.Z = 0.001f * CarState.ChassisAngVel.Z;
 
        bNewCarState = true;
        OldCarState.ChassisPosition = CarState.ChassisPosition;
        OldCarState.ChassisQuaternion = CarState.ChassisQuaternion;
        OldCarState.ChassisLinVel = CarState.ChassisLinVel;
        OldCarState.ChassisAngVel = CarState.ChassisAngVel;
        OldCarState.ServerHandbrake = CarState.ServerHandbrake;
        OldCarState.ServerBrake = CarState.ServerBrake;
        OldCarState.ServerGas = CarState.ServerGas;
        OldCarState.ServerGear = CarState.ServerGear;
        OldCarState.ServerSteering = CarState.ServerSteering;
        OldCarState.ServerViewPitch = CarState.ServerViewPitch;
        OldCarState.ServerViewYaw = CarState.ServerViewYaw;
 
        OutputPitch = RangeByteToFloat(CarState.ServerHandbrake);
        OutputHandbrake = (OutputPitch > 0.01);
        OutputBrake = RangeByteToFloat(CarState.ServerBrake);
        OutputGas = RangeByteToFloat(CarState.ServerGas);
        Gear = CarState.ServerGear;
        Steering = RangeByteToFloat(CarState.ServerSteering);
        DriverViewPitch = CarState.ServerViewPitch;
        DriverViewYaw = CarState.ServerViewYaw;
}
PrecacheAnnouncer
simulated function PrecacheAnnouncer(AnnouncerVoice V, bool bRewardSounds)
{
 
        if (bRewardSounds && !bSoundsPrecached)
                V.PrecacheSound('fender_bender');
 
        Super.PrecacheAnnouncer(V, bRewardSounds);
}
KUpdateState 
This function tells when we should update.
event bool KUpdateState(out KRigidBodyState newState)
{
        if(Role == ROLE_Authority || !bNewCarState)
                return false;
 
        newState = ChassisState;
        bNewCarState = false;
        return true;
}
SVehicleUpdateParams
event SVehicleUpdateParams()
{
        local int i;
 
        Super.SVehicleUpdateParams();
 
        for(i=0; i<Wheels.Length; i++)
        {
                Wheels[i].Softness = WheelSoftness;
                Wheels[i].PenScale = WheelPenScale;
                Wheels[i].PenOffset = WheelPenOffset;
                Wheels[i].LongSlip = WheelLongSlip[0];
                Wheels[i].LatSlipFunc = WheelLatSlipFunc[0];
                Wheels[i].Restitution = WheelRestitution;
                Wheels[i].Adhesion = WheelAdhesion;
                Wheels[i].WheelInertia = WheelInertia;
                Wheels[i].LongFrictionFunc = WheelLongFrictionFunc[0];
                Wheels[i].HandbrakeFrictionFactor = WheelHandbrakeFriction;
                Wheels[i].HandbrakeSlipFactor = WheelHandbrakeSlip;
                Wheels[i].SuspensionTravel = WheelSuspensionTravel;
                Wheels[i].SuspensionOffset = WheelSuspensionOffset;
                Wheels[i].SuspensionMaxRenderTravel = WheelSuspensionMaxRenderTravel;
        }
        if(Level.NetMode != NM_DedicatedServer && bMakeBrakeLights)
        {
                for(i=0; i<2; i++)
                {
                     if (BrakeLight[i] != None)
                     {
                                BrakeLight[i].SetBase(None);
                                BrakeLight[i].SetLocation( Location + (BrakelightOffset[i] >> Rotation) );
                                BrakeLight[i].SetBase(self);
                                BrakeLight[i].SetRelativeRotation( rot(0,32768,0) );
                                BrakeLight[i].Skins[0] = BrakeLightMaterial;
                      }
                }
        }
}
UpdateVehicle 
This is the function were everything happens
          Also see Manual Shift Car/C++ Version
function UpdateVehicle(float DeltaTime)
{
        local Matrix carTM;
        local Vector worldUp, worldRight, worldForward;
 
        local KarmaParams KP;
        local KRigidBodyState rbState;
        local int   i;
        local float maxSteerAngle, maxSteer, deltaSteer;
        local float DriveTorque, GripTorque, EngineTorque, EngineBraking, EngineWheelRatio;
        local float BrakeTorque;
        local float NewTotalSpinVel, LSDSplit, EvenSplit, UseSplit;
        local float TransInertia;
        local float LimitBrakeTorque;
        local float WheelTorque, VehicleForce, TransAcc;
        local float TurnAngVel, DampingScale, TurnDampingMag;
        local float PitchAngVel, RollAngVel, PitchDampingMag, RollDampingMag;
 
        local Vector AirControlTorque, AngVel;
        local float  VRate;
        local Vector Force, Torque;
        local int z;
 
        WForce = vect(0, 0, 0);
        WTorque = vect(0, 0, 0);
 
        if(!KIsAwake())
                return;
        KP = KarmaParams(KParams);
        if(KP == None)
                return;
 
        if(Controller != None)
        {
              //Calc up (z), right(y) and forward (x) vectors
              GetAxes(Rotation, worldRight, worldForward, worldUp);
 
              /////////// STEERING ///////////
              maxSteerAngle = InterpCurveEval(MaxSteerAngleCurve, VRate);
              if(maxSteerAngle==0)
                    maxSteer = DeltaTime * SteerSpeed * maxSteerAngle;
              else
                    maxSteer = DeltaTime * SteerSpeed;
 
              deltaSteer = (-Steering * maxSteerAngle) - ActualSteering; // Amount we want to move (target - current)
              deltaSteer = Clamp(deltaSteer, -maxSteer, maxSteer);
              ActualSteering += deltaSteer;
 
              if(bAuto==True)
              {
                      EngineTorque = OutputGas * InterpCurveEval(TorqueCurve, EngineRPM);
                      EngineBraking = (1.0f - OutputGas) * (EngineBrakeRPMScale*EngineRPM * EngineBrakeRPMScale*EngineRPM * EngineBrakeFactor);
                      EngineTorque -= EngineBraking;
                      EngineWheelRatio = GearRatios[Gear] * TransRatio;
                      NewTotalSpinVel=0.0;
                      EngineRPM = 0.0;
                      for(i=0; i<Wheels.length; i++)
                      {
                              EvenSplit = 1/NumPoweredWheels;
                              if(TotalSpinVel > 0.1)
                                      LSDSplit = (TotalSpinVel - Wheels[i].SpinVel)/((NumPoweredWheels-1) * TotalSpinVel);
                              else
                                      LSDSplit = EvenSplit;
                              UseSplit = ((1-LSDFactor) * EvenSplit) + (LSDFactor * LSDSplit);
                              DriveTorque = UseSplit * (EngineTorque / EngineWheelRatio);
                              GripTorque = FTScale * Wheels[i].WheelRadius * Wheels[i].TireLoad * WheelLongFrictionScale[0] * InterpCurveEval(Wheels[i].LongFrictionFunc, Abs(Wheels[i].SlipVel));
                              if(Wheels[i].SlipVel < 0.0)
                                      GripTorque *= -1.0;
                              TransInertia = (EngineInertia / Abs(GearRatios[Gear] * TransRatio)) + Wheels[i].WheelInertia;
                              if(Wheels[i].SpinVel > 0.0)
                                      BrakeTorque = -OutputBrake * MaxBrakeTorque;
                              else
                                      BrakeTorque = OutputBrake * MaxBrakeTorque;
 
                              LimitBrakeTorque = ( Abs(Wheels[i].SpinVel) * TransInertia ) / TheDeltaTime; // Size of torque needed to completely stop wheel spinning.
                              BrakeTorque = Clamp(BrakeTorque, -LimitBrakeTorque, LimitBrakeTorque); // Never apply more than this!
                              WheelTorque = DriveTorque + BrakeTorque - GripTorque;
                              VehicleForce = GripTorque / (FTScale * Wheels[i].WheelRadius);
                              if( OutputBrake > 0.0 ||  (DriveTorque + BrakeTorque) * Wheels[i].SpinVel < 0.0)
                              {
                                      Wheels[i].DriveForce = 0.0;
                                      Wheels[i].LongFriction = Abs(VehicleForce) + (OutputBrake * MinBrakeFriction);
                              }
                              else
                              {
                                      Wheels[i].DriveForce = VehicleForce;
                                      Wheels[i].LongFriction = 0.0;
                              }
                              if (Wheels[i].bWheelOnGround)
                                      Wheels[i].ChassisTorque = -1.0 * (DriveTorque + BrakeTorque) * ChassisTorqueScale;
                               else
                                      Wheels[i].ChassisTorque = 0.0;
                              TransAcc = WheelTorque / TransInertia;
                              Wheels[i].SpinVel += TransAcc * DeltaTime;
                              if(Gear == 0 && Wheels[i].SpinVel > 0.0)
                                      Wheels[i].SpinVel = 0.0;
                              else if(Gear > 0 && Wheels[i].SpinVel < 0.0)
                                      Wheels[i].SpinVel = 0.0;
                              NewTotalSpinVel += Wheels[i].SpinVel;
                              EngineRPM += Wheels[i].SpinVel / EngineWheelRatio;
                              Wheels[i].LatFriction = WheelLatFrictionScale[0] * Wheels[i].TireLoad;
                              Wheels[i].LatSlip = InterpCurveEval(Wheels[i].LatSlipFunc, Wheels[i].SlipAngle);
                              if(OutputHandbrake && Wheels[i].bHandbrakeWheel)
                              {
                                      Wheels[i].LatFriction *= Wheels[i].HandbrakeFrictionFactor;
                                      Wheels[i].LatSlip *= Wheels[i].HandbrakeSlipFactor;
                              }
                              if(Wheels[i].SteerType == VST_Steered)
                                      Wheels[i].Steer = ActualSteering;
                              else if(Wheels[i].SteerType == VST_Inverted)
                                      Wheels[i].Steer = -ActualSteering;
                              else
                                      Wheels[i].Steer = 0.0;
                      }
                      EngineRPM /= NumPoweredWheels;
                      EngineRPM = Max(EngineRPM, 0.01); // ensure always positive!
                      TotalSpinVel = NewTotalSpinVel;
              }
///////////////STICK SHIFT///////////////////////////////
              else
              {
                   if(bClutching)
                   {
                        EngineTorque = InterpCurveEval(TorqueCurve, EngineRPM);
                   }
                   else
                   {
                        EngineTorque = InterpCurveEval(TorqueCurve, EngineRPM);
                        if(EngineTorque >= 0)
                        {
                                   // Calculate torque at output of engine. Combination of throttle, current RPM and engine braking.
                                EngineTorque = OutputGas * InterpCurveEval(TorqueCurve, EngineRPM);
                        }
                        else if(EngineTorque < 0)
                        {
                                EngineTorque = InterpCurveEval(TorqueCurve, EngineRPM);
                        }
 
                        EngineBraking = (1.0f - OutputGas) * (EngineBrakeRPMScale*EngineRPM * EngineBrakeRPMScale*EngineRPM * EngineBrakeFactor);
                   }
 
                  // EngineRPM = OutputGas * InterpCurveEval(RPMCurve, EngineTorque);
 
                   EngineTorque -= EngineBraking;
                   ETorque = EngineTorque;
                   //DebugInfo = FString::Printf(TEXT("OutputBrake: %f      EngineRPM: %f    EngineTorque: %f"), OutputBrake, EngineRPM, EngineTorque);
 
                   // Total gear ratio between engine and differential (ie before being split between wheels).
                   // A higher gear ratio and the torque at the wheels is reduced.
                   EngineWheelRatio = GearRatios[Gear] * TransRatio;
 
                   if(bClutching)
                   {
                        //EngineRPM = 0.0;
                        WheelRPM = 0.0;
                   }
                   else
                   {
                        if(Wheels[i].bPoweredWheel)
                        {
                             // Reset engine RPM. We calculate this by adding the component of each wheel spinning.
                             NewTotalSpinVel=0.0;
                             if(bInGear)
                             {
                                   WheelRPM = 0.0;
                                   EngineRPM = 0.0;
                             }
                             else if(!bInGear)
                                   WheelRPM = 0.0;
                        }
                   }
 
              // Do model for each wheel.
              //  Okay this needs to be fixed because the way this is, all the wheels get power
 
                   for(i=0;i<Wheels.length; i++)
                   {
                      //Wheels[i];
                      /////////// DRIVE ///////////
                      // Heuristic to divide torque up so that the wheels that are spinning slower get more of it.
                      // Sum of LSDFactor across all wheels should be 1.
                      // JTODO: Do we need to handle the case of vehicles with different size wheels?
 
                      EvenSplit = 1/NumPoweredWheels;
 
                      // If no wheels are spinning, just do an even split.
                      if(TotalSpinVel > 0.1)
                              LSDSplit = (TotalSpinVel - Wheels[i].SpinVel)/((NumPoweredWheels-1) * TotalSpinVel);
                      else
                              LSDSplit = EvenSplit;
 
                      UseSplit = ((1-LSDFactor) * EvenSplit) + (LSDFactor * LSDSplit);
 
                      if(bClutching)
                      {
                           EngineRPM = RPM;
 
                           //DriveTorque = UseSplit * (EngineTorque / EngineWheelRatio);
                      }
                      else
                      {
                           if(Wheels[i].bPoweredWheel)
                           {
                                //EngineRPM = RPM;
 
                                // Calculate Drive Torque : applied at wheels (ie after gearbox and differential)
                                // This is an 'open differential' ie. equal torque to each wheel
                                DriveTorque = UseSplit * (EngineTorque / EngineWheelRatio);
                           }
                      }
 
                      /////////// LONGITUDINAL ///////////
                      // Calculate Grip Torque : longitudinal force against ground * distance of action (radius of tyre)
                      // LongFrictionFunc is assumed to be reflected for negative Slip Ratio
                      GripTorque = FTScale * Wheels[i].WheelRadius * Wheels[i].TireLoad * WheelLongFrictionScale[0] * InterpCurveEval(Wheels[i].LongFrictionFunc, Abs(Wheels[i].SlipVel));
 
                      if(Wheels[i].SlipVel < 0.0)
                              GripTorque *= -1.0;
 
                      if(Wheels[i].bPoweredWheel)
                      {
                           // GripTorque can't be more than the torque needed to invert slip ratio.
                           TransInertia = (EngineInertia / Abs(GearRatios[Gear] * TransRatio)) + Wheels[i].WheelInertia;
                      }
 
                      //FLOAT SlipAngVel = Wheels[i].SlipVel/Wheels[i].WheelRadius;
 
                      if(bBraking)
                      {
                           // Brake torque acts to stop wheels (ie against direction of motion)
                           BrakeTorque = 0.0;
                           if(Wheels[i].SpinVel > 0.0)
                                BrakeTorque = -OutputBrake * MaxBrakeTorque;
                          else
                                BrakeTorque = OutputBrake * MaxBrakeTorque;
 
                           LimitBrakeTorque = ( Abs(Wheels[i].SpinVel) * TransInertia ) / TheDeltaTime; // Size of torque needed to completely stop wheel spinning.
                           BrakeTorque = Clamp(BrakeTorque, -LimitBrakeTorque, LimitBrakeTorque); // Never apply more than this!
                           mBrakeTorque = BrakeTorque;
                      }
                      else
                      {
                           BrakeTorque = 0;
                           mBrakeTorque = BrakeTorque;
                      }
//_____________________________________________
 
                      if(bClutching)
                      {
                              WheelTorque = GripTorque;
                              //Log("GripTorque");
                              //Log(GripTorque);
                      }
                      else     // we are in full gear
                      {
                           if(!Wheels[i].bPoweredWheel)
                           {
                              //Don't do this if 4 wheel drive!!!!
                              WheelTorque = GripTorque * 2;
                           }
                           else
                           {
                              // Resultant torque at wheel : torque applied from engine + brakes + equal-and-opposite from tire-road interaction.
                              WheelTorque = DriveTorque + BrakeTorque - GripTorque;
                          /*    Log("WheelTorque");
                              Log(WheelTorque);
                              Log("GripTorque");
                              Log(GripTorque);      */
                           }
                      }
//____________________________________________
 
                      // Resultant linear force applied to car. (GripTorque applied at road)
                      VehicleForce = GripTorque / (FTScale * Wheels[i].WheelRadius);
 
                      // If the wheel torque is opposing the direction of spin (ie braking) we use friction to apply it.
                      if( OutputBrake > 0 && bBraking)//  || (DriveTorque + BrakeTorque) * Wheels[i].SpinVel < 0.0
                      {
                              Wheels[i].DriveForce = 0.0;
                              Wheels[i].LongFriction = Abs(VehicleForce) + (OutputBrake * MinBrakeFriction);
                      }
                      else if(bClutching)
                      {
                              Wheels[i].DriveForce = 0.0;
                              Wheels[i].LongFriction = 0.0;
                      }
                      else
                      {
                              if(!Wheels[i].bPoweredWheel)
                              {
                                     Wheels[i].DriveForce = 0.0;
                                     Wheels[i].LongFriction = 0.0;
                              }
                              else
                              {
                                   Wheels[i].DriveForce = VehicleForce;
                                   Wheels[i].LongFriction = 0.0;
                                   //Wheels[i].LongFriction = 0.0;
                              }
                      }
 
 
                      if(Wheels[i].bPoweredWheel)
                      {
                           // Calculate torque applied back to chassis if wheel is on the ground
                           if (Wheels[i].bWheelOnGround)
                              Wheels[i].ChassisTorque = -1.0 * (DriveTorque + BrakeTorque) * ChassisTorqueScale;
                           else
                              Wheels[i].ChassisTorque = 0.0;
                      }
 
                      // Calculate new wheel speed.
                      // The lower the gear ratio, the harder it is to accelerate the engine.
 
                      if(bClutching)
                      {
                             TransAcc = WheelTorque / -1;
                             Wheels[i].SpinVel += TransAcc * DeltaTime;
                      }
                      else
                      {
                             if(!Wheels[i].bPoweredWheel)
                             {
                                   TransAcc = WheelTorque / -1;
                                   Wheels[i].SpinVel += TransAcc * DeltaTime;
                             }
                             else
                             {
                                   TransAcc = WheelTorque / TransInertia;
                                   Wheels[i].SpinVel += TransAcc * DeltaTime;
                             }
                      }
 
//  -----this is were the engine needs to be slowly put into gear-----
 
                      if(bClutching)
                      {
 
                          WheelRPM += (Wheels[i].SpinVel / EngineWheelRatio);
                          //TorqueConverter();
                      }
                      else   // we are in full gear
                      {
                          if(!Wheels[i].bPoweredWheel)
                          {
                               WheelRPM += (Wheels[i].SpinVel / EngineWheelRatio);
                          }
                          else
                          {
                               // Accumulate wheel spin speeds to find engine RPM.
                               // The lower the gear ratio, the faster the engine spins for a given wheel speed.
                               NewTotalSpinVel += Wheels[i].SpinVel;
                               if(!bInGear)
                               {
//                                  EngineRPM += (Wheels[i].SpinVel / EngineWheelRatio);
                                    WheelRPM += (Wheels[i].SpinVel / EngineWheelRatio);
                                    TorqueConverter();
 
                               }
                               if(bInGear)
                               {
                                    WheelRPM += (Wheels[i].SpinVel / EngineWheelRatio);
                                    EngineRPM += (Wheels[i].SpinVel / EngineWheelRatio);
                               }
                          }
 
                      }
//  ---------------------------------------------------------------
 
                      // Make sure the wheel can't spin in the wrong direction for the current gear.
                      if(bClutching)
                      {
                      }
                      else
                      {
                           if(Wheels[i].bPoweredWheel)
                           {
                                  if(Gear == 0 && Wheels[i].SpinVel > 0.0)
                                       Wheels[i].SpinVel = 0.0;
                                  else if(Gear > 0 && Wheels[i].SpinVel < 0.0)
                                       Wheels[i].SpinVel = 0.0;
                           }
                      }
 
                      /////////// LATERAL ///////////
                      if(!Wheels[i].bPoweredWheel)
                      {
                           Wheels[i].LatFriction = (WheelLatFrictionScale[0] * 1.5) * Wheels[i].TireLoad ;
                           Wheels[i].LatSlip = InterpCurveEval(Wheels[i].LatSlipFunc, Wheels[i].SlipAngle);
                      }
                      else
                      {
                           Wheels[i].LatFriction = WheelLatFrictionScale[0] * Wheels[i].TireLoad;
                           Wheels[i].LatSlip = InterpCurveEval(Wheels[i].LatSlipFunc, Wheels[i].SlipAngle);
                      }
 
                      if(OutputHandbrake && Wheels[i].bHandbrakeWheel)
                      {
                              Wheels[i].LatFriction *= Wheels[i].HandbrakeFrictionFactor;
                              Wheels[i].LatSlip *= Wheels[i].HandbrakeSlipFactor;
                      }
 
                      /////////// STEERING  ///////////
 
                      // Pass on steering to wheels that want it.
                      if(Wheels[i].SteerType == VST_Steered)
                              Wheels[i].Steer = ActualSteering;
                      else if(Wheels[i].SteerType == VST_Inverted)
                              Wheels[i].Steer = -ActualSteering;
                      else
                              Wheels[i].Steer = 0.0;
                 }
              }
              if(bClutching)
              {
              }
              else
              {
                   // EngineRPM is in radians per second, want in revolutions per minute
                   EngineRPM /= 4;
//               EngineRPM /= 2.0 * PI; // revs per sec
//               EngineRPM *= 60;
                   EngineRPM = Max(EngineRPM, 0.00); // ensure always positive!
 
                   RPM /= NumPoweredWheels;
//               RPM /= 2.0 * PI; // revs per sec
//               RPM *= 60;
                   RPM = Max(EngineRPM, 0.00); // ensure always positive!
              }
 
              if(!bClutching)
              {
                   // Update total wheel spin vel
                   TotalSpinVel = NewTotalSpinVel;
              }
 
              // Turn (yaw) damping.
              carTM = CachedLocalToWorld;  // was  carTM = LocalToWorld()
              //worldUp(carTM.M[2][0], carTM.M[2][1], carTM.M[2][2]);
              //worldRight(carTM.M[1][0], carTM.M[1][1], carTM.M[1][2]);
              //worldForward(carTM.M[0][0], carTM.M[0][1], carTM.M[0][2]);
 
            //  KGetRigidBodyState(rbState);
            //  AngVel = KRBVecToVector(rbState.AngVel);
              AngVel.X = rbState.AngVel.X;
              AngVel.Y = rbState.AngVel.Y;
              AngVel.Z = rbState.AngVel.Z;
              TurnAngVel = AngVel dot worldUp;
 
              DampingScale = 1.0 - MinAirControlDamping;
              if(bAllowAirControl && !bVehicleOnGround)
              {
          //            Log("bVehicleOnGround");
          //            Log(bVehicleOnGround);
                      TurnDampingMag = (1.0 - DampingScale*Abs(Steering)) * TurnDamping * TurnAngVel;
                      //KAddImpulse( WForce, -TurnDampingMag * worldUp );
                      Force += (WForce + (-1 * TurnDampingMag) * worldUp);
              }
 
              else
              {
                      TurnDampingMag = (1.0 - Abs(ActualSteering)) * TurnDamping * TurnAngVel;
                      //KAddImpulse( WForce, -TurnDampingMag * worldUp );
                      Force += (WForce + (-1 + TurnDampingMag) * worldUp);
              }
 
              // If vehicle is in the air and we are allowing air control...
              if(!bVehicleOnGround)
              {
                      PitchAngVel = AngVel dot worldRight;
                      RollAngVel = AngVel dot worldForward;
 
                      if(bAllowAirControl)
                      {
                              AirControlTorque = worldRight * OutputPitch * -AirPitchTorque;
 
                              if(bIsWalking)
                              {
        //                          Log("bIsWalking");
        //                          Log(bIsWalking);
                                      AirControlTorque += (worldForward * Steering * -AirRollTorque);
                                      }
                              else
                              {
                                      AirControlTorque += (worldUp * Steering * -AirTurnTorque);
                              }
                              //KAddImpulse( WForce, AirControlTorque );
                              Force += AirControlTorque;
 
                              // Damping forces
                              PitchDampingMag = (1.0 - DampingScale*Abs(OutputPitch)) * AirPitchDamping * PitchAngVel;
                              RollDampingMag = (1.0 - DampingScale*Abs(Steering)) * AirRollDamping * RollAngVel;
 
                              //KAddImpulse( WForce, (-PitchDampingMag * worldRight) + (-RollDampingMag * worldForward) );
                              Force += (WForce + ((-1 + PitchDampingMag) * worldRight) + ((-1 + RollDampingMag) * worldForward));
 
                              UDForce = Force;
                              UDTorque = Torque;
                      }
                      else
                      {
                         PitchDampingMag = AirPitchDamping * PitchAngVel;
                         //KAddImpulse( WForce, -PitchDampingMag * worldRight );
                         Force += (WForce + (-1 + PitchDampingMag) * worldRight);
                      }
              }
              else
              {
                   UDForce = Force;
                   UDTorque = Torque;
              }
        }
}
Engine
function Engine()
{
     Gas = Gas2;
     RPM = InterpCurveEval(EngineS, Gas);
}
StoptheCar
  • This function allows for slower, more real life like breaking
function StoptheCar()
{
   if(bBraking)
   {
      if(hBrake<=21 && hBrake>=0)
      {
           hBrake += 0.5;
      }
      if(hBrake>21)
             hBrake = 21;
   }
   if(!bBraking)
   {
           if(hBrake<=21 && hBrake>=0)
           {
                hBrake -= 0.5;
           }
           if(hBrake<0)
                hBrake = 0;
   }
}
TorqueConverter
  • This function should prolly have a different name, I named it this thinking I would need to accually have a torque converter for the tranny but I turned out making it a function that eases into gear and fixes the rpm to equal that of the engine rpm when the clutch is pressed.
function TorqueConverter()
{
    local  float    rpmDifference;
    local  float    myRPM;
    rpmDifference = 0.0;
    myRPM = WheelRPM;
    myRPM *= 6.28; // convert to radians per sec
    myRPM /= 60;
         if(EngineRPM == myRPM)
              bInGear = True;
         else if(EngineRPM > myRPM)
         {
              if(myRPM < 0)
                    rpmDifference = EngineRPM - (2 * Abs(myRPM));
 
              else if(myRPM >= 0)
                    rpmDifference = EngineRPM - myRPM;
              if(rpmDifference <= 200.0)
              {
                   bInGear = True;
              }
              else if(rpmDifference > 200.0)
              {
                   bInGear = False;
                   rpmDifference = rpmDifference * 0.2;
                   EngineRPM -= rpmDifference;
                   bRadians = True;
              }
         }
         else if(EngineRPM < myRPM)
         {
              rpmDifference = myRPM - EngineRPM;
              if(rpmDifference <= 200.0)
              {
                   bInGear = True;
              }
              else if(rpmDifference > 200.0)
              {
                   bInGear = False;
                   rpmDifference = rpmDifference * 0.2;
                   EngineRPM -= rpmDifference;
                   bRadians = True;
              }
         }
}
KApplyForce
function KApplyForce(out vector Force, out vector Torque)
{
    Super.KApplyForce(Force, Torque);
    Force += UDForce;
    Torque += UDTorque;
    if (bBoosting == true && bVehicleOnGround == true)
        Force += vector(Rotation) * SpeedBoost;
}
KImpact
event KImpact(Actor Other, vector Pos, vector ImpactVel, vector ImpactNorm)
{
    if (Role == ROLE_Authority)
    {
 
        ImpactInfo.Other = Other;
        ImpactInfo.Pos = Pos;
        ImpactInfo.ImpactVel = ImpactVel;
        ImpactInfo.ImpactNorm = ImpactNorm;
        ImpactInfo.ImpactAccel = KParams.KAcceleration;
        ImpactTicksLeft = ImpactDamageTicks;
    }
}
DrivingStatusChanged
event DrivingStatusChanged()
{
        local int i;
        Super.DrivingStatusChanged();
    if (bDriving && Level.NetMode != NM_DedicatedServer && !bDropDetail)
        {
        Dust.length = Wheels.length;
        for(i=0; i<Wheels.Length; i++)
            if (Dust[i] == None)
            {
                        // Create wheel dust emitters.
                        WheelCoords = GetBoneCoords(Wheels[i].BoneName);
                        Dust[i] = spawn(class'ONSDirtSlipEffect', self,, WheelCoords.Origin + ((vect(0,0,-1) * Wheels[i].WheelRadius) >> Rotation));
                        Dust[i].SetBase(self);
                            Dust[i].SetDirtColor( Level.DustColor );
                }
                if(bMakeBrakeLights)
                {
                        for(i=0; i<2; i++)
                        if (BrakeLight[i] == None)
                        {
                                BrakeLight[i] = spawn(class'ONSBrakelightCorona', self,, Location + (BrakeLightOffset[i] >> Rotation) );
                                BrakeLight[i].SetBase(self);
                                BrakeLight[i].SetRelativeRotation( rot(0,32768,0) ); // Point lights backwards.
                                BrakeLight[i].Skins[0] = BrakeLightMaterial;
                        }
                }
        }
    else
    {
        if (Level.NetMode != NM_DedicatedServer)
        {
            for(i=0; i<Dust.Length; i++)
                Dust[i].Destroy();
 
            Dust.Length = 0;
 
            if(bMakeBrakeLights)
            {
                for(i=0; i<2; i++)
                    if (BrakeLight[i] != None)
                        BrakeLight[i].Destroy();
            }
        }
        TurnDamping = 0.0;
    }
}
KDriverEnter
function KDriverEnter(Pawn P)
{
        Super.KDriverEnter(P);
}
ClientKDriverLeave
simulated function ClientKDriverLeave(PlayerController PC)
{
        Super.ClientKDriverLeave(PC);
 
        bWeaponIsAltFiring = false;
        PC.EndZoom();
}
SpecialCalcFirstPersonView
simulated function SpecialCalcFirstPersonView(PlayerController PC, out actor ViewActor, out vector CameraLocation, out rotator CameraRotation )
{
        ViewActor = self;
        CameraLocation = Location + (FPCamPos >> Rotation);
}
Fire
function Fire(optional float F)
{
       VehicleFire(False);
}
AltFire
function AltFire(optional float F)
{
 
        VehicleFire(true);
}
VehicleFire
function VehicleFire(bool bWasAltFire)
{
         if(!bWasAltFire)
         {
                 bGearUp = 1;
                 ChangeGear(bGearUp);
         }
 
         else if(bWasAltFire)
         {
                 bGearDown = -1;
                 ChangeGear(bGearDown);
         }
}
VehicleCeaseFire
function VehicleCeaseFire(bool bWasAltFire)
{
         if(!bWasAltFire)
         {
                 bGearUp = 0;
                 ChangeGear(bGearUp);
         }
         else if(bWasAltFire)
         {
                 bGearDown = 0;
                 ChangeGear(bGearDown);
         }
    Super.VehicleCeaseFire(bWasAltFire);
}
ClientVehicleCeaseFire
simulated function ClientVehicleCeaseFire(bool bWasAltFire)
{
    Super.ClientVehicleCeaseFire(bWasAltFire);
}
Tick
function Tick(float DT)
{
    local int               i, x;
    local bool              lostTraction;
    local KarmaParams       KP;
    local KRigidBodyState   BodyState;
 
    TheDeltaTime = DT;
    Super.Tick(DT);
 
    VRate = VSize(Velocity);
    KP = KarmaParams(KParams);
    KGetRigidBodyState(BodyState);
 
    SteerBoneAxis = AXIS_Z;
    KWake();
    if(Role == ROLE_Authority)
    {
        if(bDriving)
        {
            // Update ForwardVel, CarMPH and bIsInverted on both server and client.
            GetAxes(Rotation, worldForward, worldRight, worldUp);
 
            ForwardVel = Velocity dot worldForward;
            CarMPH = Abs((ForwardVel * 3600.0) / 140800.0); // Convert from units per sec to miles per hour.
 
            bIsInverted = worldUp.Z < 0.2;
 
            // Update engine sound pitch
            EnginePitch = 255.0 * ((EngineRPM+IdleRPM)/EngineRPMSoundRange);
            EnginePitch = Clamp(EnginePitch, 0.0, 255.0);
            SoundPitch = EnginePitch;
 
            SteerBoneAngle = (ActualSteering/InterpCurveEval(MaxSteerAngleCurve, VRate)) * SteerBoneMaxAngle * (65535.0/360.0);
 
            one.X = 0;
            one.Y = 0;
            one.Z = SteerBoneAngle;
 
            two.X = SteerBoneAngle;
            two.Y = 0;
            two.Z = 0;
 
            three.X = 0;
            three.Y = SteerBoneAngle;
            three.Z = 0;
 
 
            if(SteerBoneAxis == AXIS_X)
                 //SteerRot = Rotator(0, 0, SteerBoneAngle);
                 SteerRot = Rotator(one);
 
            else if(SteerBoneAxis == AXIS_Y)
                 //SteerRot = Rotator(SteerBoneAngle, 0, 0);
                 SteerRot = Rotator(two);
 
            else
                 //SteerRot = Rotator(0, SteerBoneAngle, 0);
                 SteerRot = Rotator(three);
 
            SetBoneDirection(SteerBoneName, SteerRot, WForce, 1, 0);
        }
    }
        // Update any stunt variables.
        if(bDoStuntInfo)
        {
                ForwardsInOldPlane = Coords.XAxis - (Coords.XAxis dot OldCoords.ZAxis) * OldCoords.ZAxis;
                //ForwardsInOldPlane = SafeNormal(ForwardsInOldPlane);
                DeltaHeading = Acos( Clamp( ForwardsInOldPlane dot OldCoords.XAxis, -1.0, 1.0 ) );
                if( (ForwardsInOldPlane dot OldCoords.YAxis) < 0.0)
                        DeltaHeading *= -1.0;
                DeltaPitch = Asin( Clamp(Coords.XAxis dot OldCoords.ZAxis, -1.0f, 1.0) );
                DeltaRoll = Asin( Clamp(Coords.YAxis dot OldCoords.ZAxis, -1.0f, 1.0) );
                //debugf( TEXT("DR:%f DP:%f"), DeltaRoll, DeltaPitch );
 
                bCurrentOnGround = (bVehicleOnGround || KP.bContactingLevel);
                DaredevilPoints = 0;
 
                if(bCurrentOnGround)
                {
                        if(!bOldVehicleOnGround)
                        {
                                // We just landed - see if we should display Daredevil 'message'
                                InAirTime = Level.TimeSeconds - LastOnGroundTime;
 
                                Dist1 = Location;
                                Dist2 = LastOnGroundLocation;
                                Vect  = Dist1 - Dist2;
                                Dist3 = Vect.X * Vect.X - Vect.Y *