forked from 0ad/0ad
Support inverted goals with the long-range pathfinder. This allows units to flee and should fix problems with ranged units too close to their targets. Fixes #3405, refs #3372.
Now that units flee it's necessary to fix the unit chasing: this commit
reintroduces some code from 298115f4c5
that disappeared with the
committing of the new pathfinder. Refs #1537.
Also includes some style improvements to the UnitMotion code.
This was SVN commit r17013.
This commit is contained in:
parent
bbcf996531
commit
03d2c5e40b
@ -1036,13 +1036,10 @@ void CCmpUnitMotion::Move(fixed dt)
|
||||
// nearest point on the square, not towards its center
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we have a target entity, and we're not miles away from the end of
|
||||
// our current path, and the target moved enough, then recompute our
|
||||
// whole path
|
||||
if (m_PathState == PATHSTATE_FOLLOWING)
|
||||
{
|
||||
// If we have a target entity, and we're not miles away from the end of
|
||||
// our current path, and the target moved enough, then recompute our
|
||||
// whole path
|
||||
if (IsFormationMember())
|
||||
CheckTargetMovement(pos, CHECK_TARGET_MOVEMENT_MIN_DELTA_FORMATION);
|
||||
else
|
||||
@ -1425,7 +1422,7 @@ bool CCmpUnitMotion::MoveToPointRange(entity_pos_t x, entity_pos_t z, entity_pos
|
||||
{
|
||||
// Too close to target - move outwards to a circle
|
||||
// that's slightly larger than the min range
|
||||
goal.type = PathGoal::CIRCLE;// TODO: INVERTED_CIRCLE;
|
||||
goal.type = PathGoal::INVERTED_CIRCLE;
|
||||
goal.hw = minRange + g_GoalDelta;
|
||||
}
|
||||
else if (maxRange >= entity_pos_t::Zero() && distance > maxRange)
|
||||
@ -1584,7 +1581,12 @@ bool CCmpUnitMotion::MoveToTargetRange(entity_id_t target, entity_pos_t minRange
|
||||
|
||||
entity_pos_t distance = Geometry::DistanceToSquare(pos - CFixedVector2D(obstruction.x, obstruction.z), obstruction.u, obstruction.v, halfSize);
|
||||
|
||||
if (distance < minRange)
|
||||
// Compare with previous obstruction
|
||||
ICmpObstructionManager::ObstructionSquare previousObstruction;
|
||||
cmpObstruction->GetPreviousObstructionSquare(previousObstruction);
|
||||
entity_pos_t previousDistance = Geometry::DistanceToSquare(pos - CFixedVector2D(previousObstruction.x, previousObstruction.z), obstruction.u, obstruction.v, halfSize);
|
||||
|
||||
if (distance < minRange && previousDistance < minRange)
|
||||
{
|
||||
// Too close to the square - need to move away
|
||||
|
||||
@ -1592,14 +1594,14 @@ bool CCmpUnitMotion::MoveToTargetRange(entity_id_t target, entity_pos_t minRange
|
||||
|
||||
entity_pos_t goalDistance = minRange + g_GoalDelta;
|
||||
|
||||
goal.type = PathGoal::SQUARE;
|
||||
goal.type = PathGoal::INVERTED_SQUARE;
|
||||
goal.u = obstruction.u;
|
||||
goal.v = obstruction.v;
|
||||
entity_pos_t delta = std::max(goalDistance, m_Clearance + entity_pos_t::FromInt(TERRAIN_TILE_SIZE)/16); // ensure it's far enough to not intersect the building itself
|
||||
goal.hw = obstruction.hw + delta;
|
||||
goal.hh = obstruction.hh + delta;
|
||||
}
|
||||
else if (maxRange < entity_pos_t::Zero() || distance < maxRange)
|
||||
else if (maxRange < entity_pos_t::Zero() || distance < maxRange || previousDistance < maxRange)
|
||||
{
|
||||
// We're already in range - no need to move anywhere
|
||||
FaceTowardsPointFromPos(pos, goal.x, goal.z);
|
||||
@ -1620,8 +1622,9 @@ bool CCmpUnitMotion::MoveToTargetRange(entity_id_t target, entity_pos_t minRange
|
||||
// the distance to the square, so the previous "distance < maxRange"
|
||||
// check is still valid (though not sufficient)
|
||||
entity_pos_t circleDistance = (pos - CFixedVector2D(obstruction.x, obstruction.z)).Length() - circleRadius;
|
||||
entity_pos_t previousCircleDistance = (pos - CFixedVector2D(previousObstruction.x, previousObstruction.z)).Length() - circleRadius;
|
||||
|
||||
if (circleDistance < maxRange)
|
||||
if (circleDistance < maxRange || previousCircleDistance < maxRange)
|
||||
{
|
||||
// We're already in range - no need to move anywhere
|
||||
if (m_FacePointAfterMove)
|
||||
@ -1688,7 +1691,7 @@ bool CCmpUnitMotion::IsInTargetRange(entity_id_t target, entity_pos_t minRange,
|
||||
CFixedVector2D halfSize(obstruction.hw, obstruction.hh);
|
||||
entity_pos_t distance = Geometry::DistanceToSquare(pos - CFixedVector2D(obstruction.x, obstruction.z), obstruction.u, obstruction.v, halfSize);
|
||||
|
||||
// compare with previous obstruction
|
||||
// Compare with previous obstruction
|
||||
ICmpObstructionManager::ObstructionSquare previousObstruction;
|
||||
cmpObstruction->GetPreviousObstructionSquare(previousObstruction);
|
||||
entity_pos_t previousDistance = Geometry::DistanceToSquare(pos - CFixedVector2D(previousObstruction.x, previousObstruction.z), obstruction.u, obstruction.v, halfSize);
|
||||
@ -1706,16 +1709,12 @@ bool CCmpUnitMotion::IsInTargetRange(entity_id_t target, entity_pos_t minRange,
|
||||
if (ShouldTreatTargetAsCircle(maxRange, obstruction.hw, obstruction.hh, circleRadius))
|
||||
{
|
||||
// The target is small relative to our range, so pretend it's a circle
|
||||
// and see if we're close enough to that
|
||||
|
||||
// and see if we're close enough to that.
|
||||
// Also check circle around previous position.
|
||||
entity_pos_t circleDistance = (pos - CFixedVector2D(obstruction.x, obstruction.z)).Length() - circleRadius;
|
||||
entity_pos_t previousCircleDistance = (pos - CFixedVector2D(previousObstruction.x, previousObstruction.z)).Length() - circleRadius;
|
||||
|
||||
if (circleDistance <= maxRange)
|
||||
return true;
|
||||
// also check circle around previous position
|
||||
circleDistance = (pos - CFixedVector2D(previousObstruction.x, previousObstruction.z)).Length() - circleRadius;
|
||||
|
||||
if (circleDistance <= maxRange)
|
||||
if (circleDistance <= maxRange || previousCircleDistance <= maxRange)
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1728,11 +1727,9 @@ bool CCmpUnitMotion::IsInTargetRange(entity_id_t target, entity_pos_t minRange,
|
||||
return false;
|
||||
|
||||
CFixedVector2D targetPos = cmpTargetPosition->GetPreviousPosition2D();
|
||||
|
||||
entity_pos_t distance = (pos - targetPos).Length();
|
||||
|
||||
return minRange <= distance &&
|
||||
(maxRange < entity_pos_t::Zero() || distance <= maxRange);
|
||||
return minRange <= distance && (maxRange < entity_pos_t::Zero() || distance <= maxRange);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,8 +85,6 @@ fixed Geometry::DistanceToSquare(CFixedVector2D point, CFixedVector2D u, CFixedV
|
||||
fixed hw = halfSize.X;
|
||||
fixed hh = halfSize.Y;
|
||||
|
||||
// TODO: I haven't actually tested this
|
||||
|
||||
if (-hw < du && du < hw) // regions B, I, G
|
||||
{
|
||||
fixed closest = (dv.Absolute() - hh).Absolute(); // horizontal edges
|
||||
|
@ -82,10 +82,10 @@ static bool NavcellContainsSquare(int i, int j,
|
||||
// Otherwise, since the square is convex, there cannot be any other point
|
||||
// in the navcell that is outside the square.
|
||||
return (
|
||||
Geometry::PointIsInSquare(CFixedVector2D(x0 - x, z0 - z), u, v, CFixedVector2D(hw, hh))
|
||||
|| Geometry::PointIsInSquare(CFixedVector2D(x1 - x, z0 - z), u, v, CFixedVector2D(hw, hh))
|
||||
|| Geometry::PointIsInSquare(CFixedVector2D(x0 - x, z1 - z), u, v, CFixedVector2D(hw, hh))
|
||||
|| Geometry::PointIsInSquare(CFixedVector2D(x1 - x, z1 - z), u, v, CFixedVector2D(hw, hh))
|
||||
!Geometry::PointIsInSquare(CFixedVector2D(x0 - x, z0 - z), u, v, CFixedVector2D(hw, hh))
|
||||
|| !Geometry::PointIsInSquare(CFixedVector2D(x1 - x, z0 - z), u, v, CFixedVector2D(hw, hh))
|
||||
|| !Geometry::PointIsInSquare(CFixedVector2D(x0 - x, z1 - z), u, v, CFixedVector2D(hw, hh))
|
||||
|| !Geometry::PointIsInSquare(CFixedVector2D(x1 - x, z1 - z), u, v, CFixedVector2D(hw, hh))
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -121,7 +121,7 @@ bool PathGoal::NavcellRectContainsGoal(int i0, int j0, int i1, int j1, int* gi,
|
||||
int jmin = std::min(j0, j1);
|
||||
int jmax = std::max(j0, j1);
|
||||
|
||||
// Direction to iterate from ij0 towards ij1
|
||||
// Direction to iterate from (i0,j0) towards (i1,j1)
|
||||
int di = i1 < i0 ? -1 : +1;
|
||||
int dj = j1 < j0 ? -1 : +1;
|
||||
|
||||
@ -174,6 +174,36 @@ bool PathGoal::NavcellRectContainsGoal(int i0, int j0, int i1, int j1, int* gi,
|
||||
return false;
|
||||
}
|
||||
|
||||
case INVERTED_CIRCLE:
|
||||
{
|
||||
// Loop over all navcells in the given range (starting at (i0,j0) since
|
||||
// this function is meant to find the goal navcell nearest to there
|
||||
// assuming jmin==jmax || imin==imax),
|
||||
// and check whether any point in each navcell is outside the goal circle.
|
||||
// (TODO: this is pretty inefficient.)
|
||||
for (int j = j0; jmin <= j && j <= jmax; j += dj)
|
||||
{
|
||||
for (int i = i0; imin <= i && i <= imax; i += di)
|
||||
{
|
||||
entity_pos_t x0 = entity_pos_t::FromInt(i).Multiply(Pathfinding::NAVCELL_SIZE);
|
||||
entity_pos_t z0 = entity_pos_t::FromInt(j).Multiply(Pathfinding::NAVCELL_SIZE);
|
||||
entity_pos_t x1 = x0 + Pathfinding::NAVCELL_SIZE;
|
||||
entity_pos_t z1 = z0 + Pathfinding::NAVCELL_SIZE;
|
||||
entity_pos_t nx = Clamp(x, x0, x1);
|
||||
entity_pos_t nz = Clamp(z, z0, z1);
|
||||
if ((CFixedVector2D(nx, nz) - CFixedVector2D(x, z)).CompareLength(hw) > 0)
|
||||
{
|
||||
if (gi)
|
||||
*gi = i;
|
||||
if (gj)
|
||||
*gj = j;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
case SQUARE:
|
||||
{
|
||||
// Loop over all navcells in the given range (starting at (i0,j0) since
|
||||
@ -204,12 +234,35 @@ bool PathGoal::NavcellRectContainsGoal(int i0, int j0, int i1, int j1, int* gi,
|
||||
return false;
|
||||
}
|
||||
|
||||
case INVERTED_CIRCLE:
|
||||
case INVERTED_SQUARE:
|
||||
// Haven't bothered implementing these, since they're not needed by the
|
||||
// current pathfinder design
|
||||
debug_warn(L"PathGoal::NavcellRectContainsGoal doesn't support inverted shapes");
|
||||
{
|
||||
// Loop over all navcells in the given range (starting at (i0,j0) since
|
||||
// this function is meant to find the goal navcell nearest to there
|
||||
// assuming jmin==jmax || imin==imax),
|
||||
// and check whether any point in each navcell is outside the goal square.
|
||||
// (TODO: this is pretty inefficient.)
|
||||
for (int j = j0; jmin <= j && j <= jmax; j += dj)
|
||||
{
|
||||
for (int i = i0; imin <= i && i <= imax; i += di)
|
||||
{
|
||||
entity_pos_t x0 = entity_pos_t::FromInt(i).Multiply(Pathfinding::NAVCELL_SIZE);
|
||||
entity_pos_t z0 = entity_pos_t::FromInt(j).Multiply(Pathfinding::NAVCELL_SIZE);
|
||||
entity_pos_t x1 = x0 + Pathfinding::NAVCELL_SIZE;
|
||||
entity_pos_t z1 = z0 + Pathfinding::NAVCELL_SIZE;
|
||||
entity_pos_t nx = Clamp(x, x0, x1);
|
||||
entity_pos_t nz = Clamp(z, z0, z1);
|
||||
if (!Geometry::PointIsInSquare(CFixedVector2D(nx - x, nz - z), u, v, CFixedVector2D(hw, hh)))
|
||||
{
|
||||
if (gi)
|
||||
*gi = i;
|
||||
if (gj)
|
||||
*gj = j;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
NODEFAULT;
|
||||
}
|
||||
@ -229,6 +282,13 @@ bool PathGoal::RectContainsGoal(entity_pos_t x0, entity_pos_t z0, entity_pos_t x
|
||||
return (CFixedVector2D(nx, nz) - CFixedVector2D(x, z)).CompareLength(hw) <= 0;
|
||||
}
|
||||
|
||||
case INVERTED_CIRCLE:
|
||||
{
|
||||
entity_pos_t nx = Clamp(x, x0, x1);
|
||||
entity_pos_t nz = Clamp(z, z0, z1);
|
||||
return (CFixedVector2D(nx, nz) - CFixedVector2D(x, z)).CompareLength(hw) > 0;
|
||||
}
|
||||
|
||||
case SQUARE:
|
||||
{
|
||||
entity_pos_t nx = Clamp(x, x0, x1);
|
||||
@ -236,12 +296,12 @@ bool PathGoal::RectContainsGoal(entity_pos_t x0, entity_pos_t z0, entity_pos_t x
|
||||
return Geometry::PointIsInSquare(CFixedVector2D(nx - x, nz - z), u, v, CFixedVector2D(hw, hh));
|
||||
}
|
||||
|
||||
case INVERTED_CIRCLE:
|
||||
case INVERTED_SQUARE:
|
||||
// Haven't bothered implementing these, since they're not needed by the
|
||||
// current pathfinder design
|
||||
debug_warn(L"PathGoal::RectContainsGoal doesn't support inverted shapes");
|
||||
return false;
|
||||
{
|
||||
entity_pos_t nx = Clamp(x, x0, x1);
|
||||
entity_pos_t nz = Clamp(z, z0, z1);
|
||||
return !Geometry::PointIsInSquare(CFixedVector2D(nx - x, nz - z), u, v, CFixedVector2D(hw, hh));
|
||||
}
|
||||
|
||||
NODEFAULT;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user