Gah - a solution with more questions. – EntropicLqd

Legacy:KShip

From Unreal Wiki, The Unreal Engine Documentation Site
Revision as of 20:41, 16 April 2010 by LiKeMiKeS (Talk | contribs)

Jump to: navigation, search

Well this is basically my code for a space ship, thanks a lot to Daid for lending me his replication code (which turned out to come from KCar but i thank him non the less, great guy he is :D)

I currently use a different, more client oriented replication system, but this one here is a lot better, i havent incorporated my ship to it yet because i have some other problems that come with it that i have to solve, but since the "core" ship here is simple, ill use the better replication for you guys :)

(Btw i deal with all the entering/leaving of the vehicle in a parent class, this is really irrelevant to physics and is easy to do, so i left it out just so there will be less and easier to read code)

var float			Roll, CThrust, TempThrust, OldThrust; 
// Throttle and Steering are already declared in KVehicle, so all we need is roll, CThrust, TempThrust, OldThrust will be explained soon
// BTW note that i use Throttle for Pitch alteration because it is already bound by other vehicles to the forward/backward key
// ok i have also incorporated a system that allows for various thrust managments, 
//if you simply want to move forward full speed only while you press the the thrust button, you would use TempThrust. 
//when you release the thrust button you though you should always set TempThrust to -1
// if you want to have a constant speed, assign it to CThrust, so every time you release the thrust button (the one that changes TempThrust) 
// you would automatically start going at that speed (good for stuff like dogifghting and matching speeds)
// and lastly i added an afterburner effect, ill include it here for you guys to see although it isnt hard to do.
// also what i did with it was that when you afterburn and you run out of energy, while you still hold the afterburn key
// you would keep going at your max possible speed, and once you release it you would start going at your constant wanted speed (CThrust)
// Thats why i have 2 vars, bAfterburn is for after burning (holding key and having enough E), bBurn is for only holding the afterburn key with no regard to its depletion
var bool			bAfterburn, bBurn; // note that you should set both of those to true when you want to afterburn
var() float			ForwardTrust, TurnRate, AfterBurnThrust; // This is basically how fast our ship turns/moves
var float			CurRoll, CurSteering, CurThrottle, UnitAccRate; // This is used for acceleration
// CThrust is used for ships that can assign a specific throttle value, like 75% of max speed or whatever...
// UnitAccRate is how much each value increases per second
var vector			ExtraForce, ExtraTorque; // Used for Karama forces pileup
 
// Ship replication vars and functions, thanks daid!
struct StructShipState
{
	var KRBVec				ChassisPosition;
	var Quat				ChassisQuaternion;
	var KRBVec				ChassisLinVel;
	var KRBVec				ChassisAngVel;
 
	var float				ServerSteering;
	var float				ServerThrottle;
	var float				ServerRoll;
 
	var bool				ServerbAfterburn;
	var bool				ServerbBurn;
 
	var bool				bNewState; // Set to true whenever a new state is received and should be processed
};
 
var KRigidBodyState		ChassisState;
 
var StructShipState		ShipState; // This is replicated to the ship, and processed to update all the parts.
var bool			bNewShipState; // Indicated there is new data processed, and chassis RBState should be updated.
 
var float			NextNetUpdateTime;	// Next time we should force an update of vehicles state.
var() float			MaxNetUpdateInterval;
 
var int AVar;//Just for replication, else the ShipState doesn't get replicated
 
Replication
{
	unreliable if(Role == ROLE_Authority)
		ShipState, AVar;
}
 
simulated event VehicleStateReceived()
{
	if(!ShipState.bNewState)
		return;
 
	// Get root chassis info
	ChassisState.Position = ShipState.ChassisPosition;
	ChassisState.Quaternion = ShipState.ChassisQuaternion;
	ChassisState.LinVel = ShipState.ChassisLinVel;
	ChassisState.AngVel = ShipState.ChassisAngVel;
 
	// Update control inputs
	Steering = ShipState.ServerSteering;
	Throttle = ShipState.ServerThrottle;
	Roll = ShipState.ServerRoll;
 
	// Afterburner
	bAfterburn = ShipState.ServerbAfterburn;
	bBurn = ShipState.ServerbBurn;
 
	// Update flags
	ShipState.bNewState = false;
	bNewShipState = true;
}
 
simulated event bool KUpdateState(out KRigidBodyState newState)
{
	// This should never get called on the server - but just in case!
	if(Role == ROLE_Authority || !bNewShipState)
		return false;
 
	// Apply received data as new position of ship chassis.
	newState = ChassisState;
	bNewShipState = false;
 
	return true;
}
 
function PackState()
{
	local vector chassisPos, chassisLinVel, chassisAngVel;
	local vector oldPos, oldLinVel;
	local KRigidBodyState ChassisState;
 
	// Get chassis state.
	KGetRigidBodyState(ChassisState);
 
	chassisPos = KRBVecToVector(ChassisState.Position);
	chassisLinVel = KRBVecToVector(ChassisState.LinVel);
	chassisAngVel = KRBVecToVector(ChassisState.AngVel);
 
	// Last position we sent
	oldPos = KRBVectoVector(ShipState.ChassisPosition);
	oldLinVel = KRBVectoVector(ShipState.ChassisLinVel);
 
	// See if state has changed enough, or enough time has passed, that we 
	// should send out another update by updating the state struct.
	if( !KIsAwake() )
	{
		return; // Never send updates if physics is at rest
	}
 
	if( VSize(oldPos - chassisPos) > 5 ||
		VSize(oldLinVel - chassisLinVel) > 1 ||
		Abs(ShipState.ServerThrottle - Throttle) > 0.1 ||
		Abs(ShipState.ServerSteering - Steering) > 0.1 ||
		Abs(ShipState.ServerRoll - Roll) > 0.1 ||
		bAfterburn != ShipState.ServerbAfterburn ||
		bBurn != ShipState.ServerbBurn ||
		Level.TimeSeconds > NextNetUpdateTime )
	{
		NextNetUpdateTime = Level.TimeSeconds + MaxNetUpdateInterval;
	}
	else
	{
		return;
	}
 
	ShipState.ChassisPosition = ChassisState.Position;
	ShipState.ChassisQuaternion = ChassisState.Quaternion;
	ShipState.ChassisLinVel = ChassisState.LinVel;
	ShipState.ChassisAngVel = ChassisState.AngVel;
 
	// Player Input
	ShipState.ServerSteering = Steering;
	ShipState.ServerThrottle = Throttle;
	ShipState.ServerRoll = Roll;
 
	// AfterBurner
	ShipState.ServerbAfterburn = bAfterburn;
	ShipState.ServerbBurn = bBurn;
 
	// This flag lets the client know this data is new.
	ShipState.bNewState = true;
	//Make sure ShipState gets replicated
	AVar++;
	if (AVar > 10)
		AVar=0;
}
 
simulated function Tick(float DeltaTime)
{
	Super.Tick(DeltaTime);
	if(!KIsAwake() && Controller!=None)
		KWake();
	if(Role == ROLE_Authority && Level.NetMode != NM_StandAlone)
		PackState();
	UpdateAcceleration(DeltaTime);
	UpdateExtraForce(DeltaTime);
}
simulated function UpdateAcceleration(float Delta)
{
	CurSteering = CurSteering + Steering * UnitAccRate * Delta;
	CurThrottle = CurThrottle + Throttle * UnitAccRate * Delta;
	CurRoll     = CurRoll     + Roll     * UnitAccRate * Delta;
	if(Steering==0)
		CurSteering=0;
	if(Throttle==0)
		CurThrottle=0;
	if(Roll==0)
		CurRoll=0;
 
	if(Abs(CurSteering)>Abs(Steering))
		CurSteering=Steering;
	if(Abs(CurThrottle)>Abs(Throttle))
		CurThrottle=Throttle;
	if(Abs(CurRoll)>Abs(Roll))
		CurRoll=Roll;
 
	if(bAfterBurn)
	{
		ReduceAfterBurnEnergy(); // just made this up, put it here incase you have something like this
		if(GetAfterburnEnergy()<=0) // Another fictional function...
		{
			bAfterBurn=False;
		}
		else
		{
			CThrust=AfterBurnThrust;
		}
	}
	if(bBurn && !bAfterBurn && CThrust!=1)
	{
		CThrust=1;
	}
	else if(!bBurn && !bAfterBurn && CThrust!=OldThrust)
	{
		CThrust=OldThrust;
	}
 
	if(TempThrust!=-1 && !bAfterBurn)
	{
		if(Abs(CurThrust-TempThrust)<0.01)
			CurThrust=TempThrust;
		if(CurThrust>TempThrust)
			CurThrust = CurThrust - UnitAccRate * Delta / 4; 
			// I made linear acceleration 4 times slower than rotation, you can do whatever you want though
		else if(CurThrust<TempThrust)
			CurThrust = CurThrust + UnitAccRate * Delta / 4;
	}
	else if(CurThrust!=CThrust && !bAfterBurn)
	{
		if(Abs(CurThrust-CThrust)<0.01)
			CurThrust=CThrust;
		else if(CurThrust>CThrust)
			CurThrust = CurThrust - UnitAccRate * Delta / 4;
		else if(CurThrust<CThrust)
			CurThrust = CurThrust + UnitAccRate * Delta / 4;
	}
	else if(CurThrust!=CThrust && bAfterBurn)
	{
		if(Abs(CurThrust-CThrust)<0.01)
			CurThrust=CThrust;
		else if(CurThrust>CThrust)
			CurThrust = CurThrust - UnitAccRate * Delta / 2.2; // Acceleration with afterburner a lot faster
		else if(CurThrust<CThrust)
			CurThrust = CurThrust + UnitAccRate * Delta / 2.2;
	}
}
 
simulated function UpdateExtraForce(float Delta)
{
	local vector worldForward, worldDown, worldLeft;
 
	worldForward = vect(1, 0, 0) >> Rotation;
	worldDown = vect(0, 0, -1) >> Rotation;
	worldLeft = vect(0, -1, 0) >> Rotation;
 
	ExtraForce = ExtraForce + worldForward * ForwardThrust * Delta * CurThrust; // Speed
	ExtraTorque = ExtraTorque + worldDown * TurnRate * Delta * CurSteering; // Yaw
	ExtraTorque = ExtraTorque + worldLeft * TurnRate * Delta * CurThrottle; // Pitch
	ExtraTorque = ExtraTorque + worldForward * TurnRate * Delta * -CurRoll; // Roll
}
 
simulated event KApplyForce(out vector Force, out vector Torque)
{
	// This actually does the applying of the piled up force
	Force = ExtraForce;
	Torque = ExtraTorque;
	ExtraForce = vect(0,0,0);
	ExtraTorque = vect(0,0,0);
}
 
DefaultProperties
{
     // Create Karma collision Params for ourselves, you can change whatever you want here
     Begin Object Class=KarmaParamsRBFull Name=KParams0
         KLinearDamping=2.000;
         KAngularDamping=2.000;
         KStartEnabled=True
         bHighDetailOnly=False
         bClientOnly=False
         bKDoubleTickRate=False
         KFriction=1.600000
         KActorGravScale = 0.0;
	 KMass=2;
         Name="KParams0"
     End Object
     KParams=KarmaParamsRBFull'<MyPackage>.<MyShipClass>.KParams0'
 
     // And just some other variables:
     TurnRate=8
     ForwardThrust=5000
     UnitAccRate=2.0
     AfterBurnThrust=1.20 // basically means that afterburner goes at 120% of regular maximum speed
}

and that should be it, i hope i didnt miss anything...

Spark: KParams=KarmaParamsRBFull'<MyPackage>.<MyShipClass>.KParams0' <– Is this supposed to be a trap? ;) Took me a while to figure out that my ship didn't fly because this wasn't set to KParams0 and thus wasn't enabled at all. :)

Sir_Brizz: Zep, did you end up getting your Quaternion working for the indicator? I have a few ideas that work if you want to know what they are.

ProjectX: I'm a n00b to coding, but is it possible to take this code, and change it to create a "hovering vehicles" class, that basicly, wont go a certan height above ground, but, from high jumps, etc., go lower to the ground? I also saw that there was 3 types of thrust, is it possible to bind a key that will cycle through the flying types (for more precise flying, eg. for dog matches and realism)?

NickR: Does anyone have a working example of a flying vehicle?

Foxpaw: I do, but my mod is still quite a ways from release. The code above allegedly is working code for a flying vehicle, though I've never tested it.

LiKeMiKeS: I've tried many times compiling this KShip script and have ended up with an error for the ShipState 'struct' & 'var' references obscuring each other and haven't been able to figure out a clean fix so it will compile - without creating another unneeded var instance or reference. I'm still learning the nuances of uscript, so it's difficult to debug atm.