| Home Page | Recent Changes | Preferences

# 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 )

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.

The Unreal Engine Documentation Site

Wiki Community

Topic Categories

Image Uploads

Random Page

Recent Changes

Offline Wiki

Unreal Engine

Console Commands

Terminology

Mapping Topics

Mapping Lessons

UnrealEd Interface

Questions&Answers

Scripting Topics

Scripting Lessons

Making Mods

Class Tree

Questions&Answers

Modeling Topics

Questions&Answers

Log In