Index: source/simulation2/components/CCmpUnitMotion.cpp =================================================================== --- source/simulation2/components/CCmpUnitMotion.cpp +++ source/simulation2/components/CCmpUnitMotion.cpp @@ -152,6 +152,7 @@ SHORT_PATH, LONG_PATH } m_Type; + u8 m_Tries = 0; void clear() { m_Ticket = 0; } } m_ExpectedPathTicket; @@ -199,9 +200,6 @@ WaypointPath m_LongPath; WaypointPath m_ShortPath; - // Motion planning - u8 m_Tries; // how many tries we've done to get to our current Final Goal. - static std::string GetSchema() { return @@ -252,8 +250,6 @@ cmpObstruction->SetUnitClearance(m_Clearance); } - m_Tries = 0; - m_DebugOverlayEnabled = false; } @@ -267,6 +263,7 @@ serialize.StringASCII("pass class", m_PassClassName, 0, 64); serialize.NumberU32_Unbounded("ticket", m_ExpectedPathTicket.m_Ticket); + serialize.NumberU8("tries", m_ExpectedPathTicket.m_Tries, 0, 255); SerializeU8_Enum()(serialize, "ticket type", m_ExpectedPathTicket.m_Type); m_MoveRequest.Serialize(serialize); @@ -277,8 +274,6 @@ serialize.Bool("facePointAfterMove", m_FacePointAfterMove); - serialize.NumberU8("tries", m_Tries, 0, 255); - SerializeVector()(serialize, "long path", m_LongPath.m_Waypoints); SerializeVector()(serialize, "short path", m_ShortPath.m_Waypoints); } @@ -682,51 +677,58 @@ if (ComputeTargetPosition(targetPos)) m_LongPath.m_Waypoints.emplace_back(Waypoint{ targetPos.X, targetPos.Y }); } + return; } - else + + m_ShortPath = path; + + if (!m_ShortPath.m_Waypoints.empty()) + { + m_ExpectedPathTicket.m_Tries = 0; + return; + } + + // If there's no waypoints then we couldn't get near the target + // If we're globally following a long path, try to remove the next waypoint, it might be obstructed (e.g. by idle entities) + // If not, and we are not in a formation, retry + // unless we are close to our target and we don't have a target entity. + // This makes sure that units don't clump too much when they are not in a formation and tasked to move. + if (m_LongPath.m_Waypoints.size() > 1) + m_LongPath.m_Waypoints.pop_back(); + else if (IsFormationMember()) + { + CMessageMotionChanged msg(true); + GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg); + return; + } + + CFixedVector2D pos = cmpPosition->GetPosition2D(); + + if (CloseEnoughFromDestinationToStop(pos)) + MoveSucceeded(); + + CFixedVector2D targetPos; + if (!ComputeTargetPosition(targetPos)) + return; + + if ((pos - targetPos).CompareLength(LONG_PATH_MIN_DIST) <= 0) { - m_ShortPath = path; - - // If there's no waypoints then we couldn't get near the target - if (m_ShortPath.m_Waypoints.empty()) - { - // If we're globally following a long path, try to remove the next waypoint, it might be obstructed (e.g. by idle entities) - // If not, and we are not in a formation, retry - // unless we are close to our target and we don't have a target entity. - // This makes sure that units don't clump too much when they are not in a formation and tasked to move. - if (m_LongPath.m_Waypoints.size() > 1) - m_LongPath.m_Waypoints.pop_back(); - else if (IsFormationMember()) - { - CMessageMotionChanged msg(true); - GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg); - return; - } - - CMessageMotionChanged msg(false); - GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg); - - CmpPtr cmpPosition(GetEntityHandle()); - if (!cmpPosition || !cmpPosition->IsInWorld()) - return; - - CFixedVector2D pos = cmpPosition->GetPosition2D(); - - if (CloseEnoughFromDestinationToStop(pos)) - { - MoveSucceeded(); - return; - } - - PathGoal goal; - ComputeGoal(goal, m_MoveRequest); - RequestLongPath(pos, goal); - return; - } - - // else we could, so reset our number of tries. - m_Tries = 0; + PathGoal goal; + ComputeGoal(goal, m_MoveRequest); + RequestShortPath(pos, goal, false); + return; } + else if (!m_LongPath.m_Waypoints.empty() && m_ExpectedPathTicket.m_Tries <= 3) + { + m_ExpectedPathTicket.m_Tries = 0; + PathGoal goal = { PathGoal::POINT, m_LongPath.m_Waypoints.back().x, m_LongPath.m_Waypoints.back().z }; + RequestShortPath(pos, goal, false); + return; + } + + PathGoal goal; + ComputeGoal(goal, m_MoveRequest); + RequestLongPath(pos, goal); } void CCmpUnitMotion::Move(fixed dt) @@ -916,14 +918,29 @@ // Oops, we hit something (very likely another unit). - // If we still have long waypoints, try and compute a short path - if (!m_LongPath.m_Waypoints.empty()) - { - PathGoal goal = { PathGoal::POINT, m_LongPath.m_Waypoints.back().x, m_LongPath.m_Waypoints.back().z }; - RequestShortPath(pos, goal, true); - return true; - } + CFixedVector2D targetPos; + if (!ComputeTargetPosition(targetPos)) + return false; + // If we are almost within distance or only have one waypoint left, the problem is likely that our long path + // returned a position blocked by other entities, so use the short pathfinder to work around that. + if ((pos - targetPos).CompareLength(LONG_PATH_MIN_DIST) <= 0 || m_LongPath.m_Waypoints.size() == 1) + { + m_LongPath.m_Waypoints.clear(); + m_ExpectedPathTicket.m_Tries = 0; + PathGoal goal; + ComputeGoal(goal, m_MoveRequest); + RequestShortPath(pos, goal, false); + return true; + } + // Otherwise use the short pathfinder to go to the next waypoint + else if (!m_LongPath.m_Waypoints.empty()) + { + m_ExpectedPathTicket.m_Tries = 0; + PathGoal goal = { PathGoal::POINT, m_LongPath.m_Waypoints.back().x, m_LongPath.m_Waypoints.back().z }; + RequestShortPath(pos, goal, false); + return true; + } // Else, just entirely recompute PathGoal goal; ComputeGoal(goal, m_MoveRequest); @@ -1309,6 +1326,7 @@ cmpPathfinder->SetDebugPath(from.X, from.Y, improvedGoal, m_PassClass); m_ExpectedPathTicket.m_Type = Ticket::LONG_PATH; + m_ExpectedPathTicket.m_Tries = 0; m_ExpectedPathTicket.m_Ticket = cmpPathfinder->ComputePathAsync(from.X, from.Y, improvedGoal, m_PassClass, GetEntityId()); } @@ -1319,7 +1337,7 @@ return; // wrapping around on m_Tries isn't really a problem so don't check for overflow. - fixed searchRange = std::max(SHORT_PATH_MIN_SEARCH_RANGE * ++m_Tries, goal.DistanceToPoint(from)); + fixed searchRange = std::max(SHORT_PATH_MIN_SEARCH_RANGE * ++m_ExpectedPathTicket.m_Tries, goal.DistanceToPoint(from)); if (goal.type != PathGoal::POINT && searchRange < goal.hw && searchRange < SHORT_PATH_MIN_SEARCH_RANGE * 2) searchRange = std::min(goal.hw, SHORT_PATH_MIN_SEARCH_RANGE * 2); if (searchRange > SHORT_PATH_MAX_SEARCH_RANGE) @@ -1344,7 +1362,7 @@ return false; m_MoveRequest = moveRequest; - m_Tries = 0; + m_ExpectedPathTicket.m_Tries = 0; BeginPathing(cmpPosition->GetPosition2D(), goal); @@ -1367,7 +1385,7 @@ return false; m_MoveRequest = moveRequest; - m_Tries = 0; + m_ExpectedPathTicket.m_Tries = 0; BeginPathing(cmpPosition->GetPosition2D(), goal); @@ -1387,7 +1405,7 @@ return; m_MoveRequest = moveRequest; - m_Tries = 0; + m_ExpectedPathTicket.m_Tries = 0; BeginPathing(cmpPosition->GetPosition2D(), goal); }