Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/source/simulation2/components/CCmpUnitMotion.cpp
Show First 20 Lines • Show All 1,415 Lines • ▼ Show 20 Lines | bool CCmpUnitMotion::MoveToPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t minRange, entity_pos_t maxRange, entity_id_t target) | ||||
{ | { | ||||
// Ranged movement: | // Ranged movement: | ||||
entity_pos_t distance = (pos - CFixedVector2D(x, z)).Length(); | entity_pos_t distance = (pos - CFixedVector2D(x, z)).Length(); | ||||
if (distance < minRange) | if (distance < minRange) | ||||
{ | { | ||||
// Too close to target - move outwards to a circle | // Too close to target - move outwards to a circle | ||||
// that's slightly larger than the min range | // that's slightly larger than the min range. | ||||
goal.type = PathGoal::INVERTED_CIRCLE; | goal.type = PathGoal::INVERTED_CIRCLE; | ||||
goal.hw = minRange + Pathfinding::GOAL_DELTA; | |||||
// Distance checks are nearest edge to nearest edge, so we need to account for our clearance | |||||
// and we must make sure diagonals also fit so multiply by slightly more than sqrt(2) | |||||
goal.hw = minRange + m_Clearance * 3 /2; | |||||
} | } | ||||
else if (maxRange >= entity_pos_t::Zero() && distance > maxRange) | else if (maxRange >= entity_pos_t::Zero() && distance > maxRange) | ||||
{ | { | ||||
// Too far from target - move inwards to a circle | // Too far from target - move inwards to a circle | ||||
// that's slightly smaller than the max range | // that's slightly smaller than the max range | ||||
goal.type = PathGoal::CIRCLE; | goal.type = PathGoal::CIRCLE; | ||||
goal.hw = maxRange - Pathfinding::GOAL_DELTA; | goal.hw = maxRange; | ||||
// If maxRange was abnormally small, | // If maxRange was abnormally small, | ||||
// collapse the circle into a point | // collapse the circle into a point | ||||
if (goal.hw <= entity_pos_t::Zero()) | if (goal.hw <= entity_pos_t::Zero()) | ||||
goal.type = PathGoal::POINT; | goal.type = PathGoal::POINT; | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | if (!hasObstruction) | ||||
CFixedVector2D targetPos = cmpTargetPosition->GetPosition2D(); | CFixedVector2D targetPos = cmpTargetPosition->GetPosition2D(); | ||||
return MoveToPointRange(targetPos.X, targetPos.Y, minRange, maxRange); | return MoveToPointRange(targetPos.X, targetPos.Y, minRange, maxRange); | ||||
} | } | ||||
/* | /* | ||||
* If we're starting outside the maxRange, we need to move closer in. | * If we're starting outside the maxRange, we need to move closer in. | ||||
* If we're starting inside the minRange, we need to move further out. | * If we're starting inside the minRange, we need to move further out. | ||||
* These ranges are measured from the center of this entity to the edge of the target; | * These ranges are measured from the edge of this entity to the edge of the target; | ||||
* we add the goal range onto the size of the target shape to get the goal shape. | * we add the goal range onto the size of the target shape to get the goal shape. | ||||
* (Then we extend it outwards/inwards by a little bit to be sure we'll end up | * (Then we extend it outwards/inwards by a little bit to be sure we'll end up | ||||
* within the right range, in case of minor numerical inaccuracies.) | * within the right range, in case of minor numerical inaccuracies.) | ||||
* | * | ||||
* There's a bit of a problem with large square targets: | * There's a bit of a problem with large square targets: | ||||
* the pathfinder only lets us move to goals that are squares, but the points an equal | * the pathfinder only lets us move to goals that are squares, but the points an equal | ||||
* distance from the target make a rounded square shape instead. | * distance from the target make a rounded square shape instead. | ||||
* | * | ||||
Show All 25 Lines | bool CCmpUnitMotion::MoveToTargetRange(entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange) | ||||
bool inside = distance.IsZero() && !Geometry::DistanceToSquare(pos - CFixedVector2D(obstruction.x, obstruction.z), obstruction.u, obstruction.v, halfSize).IsZero(); | bool inside = distance.IsZero() && !Geometry::DistanceToSquare(pos - CFixedVector2D(obstruction.x, obstruction.z), obstruction.u, obstruction.v, halfSize).IsZero(); | ||||
if ((distance < minRange && previousDistance < minRange) || inside) | if ((distance < minRange && previousDistance < minRange) || inside) | ||||
{ | { | ||||
// Too close to the square - need to move away | // Too close to the square - need to move away | ||||
// Circumscribe the square | // Circumscribe the square | ||||
entity_pos_t circleRadius = halfSize.Length(); | entity_pos_t circleRadius = halfSize.Length(); | ||||
entity_pos_t goalDistance = minRange + Pathfinding::GOAL_DELTA; | // Distance checks are nearest edge to nearest edge, so we need to account for our clearance | ||||
// and we must make sure diagonals also fit so multiply by slightly more than sqrt(2) | |||||
entity_pos_t goalDistance = minRange + m_Clearance * 3 /2; | |||||
if (ShouldTreatTargetAsCircle(minRange, circleRadius)) | if (ShouldTreatTargetAsCircle(minRange, circleRadius)) | ||||
{ | { | ||||
// The target is small relative to our range, so pretend it's a circle | // The target is small relative to our range, so pretend it's a circle | ||||
goal.type = PathGoal::INVERTED_CIRCLE; | goal.type = PathGoal::INVERTED_CIRCLE; | ||||
goal.hw = circleRadius + goalDistance; | goal.hw = circleRadius + goalDistance; | ||||
} | } | ||||
else | else | ||||
Show All 31 Lines | if (ShouldTreatTargetAsCircle(maxRange, circleRadius)) | ||||
if (circleDistance < maxRange || previousCircleDistance < maxRange) | if (circleDistance < maxRange || previousCircleDistance < maxRange) | ||||
{ | { | ||||
// We're already in range - no need to move anywhere | // We're already in range - no need to move anywhere | ||||
if (m_FacePointAfterMove) | if (m_FacePointAfterMove) | ||||
FaceTowardsPointFromPos(pos, goal.x, goal.z); | FaceTowardsPointFromPos(pos, goal.x, goal.z); | ||||
return true; | return true; | ||||
} | } | ||||
entity_pos_t goalDistance = maxRange - Pathfinding::GOAL_DELTA; | entity_pos_t goalDistance = maxRange; | ||||
goal.type = PathGoal::CIRCLE; | goal.type = PathGoal::CIRCLE; | ||||
goal.hw = circleRadius + goalDistance; | goal.hw = circleRadius + goalDistance; | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
// The target is large relative to our range, so treat it as a square and | // The target is large relative to our range, so treat it as a square and | ||||
// get close enough that the diagonals come within range | // get close enough that the diagonals come within range | ||||
entity_pos_t goalDistance = (maxRange - Pathfinding::GOAL_DELTA)*2 / 3; // multiply by slightly less than 1/sqrt(2) | entity_pos_t goalDistance = maxRange * 2 / 3; // multiply by slightly less than 1/sqrt(2) | ||||
goal.type = PathGoal::SQUARE; | goal.type = PathGoal::SQUARE; | ||||
goal.u = obstruction.u; | goal.u = obstruction.u; | ||||
goal.v = obstruction.v; | 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 | 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.hw = obstruction.hw + delta; | ||||
goal.hh = obstruction.hh + delta; | goal.hh = obstruction.hh + delta; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 80 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator