Differential D2457 Diff 11833 ps/trunk/binaries/data/mods/public/simulation/components/UnitMotionFlying.js
Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/binaries/data/mods/public/simulation/components/UnitMotionFlying.js
Show First 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | UnitMotionFlying.prototype.Init = function() | ||||
this.pitch = 0; | this.pitch = 0; | ||||
this.roll = 0; | this.roll = 0; | ||||
this.waterDeath = false; | this.waterDeath = false; | ||||
this.passabilityClass = Engine.QueryInterface(SYSTEM_ENTITY, IID_Pathfinder).GetPassabilityClass(this.template.PassabilityClass); | this.passabilityClass = Engine.QueryInterface(SYSTEM_ENTITY, IID_Pathfinder).GetPassabilityClass(this.template.PassabilityClass); | ||||
}; | }; | ||||
UnitMotionFlying.prototype.OnUpdate = function(msg) | UnitMotionFlying.prototype.OnUpdate = function(msg) | ||||
{ | { | ||||
var turnLength = msg.turnLength; | let turnLength = msg.turnLength; | ||||
if (!this.hasTarget) | if (!this.hasTarget) | ||||
return; | return; | ||||
var cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder); | let cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder); | ||||
var cmpHealth = Engine.QueryInterface(this.entity, IID_Health); | let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | ||||
var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | let pos = cmpPosition.GetPosition(); | ||||
var pos = cmpPosition.GetPosition(); | let angle = cmpPosition.GetRotation().y; | ||||
var angle = cmpPosition.GetRotation().y; | let cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain); | ||||
var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain); | let cmpWaterManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_WaterManager); | ||||
var cmpWaterManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_WaterManager); | let ground = Math.max(cmpTerrain.GetGroundLevel(pos.x, pos.z), cmpWaterManager.GetWaterLevel(pos.x, pos.z)); | ||||
var ground = Math.max(cmpTerrain.GetGroundLevel(pos.x, pos.z), cmpWaterManager.GetWaterLevel(pos.x, pos.z)); | let newangle = angle; | ||||
var newangle = angle; | let canTurn = true; | ||||
var canTurn = true; | |||||
if (this.landing) | if (this.landing) | ||||
{ | { | ||||
if (this.speed > 0 && this.onGround) | if (this.speed > 0 && this.onGround) | ||||
{ | { | ||||
if (pos.y <= cmpWaterManager.GetWaterLevel(pos.x, pos.z) && this.template.DiesInWater == "true") | if (pos.y <= cmpWaterManager.GetWaterLevel(pos.x, pos.z) && this.template.DiesInWater == "true") | ||||
this.waterDeath = true; | this.waterDeath = true; | ||||
this.pitch = 0; | this.pitch = 0; | ||||
// Deaccelerate forwards...at a very reduced pace. | // Deaccelerate forwards...at a very reduced pace. | ||||
if (this.waterDeath) | if (this.waterDeath) | ||||
this.speed = Math.max(0, this.speed - turnLength * this.template.BrakingRate * 10); | this.speed = Math.max(0, this.speed - turnLength * this.template.BrakingRate * 10); | ||||
else | else | ||||
this.speed = Math.max(0, this.speed - turnLength * this.template.BrakingRate); | this.speed = Math.max(0, this.speed - turnLength * this.template.BrakingRate); | ||||
canTurn = false; | canTurn = false; | ||||
// Clamp to ground if below it, or descend if above | // Clamp to ground if below it, or descend if above. | ||||
if (pos.y < ground) | if (pos.y < ground) | ||||
pos.y = ground; | pos.y = ground; | ||||
else if (pos.y > ground) | else if (pos.y > ground) | ||||
pos.y = Math.max(ground, pos.y - turnLength * this.template.ClimbRate); | pos.y = Math.max(ground, pos.y - turnLength * this.template.ClimbRate); | ||||
} | } | ||||
else if (this.speed == 0 && this.onGround) | else if (this.speed == 0 && this.onGround) | ||||
{ | { | ||||
let cmpHealth = Engine.QueryInterface(this.entity, IID_Health); | |||||
if (this.waterDeath && cmpHealth) | if (this.waterDeath && cmpHealth) | ||||
cmpHealth.Kill(); | cmpHealth.Kill(); | ||||
else | else | ||||
{ | { | ||||
this.pitch = 0; | this.pitch = 0; | ||||
// We've stopped. | // We've stopped. | ||||
if (cmpGarrisonHolder) | if (cmpGarrisonHolder) | ||||
cmpGarrisonHolder.AllowGarrisoning(true,"UnitMotionFlying"); | cmpGarrisonHolder.AllowGarrisoning(true, "UnitMotionFlying"); | ||||
canTurn = false; | canTurn = false; | ||||
this.hasTarget = false; | this.hasTarget = false; | ||||
this.landing = false; | this.landing = false; | ||||
// summon planes back from the edge of the map | // Summon planes back from the edge of the map. | ||||
var terrainSize = cmpTerrain.GetMapSize(); | let terrainSize = cmpTerrain.GetMapSize(); | ||||
var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); | let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); | ||||
if (cmpRangeManager.GetLosCircular()) | if (cmpRangeManager.GetLosCircular()) | ||||
{ | { | ||||
var mapRadius = terrainSize/2; | let mapRadius = terrainSize/2; | ||||
var x = pos.x - mapRadius; | let x = pos.x - mapRadius; | ||||
var z = pos.z - mapRadius; | let z = pos.z - mapRadius; | ||||
var div = (mapRadius - 12) / Math.sqrt(x*x + z*z); | let div = (mapRadius - 12) / Math.sqrt(x*x + z*z); | ||||
if (div < 1) | if (div < 1) | ||||
{ | { | ||||
pos.x = mapRadius + x*div; | pos.x = mapRadius + x*div; | ||||
pos.z = mapRadius + z*div; | pos.z = mapRadius + z*div; | ||||
newangle += Math.PI; | newangle += Math.PI; | ||||
} | } | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
pos.x = Math.max(Math.min(pos.x, terrainSize - 12), 12); | pos.x = Math.max(Math.min(pos.x, terrainSize - 12), 12); | ||||
pos.z = Math.max(Math.min(pos.z, terrainSize - 12), 12); | pos.z = Math.max(Math.min(pos.z, terrainSize - 12), 12); | ||||
newangle += Math.PI; | newangle += Math.PI; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
// Final Approach | // Final Approach. | ||||
// We need to slow down to land! | // We need to slow down to land! | ||||
this.speed = Math.max(this.template.LandingSpeed, this.speed - turnLength * this.template.SlowingRate); | this.speed = Math.max(this.template.LandingSpeed, this.speed - turnLength * this.template.SlowingRate); | ||||
canTurn = false; | canTurn = false; | ||||
var targetHeight = ground; | let targetHeight = ground; | ||||
// Steep, then gradual descent. | // Steep, then gradual descent. | ||||
if ((pos.y - targetHeight) / this.template.FlyingHeight > 1 / SHORT_FINAL) | if ((pos.y - targetHeight) / this.template.FlyingHeight > 1 / SHORT_FINAL) | ||||
this.pitch = - Math.PI / 18; | this.pitch = -Math.PI / 18; | ||||
else | else | ||||
this.pitch = Math.PI / 18; | this.pitch = Math.PI / 18; | ||||
var descentRate = ((pos.y - targetHeight) / this.template.FlyingHeight * this.template.ClimbRate + SHORT_FINAL) * SHORT_FINAL; | let descentRate = ((pos.y - targetHeight) / this.template.FlyingHeight * this.template.ClimbRate + SHORT_FINAL) * SHORT_FINAL; | ||||
if (pos.y < targetHeight) | if (pos.y < targetHeight) | ||||
pos.y = Math.max(targetHeight, pos.y + turnLength * descentRate); | pos.y = Math.max(targetHeight, pos.y + turnLength * descentRate); | ||||
else if (pos.y > targetHeight) | else if (pos.y > targetHeight) | ||||
pos.y = Math.max(targetHeight, pos.y - turnLength * descentRate); | pos.y = Math.max(targetHeight, pos.y - turnLength * descentRate); | ||||
if (targetHeight == pos.y) | if (targetHeight == pos.y) | ||||
{ | { | ||||
this.onGround = true; | this.onGround = true; | ||||
if (targetHeight == cmpWaterManager.GetWaterLevel(pos.x, pos.z) && this.template.DiesInWater) | if (targetHeight == cmpWaterManager.GetWaterLevel(pos.x, pos.z) && this.template.DiesInWater) | ||||
this.waterDeath = true; | this.waterDeath = true; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
// If we haven't reached max speed yet then we're still on the ground; | // If we haven't reached max speed yet then we're still on the ground; | ||||
// otherwise we're taking off or flying | // otherwise we're taking off or flying. | ||||
// this.onGround in case of a go-around after landing (but not fully stopped) | // this.onGround in case of a go-around after landing (but not fully stopped). | ||||
if (this.speed < this.template.TakeoffSpeed && this.onGround) | if (this.speed < this.template.TakeoffSpeed && this.onGround) | ||||
{ | { | ||||
if (cmpGarrisonHolder) | if (cmpGarrisonHolder) | ||||
cmpGarrisonHolder.AllowGarrisoning(false,"UnitMotionFlying"); | cmpGarrisonHolder.AllowGarrisoning(false, "UnitMotionFlying"); | ||||
this.pitch = 0; | this.pitch = 0; | ||||
// Accelerate forwards | // Accelerate forwards. | ||||
this.speed = Math.min(this.template.MaxSpeed, this.speed + turnLength * this.template.AccelRate); | this.speed = Math.min(this.template.MaxSpeed, this.speed + turnLength * this.template.AccelRate); | ||||
canTurn = false; | canTurn = false; | ||||
// Clamp to ground if below it, or descend if above | // Clamp to ground if below it, or descend if above. | ||||
if (pos.y < ground) | if (pos.y < ground) | ||||
pos.y = ground; | pos.y = ground; | ||||
else if (pos.y > ground) | else if (pos.y > ground) | ||||
pos.y = Math.max(ground, pos.y - turnLength * this.template.ClimbRate); | pos.y = Math.max(ground, pos.y - turnLength * this.template.ClimbRate); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
this.onGround = false; | this.onGround = false; | ||||
// Climb/sink to max height above ground | // Climb/sink to max height above ground. | ||||
this.speed = Math.min(this.template.MaxSpeed, this.speed + turnLength * this.template.AccelRate); | this.speed = Math.min(this.template.MaxSpeed, this.speed + turnLength * this.template.AccelRate); | ||||
var targetHeight = ground + (+this.template.FlyingHeight); | let targetHeight = ground + (+this.template.FlyingHeight); | ||||
if (Math.abs(pos.y-targetHeight) > this.template.FlyingHeight/5) | if (Math.abs(pos.y-targetHeight) > this.template.FlyingHeight/5) | ||||
{ | { | ||||
this.pitch = Math.PI / 9; | this.pitch = Math.PI / 9; | ||||
canTurn = false; | canTurn = false; | ||||
} | } | ||||
else | else | ||||
this.pitch = 0; | this.pitch = 0; | ||||
if (pos.y < targetHeight) | if (pos.y < targetHeight) | ||||
pos.y = Math.min(targetHeight, pos.y + turnLength * this.template.ClimbRate); | pos.y = Math.min(targetHeight, pos.y + turnLength * this.template.ClimbRate); | ||||
else if (pos.y > targetHeight) | else if (pos.y > targetHeight) | ||||
{ | { | ||||
pos.y = Math.max(targetHeight, pos.y - turnLength * this.template.ClimbRate); | pos.y = Math.max(targetHeight, pos.y - turnLength * this.template.ClimbRate); | ||||
this.pitch = -1 * this.pitch; | this.pitch = -1 * this.pitch; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// If we're in range of the target then tell people that we've reached it | // If we're in range of the target then tell people that we've reached it. | ||||
// (TODO: quantisation breaks this) | // (TODO: quantisation breaks this) | ||||
var distFromTarget = Math.euclidDistance2D(pos.x, pos.z, this.targetX, this.targetZ); | let distFromTarget = Math.euclidDistance2D(pos.x, pos.z, this.targetX, this.targetZ); | ||||
if (!this.reachedTarget && this.targetMinRange <= distFromTarget && distFromTarget <= this.targetMaxRange) | if (!this.reachedTarget && this.targetMinRange <= distFromTarget && distFromTarget <= this.targetMaxRange) | ||||
{ | { | ||||
this.reachedTarget = true; | this.reachedTarget = true; | ||||
Engine.PostMessage(this.entity, MT_MotionUpdate, { "updateString": "likelySuccess" }); | Engine.PostMessage(this.entity, MT_MotionUpdate, { "updateString": "likelySuccess" }); | ||||
} | } | ||||
// If we're facing away from the target, and are still fairly close to it, | // If we're facing away from the target, and are still fairly close to it, | ||||
// then carry on going straight so we overshoot in a straight line | // then carry on going straight so we overshoot in a straight line. | ||||
var isBehindTarget = ((this.targetX - pos.x) * Math.sin(angle) + (this.targetZ - pos.z) * Math.cos(angle) < 0); | let isBehindTarget = ((this.targetX - pos.x) * Math.sin(angle) + (this.targetZ - pos.z) * Math.cos(angle) < 0); | ||||
// Overshoot the target: carry on straight | // Overshoot the target: carry on straight. | ||||
if (isBehindTarget && distFromTarget < this.template.MaxSpeed * this.template.OvershootTime) | if (isBehindTarget && distFromTarget < this.template.MaxSpeed * this.template.OvershootTime) | ||||
canTurn = false; | canTurn = false; | ||||
if (canTurn) | if (canTurn) | ||||
{ | { | ||||
// Turn towards the target | // Turn towards the target. | ||||
var targetAngle = Math.atan2(this.targetX - pos.x, this.targetZ - pos.z); | let targetAngle = Math.atan2(this.targetX - pos.x, this.targetZ - pos.z); | ||||
var delta = targetAngle - angle; | let delta = targetAngle - angle; | ||||
// Wrap delta to -pi..pi | // Wrap delta to -pi..pi. | ||||
delta = (delta + Math.PI) % (2*Math.PI); // range -2pi..2pi | delta = (delta + Math.PI) % (2*Math.PI); | ||||
if (delta < 0) delta += 2*Math.PI; // range 0..2pi | if (delta < 0) | ||||
delta -= Math.PI; // range -pi..pi | delta += 2 * Math.PI; | ||||
// Clamp to max rate | delta -= Math.PI; | ||||
var deltaClamped = Math.min(Math.max(delta, -this.template.TurnRate * turnLength), this.template.TurnRate * turnLength); | // Clamp to max rate. | ||||
let deltaClamped = Math.min(Math.max(delta, -this.template.TurnRate * turnLength), this.template.TurnRate * turnLength); | |||||
// Calculate new orientation, in a peculiar way in order to make sure the | // Calculate new orientation, in a peculiar way in order to make sure the | ||||
// result gets close to targetAngle (rather than being n*2*pi out) | // result gets close to targetAngle (rather than being n*2*pi out). | ||||
newangle = targetAngle + deltaClamped - delta; | newangle = targetAngle + deltaClamped - delta; | ||||
if (newangle - angle > Math.PI / 18) | if (newangle - angle > Math.PI / 18) | ||||
this.roll = Math.PI / 9; | this.roll = Math.PI / 9; | ||||
else if (newangle - angle < -Math.PI / 18) | else if (newangle - angle < -Math.PI / 18) | ||||
this.roll = - Math.PI / 9; | this.roll = -Math.PI / 9; | ||||
else | else | ||||
this.roll = newangle - angle; | this.roll = newangle - angle; | ||||
} | } | ||||
else | else | ||||
this.roll = 0; | this.roll = 0; | ||||
pos.x += this.speed * turnLength * Math.sin(angle); | pos.x += this.speed * turnLength * Math.sin(angle); | ||||
pos.z += this.speed * turnLength * Math.cos(angle); | pos.z += this.speed * turnLength * Math.cos(angle); | ||||
Show All 13 Lines | UnitMotionFlying.prototype.MoveToPointRange = function(x, z, minRange, maxRange) | ||||
this.targetMinRange = minRange; | this.targetMinRange = minRange; | ||||
this.targetMaxRange = maxRange; | this.targetMaxRange = maxRange; | ||||
return true; | return true; | ||||
}; | }; | ||||
UnitMotionFlying.prototype.MoveToTargetRange = function(target, minRange, maxRange) | UnitMotionFlying.prototype.MoveToTargetRange = function(target, minRange, maxRange) | ||||
{ | { | ||||
var cmpTargetPosition = Engine.QueryInterface(target, IID_Position); | let cmpTargetPosition = Engine.QueryInterface(target, IID_Position); | ||||
if (!cmpTargetPosition || !cmpTargetPosition.IsInWorld()) | if (!cmpTargetPosition || !cmpTargetPosition.IsInWorld()) | ||||
return false; | return false; | ||||
var targetPos = cmpTargetPosition.GetPosition2D(); | let targetPos = cmpTargetPosition.GetPosition2D(); | ||||
this.hasTarget = true; | this.hasTarget = true; | ||||
this.reachedTarget = false; | this.reachedTarget = false; | ||||
this.targetX = targetPos.x; | this.targetX = targetPos.x; | ||||
this.targetZ = targetPos.y; | this.targetZ = targetPos.y; | ||||
this.targetMinRange = minRange; | this.targetMinRange = minRange; | ||||
this.targetMaxRange = maxRange; | this.targetMaxRange = maxRange; | ||||
return true; | return true; | ||||
}; | }; | ||||
UnitMotionFlying.prototype.GetWalkSpeed = function() | UnitMotionFlying.prototype.GetWalkSpeed = function() | ||||
{ | { | ||||
return +this.template.MaxSpeed; | return +this.template.MaxSpeed; | ||||
}; | }; | ||||
UnitMotionFlying.prototype.SetSpeedMultiplier = function() | UnitMotionFlying.prototype.SetSpeedMultiplier = function(multiplier) | ||||
{ | { | ||||
// ignore this, the speed is always the walk speed | // Ignore this, the speed is always the walk speed. | ||||
}; | }; | ||||
UnitMotionFlying.prototype.GetRunMultiplier = function() | UnitMotionFlying.prototype.GetRunMultiplier = function() | ||||
{ | { | ||||
return 1; | return 1; | ||||
}; | }; | ||||
UnitMotionFlying.prototype.IsMoveRequested = function() | UnitMotionFlying.prototype.IsMoveRequested = function() | ||||
{ | { | ||||
return this.hasTarget; | return this.hasTarget; | ||||
}; | }; | ||||
UnitMotionFlying.prototype.GetCurrentSpeed = function() | UnitMotionFlying.prototype.GetCurrentSpeed = function() | ||||
{ | { | ||||
return this.speed; | return this.speed; | ||||
}; | }; | ||||
UnitMotionFlying.prototype.GetSpeedMultiplier = function() | UnitMotionFlying.prototype.GetSpeedMultiplier = function() | ||||
{ | { | ||||
return this.GetCurrentSpeed() / this.GetWalkSpeed(); | return this.speed / +this.template.MaxSpeed; | ||||
}; | }; | ||||
UnitMotionFlying.prototype.GetPassabilityClassName = function() | UnitMotionFlying.prototype.GetPassabilityClassName = function() | ||||
{ | { | ||||
return this.template.PassabilityClass; | return this.template.PassabilityClass; | ||||
}; | }; | ||||
UnitMotionFlying.prototype.GetPassabilityClass = function() | UnitMotionFlying.prototype.GetPassabilityClass = function() | ||||
{ | { | ||||
return this.passabilityClass; | return this.passabilityClass; | ||||
}; | }; | ||||
UnitMotionFlying.prototype.FaceTowardsPoint = function(x, z) | UnitMotionFlying.prototype.FaceTowardsPoint = function(x, z) | ||||
{ | { | ||||
// Ignore this - angle is controlled by the target-seeking code instead | // Ignore this - angle is controlled by the target-seeking code instead. | ||||
}; | }; | ||||
UnitMotionFlying.prototype.SetFacePointAfterMove = function() | UnitMotionFlying.prototype.SetFacePointAfterMove = function() | ||||
{ | { | ||||
// Ignore this - angle is controlled by the target-seeking code instead | // Ignore this - angle is controlled by the target-seeking code instead. | ||||
}; | }; | ||||
UnitMotionFlying.prototype.StopMoving = function() | UnitMotionFlying.prototype.StopMoving = function() | ||||
{ | { | ||||
//Invert | // Invert. | ||||
if (!this.waterDeath) | if (!this.waterDeath) | ||||
this.landing = !this.landing; | this.landing = !this.landing; | ||||
}; | }; | ||||
UnitMotionFlying.prototype.SetDebugOverlay = function(enabled) | UnitMotionFlying.prototype.SetDebugOverlay = function(enabled) | ||||
{ | { | ||||
}; | }; | ||||
Engine.RegisterComponentType(IID_UnitMotion, "UnitMotionFlying", UnitMotionFlying); | Engine.RegisterComponentType(IID_UnitMotion, "UnitMotionFlying", UnitMotionFlying); |
Wildfire Games · Phabricator