Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/source/simulation2/components/CCmpUnitMotion.cpp
Show First 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | |||||
* When advancing along the long path, and picking a new waypoint to move | * When advancing along the long path, and picking a new waypoint to move | ||||
* towards, we'll pick one that's up to this far from the unit's current | * towards, we'll pick one that's up to this far from the unit's current | ||||
* position (to minimise the effects of grid-constrained movement) | * position (to minimise the effects of grid-constrained movement) | ||||
*/ | */ | ||||
static const entity_pos_t WAYPOINT_ADVANCE_MAX = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*8); | static const entity_pos_t WAYPOINT_ADVANCE_MAX = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*8); | ||||
/** | /** | ||||
* Min/Max range to restrict short path queries to. (Larger ranges are slower, | * Min/Max range to restrict short path queries to. (Larger ranges are slower, | ||||
* Min/Max range to restrict short path queries to. (Larger ranges are (much) slower, | |||||
* smaller ranges might miss some legitimate routes around large obstacles.) | * smaller ranges might miss some legitimate routes around large obstacles.) | ||||
*/ | */ | ||||
static const entity_pos_t SHORT_PATH_MIN_SEARCH_RANGE = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*2); | static const entity_pos_t SHORT_PATH_MIN_SEARCH_RANGE = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*3)/2; | ||||
static const entity_pos_t SHORT_PATH_MAX_SEARCH_RANGE = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*10); | static const entity_pos_t SHORT_PATH_MAX_SEARCH_RANGE = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*6); | ||||
static const entity_pos_t SHORT_PATH_SEARCH_RANGE_INCREMENT = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*1); | |||||
/** | |||||
* When using the short-pathfinder to rejoin a long-path waypoint, aim for a circle of this radius around the waypoint. | |||||
*/ | |||||
static const entity_pos_t SHORT_PATH_LONG_WAYPOINT_RANGE = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*1); | |||||
/** | /** | ||||
* Minimum distance to goal for a long path request | * Minimum distance to goal for a long path request | ||||
*/ | */ | ||||
static const entity_pos_t LONG_PATH_MIN_DIST = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*4); | static const entity_pos_t LONG_PATH_MIN_DIST = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*4); | ||||
/** | /** | ||||
* If we are this close to our target entity/point, then think about heading | * If we are this close to our target entity/point, then think about heading | ||||
▲ Show 20 Lines • Show All 388 Lines • ▼ Show 20 Lines | private: | ||||
entity_id_t GetGroup() const | entity_id_t GetGroup() const | ||||
{ | { | ||||
return IsFormationMember() ? m_MoveRequest.m_Entity : GetEntityId(); | return IsFormationMember() ? m_MoveRequest.m_Entity : GetEntityId(); | ||||
} | } | ||||
void MoveFailed() | void MoveFailed() | ||||
{ | { | ||||
CMessageMotionChanged msg(true); | CMessageMotionUpdate msg(CMessageMotionUpdate::LIKELY_FAILURE); | ||||
GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg); | GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg); | ||||
} | } | ||||
void MoveSucceeded() | void MoveSucceeded() | ||||
{ | { | ||||
CMessageMotionChanged msg(false); | CMessageMotionUpdate msg(CMessageMotionUpdate::LIKELY_SUCCESS); | ||||
GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg); | GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg); | ||||
} | } | ||||
/** | /** | ||||
* Update other components on our speed. | * Update other components on our speed. | ||||
* This doesn't use messages for efficiency. | * This doesn't use messages for efficiency. | ||||
* This should only be called when speed changes. | * This should only be called when speed changes. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 205 Lines • ▼ Show 20 Lines | if (ticketType == Ticket::LONG_PATH) | ||||
return; | return; | ||||
} | } | ||||
m_ShortPath = path; | m_ShortPath = path; | ||||
if (!m_ShortPath.m_Waypoints.empty()) | if (!m_ShortPath.m_Waypoints.empty()) | ||||
return; | return; | ||||
if (m_FailedPathComputations >= 1) | |||||
{ | |||||
// Inform other components - we might be ordered to stop, and computeGoal will then fail and return early. | |||||
CMessageMotionUpdate msg(CMessageMotionUpdate::OBSTRUCTED); | |||||
GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg); | |||||
} | |||||
// Don't notify if we are a formation member - we can occasionally be stuck for a long time | // Don't notify if we are a formation member - we can occasionally be stuck for a long time | ||||
// if our current offset is unreachable. | // if our current offset is unreachable. | ||||
if (!IsFormationMember()) | if (!IsFormationMember()) | ||||
IncrementFailedPathComputationAndMaybeNotify(); | IncrementFailedPathComputationAndMaybeNotify(); | ||||
// If there's no waypoints then we couldn't get near the target | // 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, | // If we're globally following a long path, try to remove the next waypoint, | ||||
// it might be obstructed (e.g. by idle entities which the long-range pathfinder doesn't see). | // it might be obstructed (e.g. by idle entities which the long-range pathfinder doesn't see). | ||||
if (!m_LongPath.m_Waypoints.empty()) | if (!m_LongPath.m_Waypoints.empty()) | ||||
{ | { | ||||
m_LongPath.m_Waypoints.pop_back(); | m_LongPath.m_Waypoints.pop_back(); | ||||
if (!m_LongPath.m_Waypoints.empty()) | if (!m_LongPath.m_Waypoints.empty()) | ||||
{ | { | ||||
PathGoal goal = { PathGoal::POINT, m_LongPath.m_Waypoints.back().x, m_LongPath.m_Waypoints.back().z }; | // Get close enough - this will likely help the short path efficiency, and if we end up taking a wrong way | ||||
// we'll easily be able to revert it using a long path. | |||||
PathGoal goal = { PathGoal::CIRCLE, m_LongPath.m_Waypoints.back().x, m_LongPath.m_Waypoints.back().z, SHORT_PATH_LONG_WAYPOINT_RANGE }; | |||||
RequestShortPath(pos, goal, true); | RequestShortPath(pos, goal, true); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
PathGoal goal; | PathGoal goal; | ||||
// If we can't compute a goal, we'll fail in the next Move() call so do nothing special. | // If we can't compute a goal, we'll fail in the next Move() call so do nothing special. | ||||
if (!ComputeGoal(goal, m_MoveRequest)) | if (!ComputeGoal(goal, m_MoveRequest)) | ||||
▲ Show 20 Lines • Show All 189 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
bool CCmpUnitMotion::HandleObstructedMove() | bool CCmpUnitMotion::HandleObstructedMove() | ||||
{ | { | ||||
CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle()); | CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle()); | ||||
if (!cmpPosition || !cmpPosition->IsInWorld()) | if (!cmpPosition || !cmpPosition->IsInWorld()) | ||||
return false; | return false; | ||||
if (m_FailedPathComputations >= 1) | |||||
{ | |||||
// Inform other components - we might be ordered to stop, and computeGoal will then fail and return early. | |||||
CMessageMotionUpdate msg(CMessageMotionUpdate::OBSTRUCTED); | |||||
GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg); | |||||
} | |||||
CFixedVector2D pos = cmpPosition->GetPosition2D(); | CFixedVector2D pos = cmpPosition->GetPosition2D(); | ||||
// Oops, we hit something (very likely another unit). | // Oops, we hit something (very likely another unit). | ||||
PathGoal goal; | PathGoal goal; | ||||
if (!ComputeGoal(goal, m_MoveRequest)) | if (!ComputeGoal(goal, m_MoveRequest)) | ||||
return false; | return false; | ||||
// If close enough, just compute a short path to the goal | // If close enough, just compute a short path to the goal | ||||
if (goal.DistanceToPoint(pos) < LONG_PATH_MIN_DIST) | if (goal.DistanceToPoint(pos) < LONG_PATH_MIN_DIST) | ||||
{ | { | ||||
m_LongPath.m_Waypoints.clear(); | m_LongPath.m_Waypoints.clear(); | ||||
RequestShortPath(pos, goal, true); | RequestShortPath(pos, goal, true); | ||||
return true; | return true; | ||||
} | } | ||||
// If we still have long waypoints, try and compute a short path. | // If we still have long waypoints, try and compute a short path. | ||||
// Assume the next waypoint is impassable | // Assume the next waypoint is impassable | ||||
if (m_LongPath.m_Waypoints.size() > 1) | if (m_LongPath.m_Waypoints.size() > 1) | ||||
m_LongPath.m_Waypoints.pop_back(); | m_LongPath.m_Waypoints.pop_back(); | ||||
if (!m_LongPath.m_Waypoints.empty()) | if (!m_LongPath.m_Waypoints.empty()) | ||||
{ | { | ||||
PathGoal goal = { PathGoal::POINT, m_LongPath.m_Waypoints.back().x, m_LongPath.m_Waypoints.back().z }; | // Get close enough - this will likely help the short path efficiency, and if we end up taking a wrong way | ||||
// we'll easily be able to revert it using a long path. | |||||
PathGoal goal = { PathGoal::CIRCLE, m_LongPath.m_Waypoints.back().x, m_LongPath.m_Waypoints.back().z, SHORT_PATH_LONG_WAYPOINT_RANGE }; | |||||
RequestShortPath(pos, goal, true); | RequestShortPath(pos, goal, true); | ||||
return true; | return true; | ||||
} | } | ||||
// Else, just entirely recompute | // Else, just entirely recompute | ||||
BeginPathing(pos, goal); | BeginPathing(pos, goal); | ||||
// potential TODO: We could switch the short-range pathfinder for something else entirely. | // potential TODO: We could switch the short-range pathfinder for something else entirely. | ||||
return true; | return true; | ||||
▲ Show 20 Lines • Show All 375 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
void CCmpUnitMotion::RequestShortPath(const CFixedVector2D &from, const PathGoal& goal, bool avoidMovingUnits) | void CCmpUnitMotion::RequestShortPath(const CFixedVector2D &from, const PathGoal& goal, bool avoidMovingUnits) | ||||
{ | { | ||||
CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity()); | CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity()); | ||||
if (!cmpPathfinder) | if (!cmpPathfinder) | ||||
return; | return; | ||||
fixed searchRange = std::max(SHORT_PATH_MIN_SEARCH_RANGE * (m_FailedPathComputations + 1), goal.DistanceToPoint(from)); | fixed searchRange = SHORT_PATH_MIN_SEARCH_RANGE + SHORT_PATH_SEARCH_RANGE_INCREMENT * m_FailedPathComputations; | ||||
if (searchRange > SHORT_PATH_MAX_SEARCH_RANGE) | if (searchRange > SHORT_PATH_MAX_SEARCH_RANGE) | ||||
searchRange = SHORT_PATH_MAX_SEARCH_RANGE; | searchRange = SHORT_PATH_MAX_SEARCH_RANGE; | ||||
m_ExpectedPathTicket.m_Type = Ticket::SHORT_PATH; | m_ExpectedPathTicket.m_Type = Ticket::SHORT_PATH; | ||||
m_ExpectedPathTicket.m_Ticket = cmpPathfinder->ComputeShortPathAsync(from.X, from.Y, m_Clearance, searchRange, goal, m_PassClass, avoidMovingUnits, GetGroup(), GetEntityId()); | m_ExpectedPathTicket.m_Ticket = cmpPathfinder->ComputeShortPathAsync(from.X, from.Y, m_Clearance, searchRange, goal, m_PassClass, avoidMovingUnits, GetGroup(), GetEntityId()); | ||||
} | } | ||||
bool CCmpUnitMotion::MoveToPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t minRange, entity_pos_t maxRange) | bool CCmpUnitMotion::MoveToPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t minRange, entity_pos_t maxRange) | ||||
▲ Show 20 Lines • Show All 108 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator