Mostly Harmless
Legacy:KShip
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?