| Home Page | Recent Changes

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?

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

Recent Changes

Offline Wiki

Unreal Engine

Console Commands

Terminology

FAQs

Help Desk

Mapping Topics

Mapping Lessons

UnrealEd Interface

UnrealScript Topics

UnrealScript Lessons

Making Mods

Class Tree

Modeling Topics

Chongqing Page

Log In