Index: source/simulation2/components/CCmpUnitMotion.cpp =================================================================== --- source/simulation2/components/CCmpUnitMotion.cpp +++ source/simulation2/components/CCmpUnitMotion.cpp @@ -77,36 +77,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); @@ -627,10 +597,9 @@ bool TryGoingStraightToTargetEntity(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 @@ -836,10 +805,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); } } @@ -1087,50 +1053,61 @@ 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; + // We are not at destination and have no waypoints: we need a path. + if (m_LongPath.m_Waypoints.empty() && m_ShortPath.m_Waypoints.empty()) + return true; - // 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::POINT || m_MoveRequest.m_Type == MoveRequest::OFFSET) + { + estimatedTargetShape.x = targetPos.X; + estimatedTargetShape.z = targetPos.Y; + } + else 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); + estimatedTargetShape.x = targetPos.X; + estimatedTargetShape.z = targetPos.Y; + // TODO: scale it up by a certain factor based on distance to account for uncertainty? } - // 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; + // Translate our own obstruction shape to our last waypoint + CmpPtr cmpObstruction(GetEntityHandle()); + ICmpObstructionManager::ObstructionSquare shape; + if (cmpObstruction) + cmpObstruction->GetObstructionSquare(shape); + 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); + entity_pos_t distance = cmpObstructionManager->DistanceBetweenShapes(shape, estimatedTargetShape); + + if (distance >= m_MoveRequest.m_MinRange && (distance <= m_MoveRequest.m_MaxRange || m_MoveRequest.m_MaxRange < fixed::Zero())) + 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; RequestLongPath(from, m_FinalGoal); m_PathState = PATHSTATE_FOLLOWING_REQUESTING_LONG; - return true; } void CCmpUnitMotion::UpdateFinalGoal()