Ticket #2062: landingFlyingUnits.diff
File landingFlyingUnits.diff, 7.9 KB (added by , 11 years ago) |
---|
-
binaries/data/mods/public/simulation/components/UnitMotionFlying.js
1 1 // (A serious implementation of this might want to use C++ instead of JS 2 2 // for performance; this is just for fun.) 3 3 const shortFinal = 2.5; 4 4 function UnitMotionFlying() {} 5 5 6 6 UnitMotionFlying.prototype.Schema = 7 7 "<element name='MaxSpeed'>" + 8 8 "<ref name='nonNegativeDecimal'/>" + 9 9 "</element>" + 10 "<element name='TakeoffSpeed'>" + 11 "<ref name='nonNegativeDecimal'/>" + 12 "</element>" + 13 "<element name='LandingSpeed'>" + 14 "<ref name='nonNegativeDecimal'/>" + 15 "</element>" + 10 16 "<element name='AccelRate'>" + 11 17 "<ref name='nonNegativeDecimal'/>" + 12 18 "</element>" + 19 "<element name='SlowingRate'>" + 20 "<ref name='nonNegativeDecimal'/>" + 21 "</element>" + 22 "<element name='BrakingRate'>" + 23 "<ref name='nonNegativeDecimal'/>" + 24 "</element>" + 13 25 "<element name='TurnRate'>" + 14 26 "<ref name='nonNegativeDecimal'/>" + 15 27 "</element>" + … … 32 44 this.targetMinRange = 0; 33 45 this.targetMaxRange = 0; 34 46 this.speed = 0; 47 this.landing = false; 48 this.onGround = true; 35 49 }; 36 50 37 51 UnitMotionFlying.prototype.OnUpdate = function(msg) … … 47 61 48 62 var canTurn = true; 49 63 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) 53 65 { 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) 60 69 var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain); 61 70 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 } 68 93 cmpPosition.SetHeightFixed(pos.y); 69 94 } 70 95 else 71 96 { 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 } 84 137 } 85 138 86 139 // If we're in range of the target then tell people that we've reached it … … 94 147 95 148 // If we're facing away from the target, and are still fairly close to it, 96 149 // 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) 101 153 canTurn = false; 102 }103 154 104 155 if (canTurn) 105 156 { 106 157 // Turn towards the target 107 108 158 var targetAngle = Math.atan2(this.targetX - pos.x, this.targetZ - pos.z); 109 110 159 var delta = targetAngle - angle; 111 160 // Wrap delta to -pi..pi 112 161 delta = (delta + Math.PI) % (2*Math.PI); // range -2pi..2pi 113 162 if (delta < 0) delta += 2*Math.PI; // range 0..2pi 114 163 delta -= Math.PI; // range -pi..pi 115 164 // 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); 117 166 // Calculate new orientation, in a peculiar way in order to make sure the 118 167 // result gets close to targetAngle (rather than being n*2*pi out) 119 168 angle = targetAngle + deltaClamped - delta; … … 201 250 202 251 UnitMotionFlying.prototype.StopMoving = function() 203 252 { 204 // Ignore this - we can never stop moving 253 //Invert 254 this.landing = !this.landing; 205 255 }; 206 256 207 257 UnitMotionFlying.prototype.SetDebugOverlay = function(enabled) -
binaries/data/mods/public/simulation/templates/other/plane.xml
27 27 </Position> 28 28 <UnitMotion disable=""/> 29 29 <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> 32 36 <TurnRate>1.0</TurnRate> 33 37 <OvershootTime>2.0</OvershootTime> 34 38 <FlyingHeight>50.0</FlyingHeight> … … 39 43 </Vision> 40 44 <VisualActor> 41 45 <Actor>units/global/plane.xml</Actor> 42 </VisualActor> 46 </VisualActor> 43 47 </Entity>