Legacy:KShip - Unreal Wiki

# Legacy:KShip

### From Unreal Wiki, The Unreal Engine Documentation Site

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.

##### Views

- Legacy
- Discussion
- Current revision

##### Search