mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-07-04 05:55:47 -07:00
Switch to column formation when moving longer distances.
Increase minimum box formation width to 5. This was SVN commit r8243.
This commit is contained in:
parent
7ea522a484
commit
7412e5563a
2 changed files with 104 additions and 11 deletions
|
|
@ -3,9 +3,12 @@ function Formation() {}
|
|||
Formation.prototype.Schema =
|
||||
"<a:component type='system'/><empty/>";
|
||||
|
||||
var g_ColumnDistanceThreshold = 32; // distance at which we'll switch between column/box formations
|
||||
|
||||
Formation.prototype.Init = function()
|
||||
{
|
||||
this.members = [];
|
||||
this.members = []; // entity IDs currently belonging to this formation
|
||||
this.columnar = false; // whether we're travelling in column (vs box) formation
|
||||
};
|
||||
|
||||
Formation.prototype.GetMemberCount = function()
|
||||
|
|
@ -111,7 +114,12 @@ Formation.prototype.MoveMembersIntoFormation = function()
|
|||
types["Unknown"] += 1; // TODO
|
||||
}
|
||||
|
||||
var offsets = this.ComputeFormationOffsets(types);
|
||||
// Work out whether this should be a column or box formation
|
||||
var cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI);
|
||||
var walkingDistance = cmpUnitAI.ComputeWalkingDistance();
|
||||
this.columnar = (walkingDistance > g_ColumnDistanceThreshold);
|
||||
|
||||
var offsets = this.ComputeFormationOffsets(types, this.columnar);
|
||||
|
||||
var avgpos = this.ComputeAveragePosition(positions);
|
||||
var avgoffset = this.ComputeAveragePosition(offsets);
|
||||
|
|
@ -153,22 +161,35 @@ Formation.prototype.MoveToMembersCenter = function()
|
|||
cmpPosition.JumpTo(avgpos.x, avgpos.z);
|
||||
};
|
||||
|
||||
Formation.prototype.ComputeFormationOffsets = function(types)
|
||||
Formation.prototype.ComputeFormationOffsets = function(types, columnar)
|
||||
{
|
||||
var separation = 4; // TODO: don't hardcode this
|
||||
|
||||
var count = types["Unknown"];
|
||||
|
||||
// Choose a sensible width for the basic box formation
|
||||
// Choose a sensible width for the basic default formation
|
||||
var cols;
|
||||
if (count <= 4)
|
||||
cols = count;
|
||||
if (count <= 8)
|
||||
cols = 4;
|
||||
else if (count <= 16)
|
||||
cols = Math.ceil(count / 2);
|
||||
if (columnar)
|
||||
{
|
||||
// Have at most 3 files
|
||||
if (count <= 3)
|
||||
cols = count;
|
||||
else
|
||||
cols = 3;
|
||||
}
|
||||
else
|
||||
cols = 8;
|
||||
{
|
||||
// Try to have at least 5 files (so batch training gives a single line),
|
||||
// and at most 8
|
||||
if (count <= 5)
|
||||
cols = count;
|
||||
if (count <= 10)
|
||||
cols = 5;
|
||||
else if (count <= 16)
|
||||
cols = Math.ceil(count / 2);
|
||||
else
|
||||
cols = 8;
|
||||
}
|
||||
|
||||
var ranks = Math.ceil(count / cols);
|
||||
|
||||
|
|
@ -228,6 +249,16 @@ Formation.prototype.ComputeMotionParameters = function()
|
|||
// TODO: we also need to do something about PassabilityClass, CostClass
|
||||
};
|
||||
|
||||
Formation.prototype.OnUpdate_Final = function(msg)
|
||||
{
|
||||
// Switch between column and box if necessary
|
||||
var cmpUnitAI = Engine.QueryInterface(this.entity, IID_UnitAI);
|
||||
var walkingDistance = cmpUnitAI.ComputeWalkingDistance();
|
||||
var columnar = (walkingDistance > g_ColumnDistanceThreshold);
|
||||
if (columnar != this.columnar)
|
||||
this.MoveMembersIntoFormation();
|
||||
};
|
||||
|
||||
Formation.prototype.OnGlobalOwnershipChanged = function(msg)
|
||||
{
|
||||
// When an entity is captured or destroyed, it should no longer be
|
||||
|
|
|
|||
|
|
@ -848,6 +848,68 @@ UnitAI.prototype.GetFormationController = function()
|
|||
return this.formationController;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the estimated distance that this unit will travel before either
|
||||
* finishing all of its orders, or reaching a non-walk target (attack, gather, etc).
|
||||
* Intended for Formation to switch to column layout on long walks.
|
||||
*/
|
||||
UnitAI.prototype.ComputeWalkingDistance = function()
|
||||
{
|
||||
var distance = 0;
|
||||
|
||||
var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
|
||||
if (!cmpPosition || !cmpPosition.IsInWorld())
|
||||
return 0;
|
||||
|
||||
// Keep track of the position at the start of each order
|
||||
var pos = cmpPosition.GetPosition();
|
||||
|
||||
for (var i = 0; i < this.orderQueue.length; ++i)
|
||||
{
|
||||
var order = this.orderQueue[i];
|
||||
switch (order.type)
|
||||
{
|
||||
case "Walk":
|
||||
// Add the distance to the target point
|
||||
var dx = order.data.x - pos.x;
|
||||
var dz = order.data.z - pos.z;
|
||||
var d = Math.sqrt(dx*dx + dz*dz);
|
||||
distance += d;
|
||||
|
||||
// Remember this as the start position for the next order
|
||||
pos = order.data;
|
||||
|
||||
break; // and continue the loop
|
||||
|
||||
case "WalkToTarget":
|
||||
case "Attack":
|
||||
case "Gather":
|
||||
case "Repair":
|
||||
// Find the target unit's position
|
||||
var cmpTargetPosition = Engine.QueryInterface(order.data.target, IID_Position);
|
||||
if (!cmpTargetPosition || !cmpTargetPosition.IsInWorld())
|
||||
return distance;
|
||||
var targetPos = cmpTargetPosition.GetPosition();
|
||||
|
||||
// Add the distance to the target unit
|
||||
var dx = targetPos.x - pos.x;
|
||||
var dz = targetPos.z - pos.z;
|
||||
var d = Math.sqrt(dx*dx + dz*dz);
|
||||
distance += d;
|
||||
|
||||
// Return the total distance to the target
|
||||
return distance;
|
||||
|
||||
default:
|
||||
error("Unrecognised order type '"+order.type+"'");
|
||||
return distance;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the total distance to the end of the order queue
|
||||
return distance;
|
||||
};
|
||||
|
||||
UnitAI.prototype.AddOrder = function(type, data, queued)
|
||||
{
|
||||
if (queued)
|
||||
|
|
|
|||
Loading…
Reference in a new issue