Announcement

Collapse
No announcement yet.

Code for making a boat

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Code for making a boat

    As I'm sure most of you are well aware of, the UT2004 Navy was released a little while ago. Oddly enough, my computer was down during this time and so I was unable to finish the boat code I was working on. So, I'm going to release the source code I was writing to this forum and, as long as I'm credited, you may extend off of it and create your own boats. No special volumes are required (except for water ones of course :-P). If you want to add any functionality go ahead and subclass. Either way, here you go, as you can see everything is well documented. This is still a beta release that I will be finishing up for the Kopholus team with an example boat, but I figured anybody who wants to use this instead of the navy code, go right ahead as it is (As far as i know) fully operational.

    Code:
    //-----------------------------------------------------------
    //	ONSSpeedBoat
    //	Justin "Mr-Slate" Breitfeller
    //	Test Subject (August 11/2004)
    //-----------------------------------------------------------
    
    class ONSSpeedBoat extends ONSVehicle
          abstract;
    
    //Basically how fast you can go
    var() float MaxThrust;
    
    //Basically how fast you can turn and how quick
    var() float MaxSteerTorque;
    
    //The amount your forward motion is damped
    var() float ForwardDampFactor;
    
    //The amount your MaxThrust is damped when in reverse (Default: 0.4 is 40% of normal speed || 1 is 100% (reg speed))
    var() float ReverseSpeedFactor;
    
    /*Set this to 0 to not increase the slow down length at all... Otherwise make it a high number as you divide your
    forward velocity by this and add it to the current force (only added when not hitting any throttle) */
    var() float FactorToDivideVelocityByToSlowDownSlower;
    
    //The damping factor of your movement when you exit the vehicle
    var() float ParkingDampFactor;
    
    //Increasing this value affects how fast the actual boat spins (Torque Damping)
    var() float SteerDampFactor;
    
    //How much your forward velocity is damped when turning, even a small value here shows a noticable hit to your forward momentum
    var() float TurnDampFactor;
    
    //How far down you have to hold the reverse key to invert the steering... (-0.1 is a good value as you dont want it inverted at 0[idle])
    var() float InvertSteeringThrottleThreshold;
    
    //How much lateral movement forces are damped
    var() float LateralDampFactor;
    
    //This is implemented but doesnt seem to do much
    var() float BankTorqueFactor;
    
    //This is implemented but doesnt seem to do much
    var() float BankDampFactor;
    
    //Should prevent pitch from changing too much
    var() float PitchDampFactor;
    
    //When not pressing throttle will increase the drag on forward velocity on top of ForwardDampFactor
    var() float WaterDampFactor;
    
    //Should be the value by which you slide forward if turning  (Keep values very subtle otherwise NASTY results)
    var() float SlideFactor;
    
    //the factor by which the output thrust is damped on land(ie .8 is about 80% of normal movement)
    //Radius based land damping and other things obviously use this value as well as just basic land damping
    var() float LandDampingFactor;
    
    //if this is true the land damping will increase to the value over the time specified
    //This is not applied if water is found under the boat using WaterSearchDistance
    var() bool bTimeBasedLandDamping;
    
    //if bTimeBasedLandDamping is true then this is the time until the full land damping is applied
    var() float TimeUntilFullLandDamping;
    
    //if this is true the land damping will be applied after you are out of this radius unless you have
    //bTimeBasedLandDamping true, in which case it will then start the trigger for that (Spherical searching)
    //This is not applied if water is found under the boat using WaterSearchDistance
    var() bool bRadiusBasedLandDamping;
    
    /* this rquires bRadiusBasedLandDamping to be true.. this will cause the land damping to increase along
    inside the radius until 100% on the very outer edge of the radius and outside of it... closer to center is a
    less percentage (1/2 radius = 1/2 land damping)
    */
    var() bool bAffectLandDampingEvenInRadius;
    
    //the radius for the RadiusBasedLandDamping if it is true
    var() float RadiusUntilFullLandDamping;
    
    //If you always want to use the WaterSearchDistance (search for water under the boat) before you do the radius and/or time
    //based checks set this to true (Trace every update vehicle if doesnt have a watervolume for physicsvolume or touchingone so try to avoid)
    //there is no need to set this to true if not using time or radius based land damping
    var() bool bAlwaysUseWaterSearch;
    
    //Min velocity size needed to unlock turning
    var() float MinVelocityToTurn;
    
    //distnace off top of water to scan for water (for bumping on waves and not wanting kill thrust)
    var() float WaterSearchDistance;
    
    //if true the boats will be able to thrust in the air (they are out of range of water under them set by above variable
    var() bool bApplyForceInAir;
    
    //if true as soon as the drivers head goes under water the controls lock up and the boat will rise to the top
    var() bool bKillControlsUnderWater;
    
    //if left at 0, as soon as head hits the water, otherwise must be this far underwater
    var() float MinimumDistanceUnderWaterToKillControls;
    
    //Set this value to true if you still want the boat to spin when you are under the minimum velocity
    var() bool bApplyTurnTorqueUnderMinVelocity;
    
    //This the damping factor set to spinning when you are under the minimum velocity (set to 1 for regular turning)
    //Requires: bApplyTurnTorqueUnderMinVelocity
    var() float LowVelocityTurnDampFactor;
    
    //Set this to true if you want the LowVelocityTurnDampFactor scaled by the velocity under the min velocity...
    //ie if velocity is 150 and min is 300... the turn damp factor is only 50% of normal
    var() bool bScaleLowVelocityTurnDampFactor;
    
    //if this is true damage (set by DamagePerSecondOnLand) will be applied
    var() bool bApplyDamageOnLand;
    
    //if this is true damage will be applied to the boat even if a driver is present when they are on land
    //otherwise boats on land will not get hit with damage until the driver leaves
    var() bool bApplyDamageOnLandEvenWithADriver;
    
    //If the boat is on land (meaning if the bRadiusBasedLandDamping is true || bTimeBasedLandDamping is true you are not
    //considred on land until you are out of the radius and/or out of time
    var() float DamagePerSecondOnLand;
    
    //how often land damage is applied.. for instance 1 is once every second... (0.33 is every 1/3 a second)
    var() float LandDamageTimerFrequencyInSeconds;
    
    //if this is set to true... then regardless of the fact if you have radius based land damping or time based land damping
    //bOnLand will be set to true when you are on land no matter what
    var() bool bApplyDamageRegardlessOfLandDamping;
    
    //If this is true the boat will bob (must setup the few following variables in a subclass)
    var() bool bShouldBob;
    
    //This value is how likely a bob will occur (ie .75 is 75% chance)
    var() float BobLikelihood;
    
    //This value is how hard down the boat is pushed
    var() float BobForceDownward;
    
    //This value is the time in seconds it is before the boat can bob again
    var() float BobInterval;
    
    //This value is the minimum velocity the boat needs to have to have the bob force applied (only in water)
    var() float MinimumVelocityToBob;
    
    //If set to true the boat will tilt up if going forward
    var() bool bAlterBoatsTippingWithThrottle;
    
    //This alters the force applied to the boat's rear when accelerating
    var() float TiltForceDownwardFromThrottle;
    
    //The name of the bone you apply the tilt down force too
    var() name BoneToApplyTiltForceTo;
    
    //The distance you have to be underwater for an increase in your floating up
    var float MinimumDistanceToStartIncreasedFloatUp;
    
    //How fast you have to have to be going before the float up forces stop getting added
    var float MaximumFloatUpVelocity;
    
    //The force that is applied to the boat when it is getting an extra boost up (Set this force in a subclass to fit your boat)
    var float FloatUpForce;
    
    //If you are this deep under water you will have your float up force increased by the IncreasedForceFloatUpFactor
    var float DistanceUntilIncreasedForceFloatUp;
    
    //The factor by which FloatUpForce is increased when you are farther down then DistanceUntilIncreasedForceFloatUp
    var float IncreasedForceFloatUpFactor;
    
    //The buoyancy set to the boat when it dies to allow it to sink
    var() float DeathBuoyancy;
    
    /* -----INTERNAL DO NOT SET OR CHANGE FROM HERE DOWN----- */
    
    //Simply holds the value of throttle (-1 for back, 0 for none, 1 for forward)
    var float OutputThrust;
    
    //Holds the value of turning (-1 for right, 0 for none, 1 for left)
    var float OutputTurn;
    
    //Self explanatory
    var() float BoatMPH;
    
    //The values that are added to the vehicle by this code
    var vector NewForce,NewTorque;
    
    //This value holds the time since you last seen water (used with bTimeBasedLandDamping)
    var float TimeSinceLastInWater;
    
    //This will contain the last water volume touching
    var WaterVolume LastTouchedWaterVolume;
    
    //This will contain the Location of the boat the last time it touched a water volume
    var vector LastBoatLocationInWaterVolume;
    
    //true if on land (this is affected by a few bools up farther and should NOT be set) -interal workings
    var bool bOnLand;
    
    //also should not be altered / this will be true when we are applying damage
    var bool bApplyingLandDamage;
    
    //internal storing of last bob time
    var float LastBobTime;
    
    //Replicated variables about this thing
    struct BoatMovementState
    {
    	var vector				ChassisPosition;
    	var Quat				ChassisQuaternion;
    	var vector				ChassisLinVel;
    	var vector				ChassisAngVel;
    
    	var byte				ServerThrust;
    	var byte				ServerTurn;
    	var int                 ServerViewPitch;
    	var int                 ServerViewYaw;
    };
    
    //references to the current state of this thing
    var BoatMovementState OldMovementState, MovementState;
    
    //the state of this boat
    var KRigidBodyState ChassisState;
    
    //marks a new movement state
    var bool bNewMovementState;
    
    //marks a driver change
    var bool bNewDriver;
    
    //is used to force struct to be replicated
    var bool bReplicationBuddy;
    
    replication
    {
    reliable if(Role == Role_Authority)
             MovementState;
    reliable if(!bNetOwner || (bNetOwner && !bNewDriver) && Role == Role_Authority)
             bReplicationBuddy;
    reliable if(bNetOwner && bNewDriver && Role == Role_Authority)
             LastBoatLocationInWaterVolume; //should only have to replicate this when new driver so s/he is not stuck
    reliable if(Role < Role_Authority)
             ServerSetNewDriver; //sets bNewDriver to false once client receives it
    }
    
    simulated function PostNetBeginPlay()
    {
        local WaterVolume WV;
        local vector HitLoc, HitNorm;
    
        Super.PostNetBeginPlay();
    
        /* Do basic water search so damage can be applied */
        bOnLand = true;
        if(PhysicsVolume.bWaterVolume || TouchingWaterVolume())
        {
        bOnLand = false;
        LastTouchedWaterVolume = WV;
        LastBoatLocationInWaterVolume = Location;
        }
        else
        {
        foreach TraceActors(class'WaterVolume',WV,HitLoc,HitNorm,Location - ((vect(0,0,1)>>Rotation)*WaterSearchDistance),Location)
            {
                if(WV!=None)
                        {
                        bOnLand = false;
                        TimeSinceLastInWater = 0.0;
                        LastTouchedWaterVolume = WV;
                        LastBoatLocationInWaterVolume = HitLoc;
                        break;
                        }
            }
        }
    }
    simulated function Tick(float DT)
    {
          Super.Tick(DT);
    
       if(Role == ROLE_Authority)
    	{
    	OutputThrust = Throttle;
    	OutputTurn = Steering;
    
            if (OutputThrust != 0.0 || OutputTurn != 0.0)
         	KWake();
    
    
            if(PlayerController(Controller) != None && Controller.Pawn !=None && !(PlayerController(Controller).IsInState('PlayerDriving')))
                    PlayerController(Controller).GoToState('PlayerDriving');
    
     	PackState(); //replication related
            }
    
    }
    function PackState()
    {
            local KRigidBodyState RBState;
            local rotator ViewRot;
    
            if( !KIsAwake() )
    		return;
            
    	KGetRigidBodyState(RBState);
    
    	MovementState.ChassisPosition.X = RBState.Position.X;
    	MovementState.ChassisPosition.Y = RBState.Position.Y;
    	MovementState.ChassisPosition.Z = RBState.Position.Z;
    
    	MovementState.ChassisQuaternion = RBState.Quaternion;
    
    	MovementState.ChassisLinVel.X = 10.f * RBState.LinVel.X;
    	MovementState.ChassisLinVel.Y = 10.f * RBState.LinVel.Y;
    	MovementState.ChassisLinVel.Z = 10.f * RBState.LinVel.Z;
    
    	MovementState.ChassisAngVel.X = 1000.f * RBState.AngVel.X;
    	MovementState.ChassisAngVel.Y = 1000.f * RBState.AngVel.Y;
    	MovementState.ChassisAngVel.Z = 1000.f * RBState.AngVel.Z;
    
    	MovementState.ServerThrust = FloatToRangeByte(OutputThrust);
    	MovementState.ServerTurn = FloatToRangeByte(OutputTurn);
    
    	if (Controller != None)
    	{
    		if (IsHumanControlled())
    		{
    			DriverViewPitch = Controller.Rotation.Pitch;
    			DriverViewYaw = Controller.Rotation.Yaw;
    		}
    		else
    		{
    			ViewRot = rotator(Normal((Controller.FocalPoint - Location)));
    			DriverViewPitch = ViewRot.Pitch;
    			DriverViewYaw = ViewRot.Yaw;
    		}
    	}
    	else
    	{
    		DriverViewPitch = Rotation.Pitch;
    		DriverViewYaw = Rotation.Yaw;
    	}
    
    	MovementState.ServerViewPitch = DriverViewPitch;
    	MovementState.ServerViewYaw = DriverViewYaw;
            bReplicationBuddy = !bReplicationBuddy;
    }
    simulated event DrivingStatusChanged()
    {
    Super.DrivingStatusChanged();
    if(bDriving)
        bNewDriver = true;
    }
    simulated event PostNetReceive()
    {
            if(bNewDriver && bDriving && bNetOwner) //Received the LastBoatLocationInWaterVolume
            {
                   bNewDriver = false;
                   ServerSetNewDriver();
            }
    
    	if( OldMovementState.ChassisPosition == MovementState.ChassisPosition &&
    		OldMovementState.ChassisQuaternion.X == MovementState.ChassisQuaternion.X &&
    		OldMovementState.ChassisQuaternion.Y == MovementState.ChassisQuaternion.Y &&
    		OldMovementState.ChassisQuaternion.Z == MovementState.ChassisQuaternion.Z &&
    		OldMovementState.ChassisQuaternion.W == MovementState.ChassisQuaternion.W &&
    		OldMovementState.ChassisLinVel == MovementState.ChassisLinVel &&
    		OldMovementState.ChassisAngVel == MovementState.ChassisAngVel &&
    		OldMovementState.ServerThrust == MovementState.ServerThrust &&
    		OldMovementState.ServerTurn == MovementState.ServerTurn &&
    		OldMovementState.ServerViewPitch == MovementState.ServerViewPitch &&
    		OldMovementState.ServerViewYaw == MovementState.ServerViewYaw )
    		return;
    
    	ChassisState.Position.X = MovementState.ChassisPosition.X;
    	ChassisState.Position.Y = MovementState.ChassisPosition.Y;
    	ChassisState.Position.Z = MovementState.ChassisPosition.Z;
    
    	ChassisState.Quaternion = MovementState.ChassisQuaternion;
    
    	ChassisState.LinVel.X = 0.1f * MovementState.ChassisLinVel.X;
    	ChassisState.LinVel.Y = 0.1f * MovementState.ChassisLinVel.Y;
    	ChassisState.LinVel.Z = 0.1f * MovementState.ChassisLinVel.Z;
    
    	ChassisState.AngVel.X = 0.001f * MovementState.ChassisAngVel.X;
    	ChassisState.AngVel.Y = 0.001f * MovementState.ChassisAngVel.Y;
    	ChassisState.AngVel.Z = 0.001f * MovementState.ChassisAngVel.Z;
    
    	// Set OldMovementState to MovementState
    	OldMovementState.ChassisPosition = MovementState.ChassisPosition;
    	OldMovementState.ChassisQuaternion = MovementState.ChassisQuaternion;
    	OldMovementState.ChassisLinVel = MovementState.ChassisLinVel;
    	OldMovementState.ChassisAngVel = MovementState.ChassisAngVel;
    	OldMovementState.ServerThrust = MovementState.ServerThrust;
    	OldMovementState.ServerTurn = MovementState.ServerTurn;
    	OldMovementState.ServerViewPitch = MovementState.ServerViewPitch;
    	OldMovementState.ServerViewYaw = MovementState.ServerViewYaw;
    
    	bNewMovementState = true;
    
    	OutputThrust = RangeByteToFloat(MovementState.ServerThrust);
    	OutputTurn = RangeByteToFloat(MovementState.ServerTurn);
    	DriverViewPitch = MovementState.ServerViewPitch;
    	DriverViewYaw = MovementState.ServerViewYaw;
    
           
    	Super.PostNetReceive();
    }
    function ServerSetNewDriver()
    {
    bNewDriver = false;
    }
    simulated event bool KUpdateState(out KRigidBodyState newState)
    {
    	if(Role == ROLE_Authority || !bNewMovementState)
    		return false;
    
    	newState = ChassisState;
    	bNewMovementState = false;
    
    	return true;
    }
    event UpdateVehicle(float DeltaTime)
    {
        local vector X,Y,Z, AngularVelocity, HitLoc,HitNorm;
        local KRigidBodyState RBodyState;
        local float UseForwardDamp, ForwardVelMag, UseTurn,UseLatDamp,VelMag;
        local bool bWaterNearby;
        local WaterVolume WV;
        local vector TempLastBoatLoc, TempCurrentBoatLoc;
    
        BoatMPH = 0.0;
        NewForce = vect(0,0,0);
        NewTorque = vect(0,0,0);
    
       if(bOnLand && !bApplyingLandDamage && (Controller == None || bApplyDamageOnLandEvenWithADriver))
       {
            Timer();
            SetTimer(LandDamageTimerFrequencyInSeconds,true);
            bApplyingLandDamage = true;
       }
       else if(bApplyingLandDamage && !bOnLand)
       {
            SetTimer(0,false);
            bApplyingLandDamage = false;
       }
    
       if( !KIsAwake())
    	return;
    
        X = vect(1, 0, 0) >> Rotation;
        Y = vect(0, 1, 0) >> Rotation;
        Z = vect(0, 0, 1) >> Rotation;
    
        KGetRigidBodyState(RBodyState);
    
        AngularVelocity.X = RBodyState.AngVel.X;
        AngularVelocity.Y = RBodyState.AngVel.Y;
        AngularVelocity.Z = RBodyState.AngVel.Z;
    
    
      if(bDriving)
        {
        if(HeadVolume.bWaterVolume && bKillControlsUnderWater)   //if underwater
            {
    
            if(VSize(Driver.Location - LastBoatLocationInWaterVolume) > MinimumDistanceToStartIncreasedFloatUp && VSize(Velocity) < MaximumFloatUpVelocity)
            {
                    if(VSize(Driver.Location - LastBoatLocationInWaterVolume) < DistanceUntilIncreasedForceFloatUp)
                    NewForce += (FloatUpForce * Z);    //Pop up affect tries to help the boat rush to the surface
                    else
                    NewForce += (FloatUpForce * IncreasedForceFloatUpFactor * Z);
            }
            bOnLand = false;
            if(MinimumDistanceUnderWaterToKillControls ~= 0.0)
            {
            OutputThrust = 0.0;
            OutputTurn = 0.0;
            return;
            }
            else
              {
              TempCurrentBoatLoc = Driver.Location;
              TempLastBoatLoc = LastBoatLocationInWaterVolume;
              if(VSize(TempCurrentBoatLoc - TempLastBoatLoc) > MinimumDistanceUnderWaterToKillControls)
              {
                 OutputThrust = 0.0;
                 OutputTurn = 0.0;
                 return;
              }
              }
           }
    
        //This is the setting of the initial forces && handles land damping
        bWaterNearby = false;
        //apply the damped reverse
        if(OutputThrust < 0)
        {
         OutputThrust *= ReverseSpeedFactor;
        }
    
        if(PhysicsVolume.bWaterVolume || TouchingWaterVolume())
        {
        NewForce += (OutputThrust * MaxThrust * X);
        bWaterNearby = true;
        bOnLand = false;
        TimeSinceLastInWater = 0.0;
        if(PhysicsVolume.bWaterVolume)
        LastTouchedWaterVolume = WaterVolume(PhysicsVolume);
        else
        {
           ForEach TouchingActors(class'WaterVolume',WV)
           {
    		if ( WV != None)
    		{
                         LastTouchedWaterVolume = WaterVolume(PhysicsVolume);
                         break;
                    }
           }
        }
        if(!HeadVolume.bWaterVolume) //dont want to update last location if drowning
        LastBoatLocationInWaterVolume = Location;
        } //end of if
        else if((!bRadiusBasedLandDamping && !bTimeBasedLandDamping) || bAlwaysUseWaterSearch)
        {
        foreach TraceActors(class'WaterVolume',WV,HitLoc,HitNorm,Location - (Z*WaterSearchDistance),Location)
            {
                if(WV!=None)
                        {
                        bWaterNearby = true;
                        bOnLand = false;
                        TimeSinceLastInWater = 0.0;
                        LastTouchedWaterVolume = WV;
                        LastBoatLocationInWaterVolume = HitLoc;
                        break;
                        }
            }
         if(bWaterNearby)
           NewForce += (OutputThrust * MaxThrust * X);
        }
    
         //will cut the force on land by the factor
        if(bRadiusBasedLandDamping && !bWaterNearby)
         {
          
          if(VSize(LastBoatLocationInWaterVolume - Location) < RadiusUntilFullLandDamping)
          {
                  bWaterNearby = true; 
                  if(!bApplyDamageRegardlessOfLandDamping)
                  bOnLand = false;
                  else
                  bOnLand = true;
                  TimeSinceLastInWater = 0.0; // still in radius and so timebasedlanddamping should be reset at least once
          }
    
          if(bWaterNearby)
          {
             if(!bAffectLandDampingEvenInRadius)
              NewForce += (OutputThrust * MaxThrust * X);
             else
             {
              NewForce += (OutputThrust * MaxThrust * X);
              NewForce += (-1.0f * FClamp(VSize(LastBoatLocationInWaterVolume - Location) / RadiusUntilFullLandDamping,0.0,1.0) * LandDampingFactor * OutputThrust * MaxThrust * X);
             }
          }
         }
         if(bTimeBasedLandDamping && !bWaterNearby)
         {
              TimeSinceLastInWater += DeltaTime;
              NewForce += (OutputThrust * MaxThrust * X);
              NewForce += (-1.0f * FClamp(TimeSinceLastInWater / TimeUntilFullLandDamping, 0.0, 1.0) * LandDampingFactor * OutputThrust * MaxThrust * X);
              if(TimeSinceLastInWater / TimeUntilFullLandDamping > 0.999)
              {
              bOnLand = true;
              }
              else if(TimeSinceLastInWater / TimeUntilFullLandDamping < 0.999 && !bApplyDamageRegardlessOfLandDamping)
              bOnLand = false;
              else if(bApplyDamageRegardlessOfLandDamping)
              bOnLand = true;
    
         }
         if(!bWaterNearby && !bTimeBasedLandDamping)
         {
          NewForce += (OutputThrust * MaxThrust * X);
          if(!bApplyForceInAir && ImpactInfo.Other == None) //no water nearby and in air.. kill forces
          return;
    
          NewForce += (-1.0f * OutputThrust * LandDampingFactor * MaxThrust * X);
          bOnLand = true;
    
         }
    
        //Pitch damping
        VelMag = AngularVelocity dot Y;
        NewTorque += (-1.0f * VelMag * PitchDampFactor * Y);
    
         // Forward damping
        ForwardVelMag = Velocity dot X;
        UseForwardDamp = ForwardDampFactor;
    
        if(OutputThrust == 0.0 && !bOnLand) //slide factor forward (slower slow downs)
        {
            NewForce += ForwardVelMag / FactorToDivideVelocityByToSlowDownSlower * X;
        }
    
        if(Controller == None)
         UseForwardDamp += ParkingDampFactor;
        else if(OutputThrust == 0)
         UseForwardDamp += WaterDampFactor;
        else if(ForwardVelMag > 0 && OutputThrust < 0)  //increase damping if moving forward and trying to go backwards
         UseForwardDamp += WaterDampFactor*2;
    
        NewForce += (-1.0f * ForwardVelMag * UseForwardDamp * X);
    
        //Implementation of sliding when turning  TODO: FIX ME... or remove
        if(Abs(ForwardVelMag) > 100 && Abs(OutputTurn) > 0)
         NewForce += (Abs(OutputTurn) * ForwardVelMag * SlideFactor * X);
    
        //Turn damping to my force
        NewForce += (-1.0f * Abs(OutputTurn) * ForwardVelMag * TurnDampFactor * X);
    
        // Invert steering when we are going backwards
        if( OutputThrust < InvertSteeringThrottleThreshold )
     	UseTurn = -1.0f * OutputTurn;
        else
         	UseTurn = OutputTurn;
    
        // Lateral damping for sideways movement which is ....most likely nothing except for things that dodge
        VelMag = Velocity dot Y;
        UseLatDamp = LateralDampFactor;
    
        if(Controller == None) //stop me on parking (practically)
          UseLatDamp += ParkingDampFactor;
    
        NewForce += (-1.0f * VelMag * UseLatDamp * Y);
    
    
        // Turn damping
        VelMag = AngularVelocity dot Z;
        NewTorque += (-1.0f * SteerDampFactor * VelMag * Z);
    
        // Steer Torque being applied as long as we are moving (like a real boat)
        if(VSize(Velocity) > MinVelocityToTurn)
        NewTorque += (-1.0f * MaxSteerTorque * UseTurn * Z);
        else if(bApplyTurnTorqueUnderMinVelocity && !bScaleLowVelocityTurnDampFactor)
        {
        NewTorque += (-1.0f * MaxSteerTorque * UseTurn * Z);
        NewTorque += (MaxSteerTorque * LowVelocityTurnDampFactor * UseTurn * Z);
        }
        else if(bApplyTurnTorqueUnderMinVelocity && bScaleLowVelocityTurnDampFactor)
        {
        NewTorque += (-1.0f * MaxSteerTorque * UseTurn * Z);
        NewTorque += (MaxSteerTorque * FClamp(VSize(Velocity) / MinVelocityToTurn, 0.0, 1.0) * LowVelocityTurnDampFactor * UseTurn * Z);
        }
    
    
        // Banking Torque
        NewTorque += (BankTorqueFactor * UseTurn * X);
    
        // Bank (roll) Damping
        VelMag = AngularVelocity dot X;
        NewTorque += (-1.0f * VelMag * BankDampFactor * X);
    
    
        //TILTING (Up/Down)
        if(bAlterBoatsTippingWithThrottle && OutputThrust > 0)
        {
        KAddImpulse(-1.0f * FClamp(OutputThrust,0,1.0) * TiltForceDownwardFromThrottle * Z, GetBoneCoords(BoneToApplyTiltForceTo).Origin);
        }
    
        //This may help stop the climbing I hope
        NewForce.Z = 0.0;
    
        //BOBBING
        if(bShouldBob && VSize(Velocity) > MinimumVelocityToBob && Level.TimeSeconds > (LastBobTime + BobInterval) && FRand() > (1-BobLikelihood) && !bOnLand)
        {
              NewForce += (-1.0f * BobForceDownward * Z);
              LastBobTime = Level.TimeSeconds;
        }
        // Set current boat speed. Convert from units per sec to miles per hour.
        BoatMPH = Abs( (ForwardVelMag * 3600.0f) / 140800.0f );
    
        ModifyAppliedForce(NewForce, NewTorque);
       }
    
       Super.UpdateVehicle(DeltaTime);
    }
    //hook for subclass to alter forces
    function ModifyAppliedForce(out vector ModifiedForce, out vector ModifiedTorque);
    
    function Timer()
    {
             TakeDamage(DamagePerSecondOnLand * LandDamageTimerFrequencyInSeconds, None, Location + CollisionHeight * vect(0,0,0.5), vect(0,0,0), class'Corroded');
    }
    
    simulated function KApplyForce(out vector Force, out vector Torque)
    {
          if (bDriving)
    	 {
    	 Force += NewForce;
    	 Torque += NewTorque;
             }
    
    	Super.KApplyForce(Force, Torque);
    
    }
    simulated event DestroyAppearance()
    {
    Super.DestroyAppearance();
    KarmaParams(KParams).KBuoyancy = DeathBuoyancy;
    }
    simulated function byte FloatToRangeByte(float inFloat)
    {
     return (inFloat * 255);
    }
    simulated function float RangeByteToFloat(byte inByte)
    {
     return (inByte / 255);
    }
    
    defaultproperties
    {
         ReverseSpeedFactor=0.400000
         ParkingDampFactor=0.800000
         WaterDampFactor=0.005000
    
         TimeSinceLastInWater = 0.0
    
         InvertSteeringThrottleThreshold=-0.100000
    
         WaterSearchDistance=750.000000
    
         bKillControlsUnderWater=True
         MinimumDistanceUnderWaterToKillControls=1500.000000
    
         bApplyTurnTorqueUnderMinVelocity=True
    
         bApplyDamageOnLand=True
         DamagePerSecondOnLand=15.000000
         LandDamageTimerFrequencyInSeconds=0.330000
    
         bShouldBob=False //setup the following in a subclass
         bTimeBasedLandDamping=False
         bRadiusBasedLandDamping = False
    
         bAlterBoatsTippingWithThrottle=True
    
         MinimumDistanceToStartIncreasedFloatUp=1500.000000
         MaximumFloatUpVelocity=1000.000000
         DistanceUntilIncreasedForceFloatUp=4000.000000
         IncreasedForceFloatUpFactor=1.500000
    
         WaterDamage=0.000000
    
         bNetNotify=True
         bTraceWater=True
         bNewDriver = True
    
         LastBoatLocationInWaterVolume =(x=0.0,y=0.0,z=0.0);
    
         FactorToDivideVelocityByToSlowDownSlower= 10.00 //reset this to work well with your ships speed
         
    }

    #2
    Excellent work there Mr Slate. I will be home finally in about 2 weeks, then I will be back to coding and modeling for Ut2004. Now you are finished the boat code, I may consider switching the Vipers over to it, depending on how it feels...

    Comment


      #3
      Now that is one well documented script. Huzzah to the boatsmith!

      Comment

      Working...
      X