Index: ps/trunk/source/simulation2/components/CCmpObstructionManager.cpp =================================================================== --- ps/trunk/source/simulation2/components/CCmpObstructionManager.cpp +++ ps/trunk/source/simulation2/components/CCmpObstructionManager.cpp @@ -475,6 +475,7 @@ virtual bool IsInPointRange(entity_id_t ent, entity_pos_t px, entity_pos_t pz, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const; virtual bool IsInTargetRange(entity_id_t ent, entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const; virtual bool IsPointInPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t px, entity_pos_t pz, entity_pos_t minRange, entity_pos_t maxRange) const; + virtual bool AreShapesInRange(const ObstructionSquare& source, const ObstructionSquare& target, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const; virtual bool TestLine(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, bool relaxClearanceForUnits = false) const; virtual bool TestStaticShape(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h, std::vector* out) const; @@ -843,6 +844,15 @@ distance >= minRange - fixed::FromFloat(0.0001); } +bool CCmpObstructionManager::AreShapesInRange(const ObstructionSquare& source, const ObstructionSquare& target, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const +{ + fixed dist = DistanceBetweenShapes(source, target); + // Treat -1 max range as infinite + return dist != fixed::FromInt(-1) && + (dist <= (maxRange + fixed::FromFloat(0.0001)) || maxRange < fixed::Zero()) && + (opposite ? MaxDistanceBetweenShapes(source, target) : dist) >= minRange - fixed::FromFloat(0.0001); +} + bool CCmpObstructionManager::TestLine(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, bool relaxClearanceForUnits) const { PROFILE("TestLine"); Index: ps/trunk/source/simulation2/components/CCmpUnitMotion.cpp =================================================================== --- ps/trunk/source/simulation2/components/CCmpUnitMotion.cpp +++ ps/trunk/source/simulation2/components/CCmpUnitMotion.cpp @@ -76,36 +76,6 @@ */ static const entity_pos_t DIRECT_PATH_RANGE = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*4); -/** - * If we're following a target entity, - * we will recompute our path if the target has moved - * more than this distance from where we last pathed to. - */ -static const entity_pos_t CHECK_TARGET_MOVEMENT_MIN_DELTA = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*4); - -/** - * If we're following as part of a formation, - * but can't move to our assigned target point in a straight line, - * we will recompute our path if the target has moved - * more than this distance from where we last pathed to. - */ -static const entity_pos_t CHECK_TARGET_MOVEMENT_MIN_DELTA_FORMATION = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*1); - -/** - * If we're following something but it's more than this distance away along - * our path, then don't bother trying to repath regardless of how much it has - * moved, until we get this close to the end of our old path. - */ -static const entity_pos_t CHECK_TARGET_MOVEMENT_AT_MAX_DIST = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*16); - -/** - * If we're following something and the angle between the (straight-line) directions to its previous target - * position and its present target position is greater than a given angle, recompute the path even far away - * (i.e. even if CHECK_TARGET_MOVEMENT_AT_MAX_DIST condition is not fulfilled). The actual check is done - * on the cosine of this angle, with a PI/6 angle. - */ -static const fixed CHECK_TARGET_MOVEMENT_MIN_COS = fixed::FromInt(866)/1000; - static const CColor OVERLAY_COLOR_LONG_PATH(1, 1, 1, 1); static const CColor OVERLAY_COLOR_SHORT_PATH(1, 0, 0, 1); @@ -653,10 +623,9 @@ bool TryGoingStraightToTarget(const CFixedVector2D& from); /** - * Returns whether the target entity has moved more than minDelta since our - * last path computations, and we're close enough to it to care. + * Returns whether our we need to recompute a path to reach our target. */ - bool CheckTargetMovement(const CFixedVector2D& from, entity_pos_t minDelta); + bool PathingUpdateNeeded(const CFixedVector2D& from); /** * Update goal position if moving target @@ -874,10 +843,7 @@ { // We may need to recompute our path sometimes (e.g. if our target moves). // Since we request paths asynchronously anyways, this does not need to be done before moving. - if (IsFormationMember()) - CheckTargetMovement(pos, CHECK_TARGET_MOVEMENT_MIN_DELTA_FORMATION); - else - CheckTargetMovement(pos, CHECK_TARGET_MOVEMENT_MIN_DELTA); + PathingUpdateNeeded(pos); } } @@ -1140,49 +1106,60 @@ return true; } -bool CCmpUnitMotion::CheckTargetMovement(const CFixedVector2D& from, entity_pos_t minDelta) +bool CCmpUnitMotion::PathingUpdateNeeded(const CFixedVector2D& from) { + if (m_MoveRequest.m_Type == MoveRequest::NONE) + return false; + CFixedVector2D targetPos; if (!ComputeTargetPosition(targetPos)) return false; - // Fail unless the target has moved enough - CFixedVector2D oldTargetPos(m_FinalGoal.x, m_FinalGoal.z); - if ((targetPos - oldTargetPos).CompareLength(minDelta) < 0) + if (PossiblyAtDestination()) return false; - CmpPtr cmpPosition(GetEntityHandle()); - if (!cmpPosition || !cmpPosition->IsInWorld()) - return false; - CFixedVector2D pos = cmpPosition->GetPosition2D(); - CFixedVector2D oldDir = (oldTargetPos - pos); - CFixedVector2D newDir = (targetPos - pos); - oldDir.Normalize(); - newDir.Normalize(); - - // Fail unless we're close enough to the target to care about its movement - // and the angle between the (straight-line) directions of the previous and new target positions is small - if (oldDir.Dot(newDir) > CHECK_TARGET_MOVEMENT_MIN_COS && !PathIsShort(m_LongPath, from, CHECK_TARGET_MOVEMENT_AT_MAX_DIST)) - return false; + // Get the obstruction shape and translate it where we estimate the target to be. + ICmpObstructionManager::ObstructionSquare estimatedTargetShape; + if (m_MoveRequest.m_Type == MoveRequest::ENTITY) + { + CmpPtr cmpTargetObstruction(GetSimContext(), m_MoveRequest.m_Entity); + if (cmpTargetObstruction) + cmpTargetObstruction->GetObstructionSquare(estimatedTargetShape); + } - // Fail if the target is no longer visible to this entity's owner - // (in which case we'll continue moving to its last known location, - // unless it comes back into view before we reach that location) - CmpPtr cmpOwnership(GetEntityHandle()); - if (cmpOwnership) + estimatedTargetShape.x = targetPos.X; + estimatedTargetShape.z = targetPos.Y; + + CmpPtr cmpObstruction(GetEntityHandle()); + ICmpObstructionManager::ObstructionSquare shape; + if (cmpObstruction) + cmpObstruction->GetObstructionSquare(shape); + + // Translate our own obstruction shape to our last waypoint or our current position, lacking that. + if (m_LongPath.m_Waypoints.empty() && m_ShortPath.m_Waypoints.empty()) { - CmpPtr cmpRangeManager(GetSystemEntity()); - if (cmpRangeManager && cmpRangeManager->GetLosVisibility(m_MoveRequest.m_Entity, cmpOwnership->GetOwner()) == ICmpRangeManager::VIS_HIDDEN) - return false; + shape.x = from.X; + shape.z = from.Y; + } + else + { + Waypoint& lastWaypoint = m_ShortPath.m_Waypoints.empty() ? m_LongPath.m_Waypoints.front() : m_ShortPath.m_Waypoints.front(); + shape.x = lastWaypoint.x; + shape.z = lastWaypoint.z; } - // The target moved and we need to update our current path; - // change the goal here and expect our caller to start the path request - m_FinalGoal.x = targetPos.X; - m_FinalGoal.z = targetPos.Y; - RequestLongPath(from, m_FinalGoal); - m_PathState = PATHSTATE_FOLLOWING_REQUESTING_LONG; + CmpPtr cmpObstructionManager(GetSystemEntity()); + ENSURE(cmpObstructionManager); + if (cmpObstructionManager->AreShapesInRange(shape, estimatedTargetShape, + m_MoveRequest.m_MinRange, m_MoveRequest.m_MaxRange, false)) + return false; + + // We won't be in-range when we reach our final waypoint : recompute our path. + m_FinalGoal.x = estimatedTargetShape.x; + m_FinalGoal.z = estimatedTargetShape.z; + BeginPathing(from, m_FinalGoal); + m_PathState = PATHSTATE_FOLLOWING_REQUESTING_LONG; return true; } Index: ps/trunk/source/simulation2/components/ICmpObstructionManager.h =================================================================== --- ps/trunk/source/simulation2/components/ICmpObstructionManager.h +++ ps/trunk/source/simulation2/components/ICmpObstructionManager.h @@ -218,6 +218,12 @@ virtual bool IsPointInPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t px, entity_pos_t pz, entity_pos_t minRange, entity_pos_t maxRange) const = 0; /** + * Check if the given shape is in range of the target shape given those parameters. + * @param maxRange - if -1, treated as infinite. + */ + virtual bool AreShapesInRange(const ObstructionSquare& source, const ObstructionSquare& target, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const = 0; + + /** * Collision test a flat-ended thick line against the current set of shapes. * The line caps extend by @p r beyond the end points. * Only intersections going from outside to inside a shape are counted.