Changeset View
Changeset View
Standalone View
Standalone View
source/simulation2/components/CCmpUnitMotion.cpp
Show First 20 Lines • Show All 1,409 Lines • ▼ Show 20 Lines | if (minRange.IsZero() && maxRange.IsZero()) | ||||
// Head directly for the goal | // Head directly for the goal | ||||
goal.type = PathGoal::POINT; | goal.type = PathGoal::POINT; | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
// Ranged movement: | // Ranged movement: | ||||
CmpPtr<ICmpObstruction> cmpObstruction(GetEntityHandle()); | |||||
ENSURE(cmpObstruction); | |||||
// 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 goalDelta = cmpObstruction->GetUnitRadius() * 3 /2; | |||||
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; | goal.hw = minRange + goalDelta; | ||||
} | } | ||||
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 - goalDelta; | ||||
// 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 17 Lines | bool CCmpUnitMotion::MoveToTargetRange(entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange) | ||||
entity_pos_t distance = Geometry::DistanceToSquare(pos - CFixedVector2D(obstruction.x, obstruction.z), obstruction.u, obstruction.v, halfSize, true); | entity_pos_t distance = Geometry::DistanceToSquare(pos - CFixedVector2D(obstruction.x, obstruction.z), obstruction.u, obstruction.v, halfSize, true); | ||||
// Compare with previous obstruction | // Compare with previous obstruction | ||||
ICmpObstructionManager::ObstructionSquare previousObstruction; | ICmpObstructionManager::ObstructionSquare previousObstruction; | ||||
cmpObstruction->GetPreviousObstructionSquare(previousObstruction); | cmpObstruction->GetPreviousObstructionSquare(previousObstruction); | ||||
entity_pos_t previousDistance = Geometry::DistanceToSquare(pos - CFixedVector2D(previousObstruction.x, previousObstruction.z), obstruction.u, obstruction.v, halfSize, true); | entity_pos_t previousDistance = Geometry::DistanceToSquare(pos - CFixedVector2D(previousObstruction.x, previousObstruction.z), obstruction.u, obstruction.v, halfSize, true); | ||||
CmpPtr<ICmpObstruction> cmpThisObstruction(GetEntityHandle()); | |||||
ENSURE(cmpThisObstruction); | |||||
// 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 goalDelta = cmpThisObstruction->GetUnitRadius() * 3 /2; | |||||
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; | entity_pos_t goalDistance = minRange + goalDelta; | ||||
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 - goalDelta; | ||||
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 - goalDelta) * 2 / 3; // multiply by slightly less than 1/sqrt(2) | ||||
wraitii: We can remove GOAL_DELTA here since it's edge-to-edge and this asks the centre of the unit to… | |||||
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, goalDelta + entity_pos_t::FromInt(TERRAIN_TILE_SIZE)/16); // ensure it's far enough to not intersect the building itself | ||||
Done Inline Actionsm_Clearance here is actually required or the pathing becomes odd as units try going impossibly close to the obstruction. This does mean max ranges must be at least TERRAIN_TILE_SIZE)/16 or the unit might never be in range. wraitii: m_Clearance here is actually required or the pathing becomes odd as units try going impossibly… | |||||
goal.hw = obstruction.hw + delta; | goal.hw = obstruction.hw + delta; | ||||
goal.hh = obstruction.hh + delta; | goal.hh = obstruction.hh + delta; | ||||
} | } | ||||
} | } | ||||
m_State = STATE_INDIVIDUAL_PATH; | m_State = STATE_INDIVIDUAL_PATH; | ||||
m_MoveRequest = MoveRequest(target, minRange, maxRange); | m_MoveRequest = MoveRequest(target, minRange, maxRange); | ||||
m_FinalGoal = goal; | m_FinalGoal = goal; | ||||
▲ Show 20 Lines • Show All 75 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator
We can remove GOAL_DELTA here since it's edge-to-edge and this asks the centre of the unit to be at max range (likewise above), so no need for a delta.