From 58018a1056df6705b95c5084af6a44a471e2e95d Mon Sep 17 00:00:00 2001 From: wraitii Date: Wed, 3 Jul 2019 18:06:53 +0000 Subject: [PATCH] UnitMotion - rename CheckTargetMovement to PathingUpdateNeeded for clarity, and improve the logic. This new version compares the final waypoint with the target's obtruction shape and uses reachability checks to know if we will be in range or not. Differential Revision: https://code.wildfiregames.com/D1983 This was SVN commit r22430. --- .../components/CCmpObstructionManager.cpp | 10 ++ .../simulation2/components/CCmpUnitMotion.cpp | 115 +++++++----------- .../components/ICmpObstructionManager.h | 6 + 3 files changed, 62 insertions(+), 69 deletions(-) diff --git a/source/simulation2/components/CCmpObstructionManager.cpp b/source/simulation2/components/CCmpObstructionManager.cpp index a1d4b3fc37..37e1e6e712 100644 --- a/source/simulation2/components/CCmpObstructionManager.cpp +++ b/source/simulation2/components/CCmpObstructionManager.cpp @@ -475,6 +475,7 @@ public: 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 @@ bool CCmpObstructionManager::IsPointInPointRange(entity_pos_t x, entity_pos_t z, 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"); diff --git a/source/simulation2/components/CCmpUnitMotion.cpp b/source/simulation2/components/CCmpUnitMotion.cpp index c1f589a7fd..9bc4023443 100644 --- a/source/simulation2/components/CCmpUnitMotion.cpp +++ b/source/simulation2/components/CCmpUnitMotion.cpp @@ -76,36 +76,6 @@ static const entity_pos_t SHORT_PATH_GOAL_RADIUS = entity_pos_t::FromInt(TERRAIN */ 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 @@ private: 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 @@ void CCmpUnitMotion::Move(fixed dt) { // 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 @@ bool CCmpUnitMotion::TryGoingStraightToTarget(const CFixedVector2D& from) 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; - - // 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) + // 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 cmpRangeManager(GetSystemEntity()); - if (cmpRangeManager && cmpRangeManager->GetLosVisibility(m_MoveRequest.m_Entity, cmpOwnership->GetOwner()) == ICmpRangeManager::VIS_HIDDEN) - return false; + CmpPtr cmpTargetObstruction(GetSimContext(), m_MoveRequest.m_Entity); + if (cmpTargetObstruction) + cmpTargetObstruction->GetObstructionSquare(estimatedTargetShape); } - // 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; + 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()) + { + 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; + } + + 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; } diff --git a/source/simulation2/components/ICmpObstructionManager.h b/source/simulation2/components/ICmpObstructionManager.h index f91f50de6e..9bda9f081e 100644 --- a/source/simulation2/components/ICmpObstructionManager.h +++ b/source/simulation2/components/ICmpObstructionManager.h @@ -217,6 +217,12 @@ public: */ 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.