Ticket #2062: landingFlyingUnits.diff

File landingFlyingUnits.diff, 7.9 KB (added by scythetwirler, 11 years ago)
  • binaries/data/mods/public/simulation/components/UnitMotionFlying.js

     
    11// (A serious implementation of this might want to use C++ instead of JS
    22// for performance; this is just for fun.)
    3 
     3const shortFinal = 2.5;
    44function UnitMotionFlying() {}
    55
    66UnitMotionFlying.prototype.Schema =
    77    "<element name='MaxSpeed'>" +
    88        "<ref name='nonNegativeDecimal'/>" +
    99    "</element>" +
     10    "<element name='TakeoffSpeed'>" +
     11        "<ref name='nonNegativeDecimal'/>" +
     12    "</element>" +
     13    "<element name='LandingSpeed'>" +
     14        "<ref name='nonNegativeDecimal'/>" +
     15    "</element>" +
    1016    "<element name='AccelRate'>" +
    1117        "<ref name='nonNegativeDecimal'/>" +
    1218    "</element>" +
     19    "<element name='SlowingRate'>" +
     20        "<ref name='nonNegativeDecimal'/>" +
     21    "</element>" +
     22    "<element name='BrakingRate'>" +
     23        "<ref name='nonNegativeDecimal'/>" +
     24    "</element>" +
    1325    "<element name='TurnRate'>" +
    1426        "<ref name='nonNegativeDecimal'/>" +
    1527    "</element>" +
     
    3244    this.targetMinRange = 0;
    3345    this.targetMaxRange = 0;
    3446    this.speed = 0;
     47    this.landing = false;
     48    this.onGround = true;
    3549};
    3650
    3751UnitMotionFlying.prototype.OnUpdate = function(msg)
     
    4761
    4862    var canTurn = true;
    4963
    50     // If we haven't reached max speed yet then we're still on the ground;
    51     // otherwise we're taking off or flying
    52     if (this.speed < this.template.MaxSpeed)
     64    if (!this.landing)
    5365    {
    54         // Accelerate forwards
    55         this.speed = Math.min(this.template.MaxSpeed, this.speed + turnLength*this.template.AccelRate);
    56         canTurn = false;
    57 
    58         // Clamp to ground if below it, or descend if above
    59 
     66        // If we haven't reached max speed yet then we're still on the ground;
     67        // otherwise we're taking off or flying
     68        // this.onGround in case of a go-around after landing (but not fully stopped)
    6069        var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain);
    6170        var ground = cmpTerrain.GetGroundLevel(pos.x, pos.z);
    62 
    63         if (pos.y < ground)
    64             pos.y = ground;
    65         else if (pos.y > ground)
    66             pos.y = Math.max(ground, pos.y - turnLength*this.template.ClimbRate);
    67 
     71        if (this.speed < this.template.TakeoffSpeed && this.onGround)
     72        {
     73            // Accelerate forwards
     74            this.speed = Math.min(this.template.MaxSpeed, this.speed + turnLength * this.template.AccelRate);
     75            canTurn = false;
     76            // Clamp to ground if below it, or descend if above
     77            if (pos.y < ground)
     78                pos.y = ground;
     79            else if (pos.y > ground)
     80                pos.y = Math.max(ground, pos.y - turnLength * this.template.ClimbRate);
     81        }
     82        else
     83        {
     84            this.onGround = false;
     85            // Climb/sink to max height above ground
     86            this.speed = Math.min(this.template.MaxSpeed, this.speed + turnLength * this.template.AccelRate);
     87            var targetHeight = ground + (+ this.template.FlyingHeight);
     88            if (pos.y < targetHeight)
     89                pos.y = Math.min(targetHeight, pos.y + turnLength * this.template.ClimbRate);
     90            else if (pos.y > targetHeight)
     91                pos.y = Math.max(targetHeight, pos.y - turnLength * this.template.ClimbRate);           
     92        }
    6893        cmpPosition.SetHeightFixed(pos.y);
    6994    }
    7095    else
    7196    {
    72         // Climb/sink to max height above ground
    73 
    74         var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain);
    75         var ground = cmpTerrain.GetGroundLevel(pos.x, pos.z);
    76 
    77         var targetHeight = ground + (+this.template.FlyingHeight);
    78         if (pos.y < targetHeight)
    79             pos.y = Math.min(targetHeight, pos.y + turnLength*this.template.ClimbRate);
    80         else if (pos.y > targetHeight)
    81             pos.y = Math.max(targetHeight, pos.y - turnLength*this.template.ClimbRate);
    82 
    83         cmpPosition.SetHeightFixed(pos.y);
     97        if (this.speed > 0 && this.onGround)
     98        {
     99            // Deaccelerate forwards...at a very reduced pace.
     100            this.speed = Math.max(0, this.speed - turnLength * this.template.BrakingRate);
     101            canTurn = false;
     102            // Clamp to ground if below it, or descend if above
     103            var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain);
     104            var ground = cmpTerrain.GetGroundLevel(pos.x, pos.z);
     105            if (pos.y < ground)
     106                pos.y = ground;
     107            else if (pos.y > ground)
     108                pos.y = Math.max(ground, pos.y - turnLength * this.template.ClimbRate);
     109            cmpPosition.SetHeightFixed(pos.y);         
     110        }
     111        else if (this.speed == 0)
     112        {
     113            // We've stopped.
     114            canTurn = false;
     115            this.hasTarget = false;
     116            this.landing = false;                   
     117        }
     118        else
     119        {
     120            // Final Approach
     121            // We need to slow down to land!
     122            this.speed = Math.max(this.template.LandingSpeed, this.speed - turnLength * this.template.SlowingRate);
     123            canTurn = false;
     124            var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain);
     125            var ground = cmpTerrain.GetGroundLevel(pos.x, pos.z);
     126            var targetHeight = ground;
     127            // Steep, then gradual descent.
     128            var descentRate = ((pos.y - targetHeight) / this.template.FlyingHeight * this.template.ClimbRate + shortFinal) * shortFinal;
     129            if (pos.y < targetHeight)
     130                pos.y = Math.max(targetHeight, pos.y + turnLength * descentRate);
     131            else if (pos.y > targetHeight)
     132                pos.y = Math.max(targetHeight, pos.y - turnLength * descentRate);
     133            if (targetHeight == pos.y)
     134                this.onGround = true;
     135            cmpPosition.SetHeightFixed(pos.y);
     136        }       
    84137    }
    85138
    86139    // If we're in range of the target then tell people that we've reached it
     
    94147
    95148    // If we're facing away from the target, and are still fairly close to it,
    96149    // then carry on going straight so we overshoot in a straight line
    97     var isBehindTarget = ((this.targetX - pos.x)*Math.sin(angle) + (this.targetZ - pos.z)*Math.cos(angle) < 0);
    98     if (isBehindTarget && distFromTarget < this.template.MaxSpeed*this.template.OvershootTime)
    99     {
    100         // Overshoot the target: carry on straight
     150    var isBehindTarget = ((this.targetX - pos.x) * Math.sin(angle) + (this.targetZ - pos.z) * Math.cos(angle) < 0);
     151    // Overshoot the target: carry on straight
     152    if (isBehindTarget && distFromTarget < this.template.MaxSpeed * this.template.OvershootTime)
    101153        canTurn = false;
    102     }
    103154
    104155    if (canTurn)
    105156    {
    106157        // Turn towards the target
    107 
    108158        var targetAngle = Math.atan2(this.targetX - pos.x, this.targetZ - pos.z);
    109 
    110159        var delta = targetAngle - angle;
    111160        // Wrap delta to -pi..pi
    112161        delta = (delta + Math.PI) % (2*Math.PI); // range -2pi..2pi
    113162        if (delta < 0) delta += 2*Math.PI; // range 0..2pi
    114163        delta -= Math.PI; // range -pi..pi
    115164        // Clamp to max rate
    116         var deltaClamped = Math.min(Math.max(delta, -this.template.TurnRate*turnLength), this.template.TurnRate*turnLength);
     165        var deltaClamped = Math.min(Math.max(delta, -this.template.TurnRate * turnLength), this.template.TurnRate*turnLength);
    117166        // Calculate new orientation, in a peculiar way in order to make sure the
    118167        // result gets close to targetAngle (rather than being n*2*pi out)
    119168        angle = targetAngle + deltaClamped - delta;
     
    201250
    202251UnitMotionFlying.prototype.StopMoving = function()
    203252{
    204     // Ignore this - we can never stop moving
     253    //Invert
     254    this.landing = !this.landing;
    205255};
    206256
    207257UnitMotionFlying.prototype.SetDebugOverlay = function(enabled)
  • binaries/data/mods/public/simulation/templates/other/plane.xml

     
    2727  </Position>
    2828  <UnitMotion disable=""/>
    2929  <UnitMotionFlying>
    30     <MaxSpeed>40.0</MaxSpeed>
    31     <AccelRate>15.0</AccelRate>
     30    <MaxSpeed>60.0</MaxSpeed>
     31    <TakeoffSpeed>50.0</TakeoffSpeed>
     32    <LandingSpeed>40.0</LandingSpeed>
     33    <AccelRate>25.0</AccelRate>
     34    <SlowingRate>5.0</SlowingRate>
     35    <BrakingRate>10.0</BrakingRate>
    3236    <TurnRate>1.0</TurnRate>
    3337    <OvershootTime>2.0</OvershootTime>
    3438    <FlyingHeight>50.0</FlyingHeight>
     
    3943  </Vision>
    4044  <VisualActor>
    4145    <Actor>units/global/plane.xml</Actor>
    42   </VisualActor>
     46  </VisualActor> 
    4347</Entity>