The three virtues of a programmer: Laziness, Impatience, and Hubris. – Larry Wall

Legacy:KHoverTank

From Unreal Wiki, The Unreal Engine Documentation Site
Jump to: navigation, search
UT2003 :: Actor >> Pawn >> KVehicle >> KCar >> KHoverTank

Adding extra wheels is pretty easy, useful for making tanks or hovercrafts. :] Also, Rear Steering with forward steering allows for some sharp turns and cool looking vehicle :]

//=============================================================================
// KHoverTank.
// Base class for 6-invisible wheeled 'hover' vehicles using Karma
// Assumes negative-X is forward, negative-Y is right
//=============================================================================
class KHoverTank extends KCar
	abstract;
 
var KTire		midLeft, midRight;
var (KHoverTank)	class<KTire>	MidTireClass< SEMI >
// Wheel positions
var const float		WheelMidAlong;
var const float		WheelMidAcross;
 
replication
{
	// We replicate the Gear for brake-lights etc.
	unreliable if(Role == ROLE_Authority)
		CarState, Gear;
 
	reliable if(Role == ROLE_Authority)
		FlipTimeLeft;
}
 
// When new information is received, see if it's new. If so, pass bits off the wheels.
// Each part will then update its rigid body position via the KUpdateState event.
// JTODO: This is where clever unpacking would happen.
simulated event VehicleStateReceived()
{
	local vector ChassisY, SteerY, ChassisZ, calcPos, WheelY, lPos;
	local vector chassisPos, chassisLinVel, chassisAngVel, WheelLinVel, wPosRel;
	local Quat relQ, WheelQ;
 
	// Don't do anything if car isn't started up. 
	// Shouldn't need to worry about Front or Rear as it's done in Super.
	if( midLeft == None || midRight == None )
		return;
 
	Super.VehicleStateReceived()
 
	////////////////////////// MID LEFT //////////////////////////
	midLeft.KGetRigidBodyState(midLeft.ReceiveState);
 
	// Position
	lPos.X = WheelMidAlong;
	lPos.Y = WheelMidAcross;
	lPos.Z = CarState.WheelHeight[2];
	calcPos = chassisPos + QuatRotateVector(CarState.ChassisQuaternion, lPos);
	midLeft.ReceiveState.Position = KRBVecFromVector(calcPos);
 
	// Rotation
	wheelQ = midLeft.KGetRBQuaternion();
	WheelY = QuatRotateVector(wheelQ, vect(0, 1, 0));
	relQ = QuatFindBetween(WheelY, ChassisY);
	midLeft.ReceiveState.Quaternion = QuatProduct(relQ, wheelQ);
 
	// Velocity
	wPosRel = calcPos - chassisPos;
	WheelLinVel = chassisLinVel + (chassisAngVel Cross wPosRel);
	WheelLinVel += CarState.WheelVertVel[2] * ChassisZ;
	midLeft.ReceiveState.LinVel = KRBVecFromVector(WheelLinVel);
 
	midLeft.bReceiveStateNew = true;
 
	////////////////////////// MID RIGHT //////////////////////////
	midRight.KGetRigidBodyState(midRight.ReceiveState);
 
	// Position
	lPos.X = WheelMidAlong;
	lPos.Y = WheelMidAcross;
	lPos.Z = CarState.WheelHeight[3];
	calcPos = chassisPos + QuatRotateVector(CarState.ChassisQuaternion, lPos);
	midRight.ReceiveState.Position = KRBVecFromVector(calcPos);
 
	// Rotation
	wheelQ = midRight.KGetRBQuaternion();
	WheelY = QuatRotateVector(wheelQ, vect(0, 1, 0));
	relQ = QuatFindBetween(WheelY, ChassisY);
	midRight.ReceiveState.Quaternion = QuatProduct(relQ, wheelQ);
 
	// Velocity
	wPosRel = calcPos - chassisPos;
	WheelLinVel = chassisLinVel + (chassisAngVel Cross wPosRel);
	WheelLinVel += CarState.WheelVertVel[3] * ChassisZ;
	midRight.ReceiveState.LinVel = KRBVecFromVector(WheelLinVel);
 
	midRight.bReceiveStateNew = true;
 
	////// OTHER //////
 
	// Update control inputs
	Steering = CarState.ServerSteering;
	OutputTorque = CarState.ServerTorque;
	OutputBrake = CarState.ServerBrake;
	OutputHandbrakeOn = CarState.ServerHandbrakeOn;
 
	// Update flags
 
	CarState.bNewState = false;
	bNewCarState = true;
 
}
 
// Pack current state of whole car into the state struct, to be sent to the client.
// Should only get called on the server.
function PackState()
{
	local vector lPos, wPos, chassisPos, chassisLinVel, chassisAngVel, wPosRel, WheelLinVel;
	local vector ChassisX, ChassisZ, WheelY, oldPos, oldLinVel;
	local KRigidBodyState ChassisState, WheelState, TurrState;
 
	Super.PackState();
 
 
	////////////////////////// MID LEFT //////////////////////////
	midLeft.KGetRigidBodyState(WheelState);
	wPos = KRBVecToVector(WheelState.Position);
	lPos = QuatRotateVector(QuatInvert(CarState.ChassisQuaternion), wPos - chassisPos);
	CarState.WheelHeight[2] = lPos.Z;
 
	wPosRel = KRBVecToVector(WheelState.Position) - chassisPos;
	WheelLinVel = chassisLinVel + (chassisAngVel Cross wPosRel);
 
	CarState.WheelVertVel[2] = 
		((WheelState.LinVel.X - WheelLinVel.X)* ChassisZ.X) + 
		((WheelState.LinVel.Y - WheelLinVel.Y)* ChassisZ.Y) + 
		((WheelState.LinVel.Z - WheelLinVel.Z)* ChassisZ.Z);
 
	WheelY = QuatRotateVector(WheelState.Quaternion, vect(0, 1, 0));
 
	////////////////////////// MID RIGHT //////////////////////////
	midRight.KGetRigidBodyState(WheelState);
	wPos = KRBVecToVector(WheelState.Position);
	lPos = QuatRotateVector(QuatInvert(CarState.ChassisQuaternion), wPos - chassisPos);
	CarState.WheelHeight[3] = lPos.Z;
 
	wPosRel = KRBVecToVector(WheelState.Position) - chassisPos;
	WheelLinVel = chassisLinVel + (chassisAngVel Cross wPosRel);
 
	CarState.WheelVertVel[3] = 
		((WheelState.LinVel.X - WheelLinVel.X)* ChassisZ.X) + 
		((WheelState.LinVel.Y - WheelLinVel.Y)* ChassisZ.Y) + 
		((WheelState.LinVel.Z - WheelLinVel.Z)* ChassisZ.Z);
 
 
 
	WheelY = QuatRotateVector(WheelState.Quaternion, vect(0, 1, 0));
 
	// OTHER
	CarState.ServerSteering = Steering;
	CarState.ServerTorque = OutputTorque;
	CarState.ServerBrake = OutputBrake;
	CarState.ServerHandbrakeOn = OutputHandbrakeOn;
 
	// This flag lets the client know this data is new.
	CarState.bNewState = true;
 
}
 
simulated function PostNetBeginPlay()
{
	local vector RotX, RotY, RotZ, lPos;
 
    Super.PostNetBeginPlay();
 
    // Set up suspension graphics
    GetAxes(Rotation,RotX,RotY,RotZ);
 
	frontLeft.bHidden = True;  // Invisible wheels for hovercrafts
	frontRight.bHidden = True;  // Invisible wheels for hovercrafts
	rearLeft.bHidden = True;  // Invisible wheels for hovercrafts
	rearRight.bHidden = True;  // Invisible wheels for hovercrafts
    midLeft = spawn(MidTireClass, self,, Location + WheelMidAlong*RotX - WheelMidAcross*RotY + (256 /*WheelVert*/)*RotZ, Rotation);
    midLeft.SetDrawScale3D(vect(1, 1, 1));
	midLeft.bHidden = True; // Invisible wheels for hovercrafts
 
    midRight = spawn(MidTireClass, self,, Location + WheelMidAlong*RotX - WheelMidAcross*RotY + (256 /*WheelVert*/)*RotZ, Rotation);
    midRight.SetDrawScale3D(vect(1, -1, 1));
	midRight.bHidden = True; // Invisible wheels for hovercrafts
 
	lPos.X = WheelMidAlong;
	lPos.Y = -WheelMidAcross;
    midRight.WheelJoint = spawn(class'KCarWheelJoint', self);
    midRight.WheelJoint.KPos1 = lPos/50;
    midRight.WheelJoint.KPriAxis1 = vect(0, 0, 1);
    midRight.WheelJoint.KSecAxis1 = vect(0, 1, 0);
    midRight.WheelJoint.KConstraintActor1 = self;
    midRight.WheelJoint.KPos2 = vect(0, 0, 0);
    midRight.WheelJoint.KPriAxis2 = vect(0, 0, 1);
    midRight.WheelJoint.KSecAxis2 = vect(0, 1, 0);
    midRight.WheelJoint.KConstraintActor2 = midRight;
    midRight.WheelJoint.SetPhysics(PHYS_Karma);
 
	lPos.Y = WheelMidAcross;
    midLeft.WheelJoint = spawn(class'KCarWheelJoint', self);
    midLeft.WheelJoint.KPos1 = lPos/50;
    midLeft.WheelJoint.KPriAxis1 = vect(0, 0, 1);
    midLeft.WheelJoint.KSecAxis1 = vect(0, 1, 0);
    midLeft.WheelJoint.KConstraintActor1 = self;
    midLeft.WheelJoint.KPos2 = vect(0, 0, 0);
    midLeft.WheelJoint.KPriAxis2 = vect(0, 0, 1);
    midLeft.WheelJoint.KSecAxis2 = vect(0, 1, 0);
    midLeft.WheelJoint.KConstraintActor2 = midLeft;
    midLeft.WheelJoint.SetPhysics(PHYS_Karma);
 
	// Initially make sure parameters are synced with Karma
	KVehicleUpdateParams();
 
}
 
// Clean up wheels etc.
simulated event Destroyed()
{
 
	// Destroy joints holding wheels to car
	midLeft.WheelJoint.Destroy();
	midRight.WheelJoint.Destroy();
 
	// Destroy wheels themselves.
	midLeft.Destroy();
	midRight.Destroy();
 
	Super.Destroyed();
 
}
 
// Call this if you change any parameters (tire, suspension etc.) and they
// will be passed down to each wheel/joint.
simulated event KVehicleUpdateParams()
{
 
	Super.KVehicleUpdateParams();
 
    midLeft.WheelJoint.bKSteeringLocked = true;
    midRight.WheelJoint.bKSteeringLocked = true;
 
    // unlock rear wheels for steering
    rearLeft.WheelJoint.bKSteeringLocked = false;
 
    rearLeft.WheelJoint.KProportionalGap = SteerPropGap;
    rearLeft.WheelJoint.KMaxSteerTorque = SteerTorque;
    rearLeft.WheelJoint.KMaxSteerSpeed = SteerSpeed;
 
    // unlock rear wheels for steering
    rearRight.WheelJoint.bKSteeringLocked = false;
    rearRight.WheelJoint.KProportionalGap = SteerPropGap;
    rearRight.WheelJoint.KMaxSteerTorque = SteerTorque;
    rearRight.WheelJoint.KMaxSteerSpeed = SteerSpeed;
 
    midLeft.WheelJoint.KSuspHighLimit = SuspHighLimit;
    midLeft.WheelJoint.KSuspLowLimit = SuspLowLimit;
    midLeft.WheelJoint.KSuspStiffness = SuspStiffness;
    midLeft.WheelJoint.KSuspDamping = SuspDamping;
 
    midRight.WheelJoint.KSuspHighLimit = SuspHighLimit;
    midRight.WheelJoint.KSuspLowLimit = SuspLowLimit;
    midRight.WheelJoint.KSuspStiffness = SuspStiffness;
    midRight.WheelJoint.KSuspDamping = SuspDamping;
 
	// Sync parameters with Karma - even front and rear wheels… Just incase. :P
	frontLeft.WheelJoint.KUpdateConstraintParams();
	frontRight.WheelJoint.KUpdateConstraintParams();
	midLeft.WheelJoint.KUpdateConstraintParams();
	midRight.WheelJoint.KUpdateConstraintParams();
	rearLeft.WheelJoint.KUpdateConstraintParams();
	rearRight.WheelJoint.KUpdateConstraintParams();
 
 
 
    // Mass
    frontLeft.KSetMass(TireMass+2); // maybe increase front wheels mass to simulte engine weight??
    frontRight.KSetMass(TireMass+2); // maybe increase front wheels mass to simulte engine weight??
    midLeft.KSetMass(TireMass);
    midRight.KSetMass(TireMass);
 
    midLeft.RollFriction = TireRollFriction;
    midLeft.LateralFriction = TireLateralFriction;
    midLeft.RollSlip = TireRollSlip;
    midLeft.LateralSlip = TireLateralSlip;
    midLeft.MinSlip = TireMinSlip;
    midLeft.SlipRate = TireSlipRate;
    midLeft.Softness = TireSoftness;
    midLeft.Adhesion = TireAdhesion;
    midLeft.Restitution = TireRestitution;
 
    midRight.RollFriction = TireRollFriction;
    midRight.LateralFriction = TireLateralFriction;
    midRight.RollSlip = TireRollSlip;
    midRight.LateralSlip = TireLateralSlip;
    midRight.MinSlip = TireMinSlip;
    midRight.SlipRate = TireSlipRate;
    midRight.Softness = TireSoftness;
    midRight.Adhesion = TireAdhesion;
    midRight.Restitution = TireRestitution;
 
}
 
// Car Simulation
simulated function Tick(float Delta)
{
	local float tana, sFactor;
 
	Super.Tick(Delta);
 
    WheelSpinSpeed = (frontLeft.SpinSpeed 
			+ frontRight.SpinSpeed 
			+ rearLeft.SpinSpeed 
			+ midLeft.SpinSpeed 
			+ midRight.SpinSpeed 
			+ rearRight.SpinSpeed)/6;
 
    // Motor
	// MID .. make them wheel spin :]
    midLeft.WheelJoint.KMotorTorque = 0.5 * OutputTorque * TorqueSplit;
    midRight.WheelJoint.KMotorTorque = 0.5 * OutputTorque * TorqueSplit;
 
    // Braking
 
	if(OutputBrake)
	{
		midLeft.WheelJoint.KBraking = MaxBrakeTorque;
		midRight.WheelJoint.KBraking = MaxBrakeTorque;
	}
	else
	{
		midLeft.WheelJoint.KBraking = 0.0;
		midRight.WheelJoint.KBraking = 0.0;
	}
 
	// Steering
    tana = Tan(6.283/65536 * Steering * MaxSteerAngle);
    sFactor = 0.5 * tana * (2 * WheelFrontAcross) / Abs(WheelFrontAlong - WheelRearAlong);
 
    // Make rear wheel turn in opposite direction to turn properly: -65536/6.283 
    RearLeft.WheelJoint.KSteerAngle = -65536/6.283 * Atan(tana, (1-sFactor));
    RearRight.WheelJoint.KSteerAngle = -65536/6.283 * Atan(tana, (1+sFactor));
 
	// Handbrake
	if(OutputHandbrakeOn == true)
	{
 
		midLeft.LateralFriction = TireLateralFriction + TireHandbrakeFriction;
		midLeft.LateralSlip = TireLateralSlip + TireHandbrakeSlip;
 
		midRight.LateralFriction = TireLateralFriction + TireHandbrakeFriction;
		midRight.LateralSlip = TireLateralSlip + TireHandbrakeSlip;
	}
	else
	{
		midLeft.LateralFriction = TireLateralFriction;
		midLeft.LateralSlip = TireLateralSlip;
 
		midRight.LateralFriction = TireLateralFriction;
		midRight.LateralSlip = TireLateralSlip;
	}
 
}
 
defaultproperties
{
}