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:
Ykkrosh 2010-10-02 19:40:30 +00:00
parent 7ea522a484
commit 7412e5563a
2 changed files with 104 additions and 11 deletions

View file

@ -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

View file

@ -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)