Changeset View
Changeset View
Standalone View
Standalone View
source/simulation2/components/CCmpUnitMotion.cpp
Show All 39 Lines | |||||
#include "ps/Profile.h" | #include "ps/Profile.h" | ||||
#include "renderer/Scene.h" | #include "renderer/Scene.h" | ||||
// For debugging; units will start going straight to the target | // For debugging; units will start going straight to the target | ||||
// instead of calling the pathfinder | // instead of calling the pathfinder | ||||
#define DISABLE_PATHFINDER 0 | #define DISABLE_PATHFINDER 0 | ||||
/** | /** | ||||
* 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 | |||||
* 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); | |||||
/** | |||||
* 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, | ||||
* 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*2); | ||||
static const entity_pos_t SHORT_PATH_MAX_SEARCH_RANGE = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*9); | static const entity_pos_t SHORT_PATH_MAX_SEARCH_RANGE = entity_pos_t::FromInt(TERRAIN_TILE_SIZE*9); | ||||
/** | /** | ||||
* Minimum distance to goal for a long path request | * Minimum distance to goal for a long path request | ||||
▲ Show 20 Lines • Show All 344 Lines • ▼ Show 20 Lines | public: | ||||
} | } | ||||
virtual void SetDebugOverlay(bool enabled) | virtual void SetDebugOverlay(bool enabled) | ||||
{ | { | ||||
m_DebugOverlayEnabled = enabled; | m_DebugOverlayEnabled = enabled; | ||||
UpdateMessageSubscriptions(); | UpdateMessageSubscriptions(); | ||||
} | } | ||||
virtual bool MoveToPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t minRange, entity_pos_t maxRange); | virtual bool MoveToPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t minRange, entity_pos_t maxRange) | ||||
virtual bool MoveToTargetRange(entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange); | { | ||||
virtual void MoveToFormationOffset(entity_id_t target, entity_pos_t x, entity_pos_t z); | return MoveTo(MoveRequest(CFixedVector2D(x, z), minRange, maxRange)); | ||||
} | |||||
virtual bool MoveToTargetRange(entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange) | |||||
{ | |||||
return MoveTo(MoveRequest(target, minRange, maxRange)); | |||||
} | |||||
virtual void MoveToFormationOffset(entity_id_t target, entity_pos_t x, entity_pos_t z) | |||||
{ | |||||
MoveTo(MoveRequest(target, CFixedVector2D(x, z))); | |||||
} | |||||
virtual void FaceTowardsPoint(entity_pos_t x, entity_pos_t z); | virtual void FaceTowardsPoint(entity_pos_t x, entity_pos_t z); | ||||
virtual void StopMoving() | virtual void StopMoving() | ||||
{ | { | ||||
if (m_FacePointAfterMove) | if (m_FacePointAfterMove) | ||||
{ | { | ||||
CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle()); | CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle()); | ||||
Show All 28 Lines | bool IsFormationMember() const | ||||
return m_MoveRequest.m_Type == MoveRequest::OFFSET; | return m_MoveRequest.m_Type == MoveRequest::OFFSET; | ||||
} | } | ||||
entity_id_t GetGroup() const | entity_id_t GetGroup() const | ||||
{ | { | ||||
return IsFormationMember() ? m_MoveRequest.m_Entity : GetEntityId(); | return IsFormationMember() ? m_MoveRequest.m_Entity : GetEntityId(); | ||||
} | } | ||||
/** | |||||
* Warns other components that our current movement will likely fail (e.g. we won't be able to reach our target) | |||||
* This should only be called before the actual movement in a given turn, or units might both move and try to do things | |||||
* on the same turn, leading to gliding units. | |||||
*/ | |||||
void MoveFailed() | void MoveFailed() | ||||
{ | { | ||||
CMessageMotionChanged msg(true); | CMessageMotionChanged msg(true); | ||||
GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg); | GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg); | ||||
} | } | ||||
/** | |||||
* Warns other components that our current movement is likely over (i.e. we probably reached our destination) | |||||
* This should only be called before the actual movement in a given turn, or units might both move and try to do things | |||||
* on the same turn, leading to gliding units. | |||||
*/ | |||||
void MoveSucceeded() | void MoveSucceeded() | ||||
{ | { | ||||
CMessageMotionChanged msg(false); | CMessageMotionChanged msg(false); | ||||
GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg); | GetSimContext().GetComponentManager().PostMessage(GetEntityId(), msg); | ||||
} | } | ||||
/** | /** | ||||
* Update other components on our speed. | * Increment the number of failed path computations and notify other components if required. | ||||
* This doesn't use messages for efficiency. | |||||
* This should only be called when speed changes. | |||||
*/ | |||||
void UpdateMovementState(entity_pos_t speed) | |||||
{ | |||||
CmpPtr<ICmpObstruction> cmpObstruction(GetEntityHandle()); | |||||
CmpPtr<ICmpVisual> cmpVisual(GetEntityHandle()); | |||||
// Moved last turn, didn't this turn. | |||||
if (speed == fixed::Zero() && m_CurSpeed > fixed::Zero()) | |||||
{ | |||||
if (cmpObstruction) | |||||
cmpObstruction->SetMovingFlag(false); | |||||
if (cmpVisual) | |||||
cmpVisual->SelectMovementAnimation("idle", fixed::FromInt(1)); | |||||
} | |||||
// Moved this turn, didn't last turn | |||||
else if (speed > fixed::Zero() && m_CurSpeed == fixed::Zero()) | |||||
{ | |||||
if (cmpObstruction) | |||||
cmpObstruction->SetMovingFlag(true); | |||||
if (cmpVisual) | |||||
cmpVisual->SelectMovementAnimation(m_Speed > m_WalkSpeed ? "run" : "walk", m_Speed); | |||||
} | |||||
// Speed change, update the visual actor if necessary. | |||||
else if (speed != m_CurSpeed && cmpVisual) | |||||
cmpVisual->SelectMovementAnimation(m_Speed > m_WalkSpeed ? "run" : "walk", m_Speed); | |||||
m_CurSpeed = speed; | |||||
} | |||||
/** | |||||
* Increment the number of failed path and notify other components if required. | |||||
*/ | */ | ||||
void IncrementFailedPathComputationAndMaybeNotify() | void IncrementFailedPathComputationAndMaybeNotify() | ||||
{ | { | ||||
m_FailedPathComputations++; | m_FailedPathComputations++; | ||||
if (m_FailedPathComputations >= MAX_FAILED_PATH_COMPUTATIONS) | if (m_FailedPathComputations >= MAX_FAILED_PATH_COMPUTATIONS) | ||||
{ | { | ||||
MoveFailed(); | MoveFailed(); | ||||
m_FailedPathComputations = 0; | m_FailedPathComputations = 0; | ||||
Show All 18 Lines | private: | ||||
/** | /** | ||||
* Process the move the unit will do this turn. | * Process the move the unit will do this turn. | ||||
* This does not send actually change the position. | * This does not send actually change the position. | ||||
* @returns true if the move was obstructed. | * @returns true if the move was obstructed. | ||||
*/ | */ | ||||
bool PerformMove(fixed dt, WaypointPath& shortPath, WaypointPath& longPath, CFixedVector2D& pos) const; | bool PerformMove(fixed dt, WaypointPath& shortPath, WaypointPath& longPath, CFixedVector2D& pos) const; | ||||
/** | /** | ||||
* React if our move was obstructed. | * Update other components on our speed | ||||
* @returns true if the obstruction required handling, false otherwise. | * (this doesn't use messages for efficiency). | ||||
*/ | */ | ||||
bool HandleObstructedMove(); | void UpdateMovementState(entity_pos_t speed); | ||||
/** | /** | ||||
* Decide whether to approximate the given range from a square target as a circle, | * React if our move was obstructed. | ||||
* rather than as a square. | * @returns true if the obstruction required handling, false otherwise. | ||||
*/ | */ | ||||
bool ShouldTreatTargetAsCircle(entity_pos_t range, entity_pos_t circleRadius) const; | bool HandleObstructedMove(); | ||||
/** | /** | ||||
* Returns true if the target position is valid. False otherwise. | * Returns true if the target position is valid. False otherwise. | ||||
* (this may indicate that the target is e.g. out of the world/dead). | * (this may indicate that the target is e.g. out of the world/dead). | ||||
* NB: for code-writing convenience, if we have no target, this returns true. | * NB: for code-writing convenience, if we have no target, this returns true. | ||||
*/ | */ | ||||
bool TargetHasValidPosition(const MoveRequest& moveRequest) const; | bool TargetHasValidPosition(const MoveRequest& moveRequest) const; | ||||
bool TargetHasValidPosition() const | bool TargetHasValidPosition() const | ||||
Show All 18 Lines | private: | ||||
bool TryGoingStraightToTarget(const CFixedVector2D& from); | bool TryGoingStraightToTarget(const CFixedVector2D& from); | ||||
/** | /** | ||||
* Returns whether our we need to recompute a path to reach our target. | * Returns whether our we need to recompute a path to reach our target. | ||||
*/ | */ | ||||
bool PathingUpdateNeeded(const CFixedVector2D& from) const; | bool PathingUpdateNeeded(const CFixedVector2D& from) const; | ||||
/** | /** | ||||
* Returns whether the length of the given path, plus the distance from | |||||
* 'from' to the first waypoints, it shorter than minDistance. | |||||
*/ | |||||
bool PathIsShort(const WaypointPath& path, const CFixedVector2D& from, entity_pos_t minDistance) const; | |||||
/** | |||||
* Rotate to face towards the target point, given the current pos | * Rotate to face towards the target point, given the current pos | ||||
*/ | */ | ||||
void FaceTowardsPointFromPos(const CFixedVector2D& pos, entity_pos_t x, entity_pos_t z); | void FaceTowardsPointFromPos(const CFixedVector2D& pos, entity_pos_t x, entity_pos_t z); | ||||
/** | /** | ||||
* Returns an appropriate obstruction filter for use with path requests. | * Returns an appropriate obstruction filter for use with path requests. | ||||
* noTarget is true only when used inside TryGoingStraightToTarget, | * noTarget is true only when used inside TryGoingStraightToTarget, | ||||
* in which case we do not want the target obstruction otherwise it would always fail | * in which case we do not want the target obstruction otherwise it would always fail | ||||
*/ | */ | ||||
ControlGroupMovementObstructionFilter GetObstructionFilter(bool noTarget = false) const; | ControlGroupMovementObstructionFilter GetObstructionFilter(bool noTarget = false) const; | ||||
/** | /** | ||||
* Decide whether to approximate the given range from a square target as a circle, | |||||
* rather than as a square. | |||||
*/ | |||||
bool ShouldTreatTargetAsCircle(entity_pos_t range, entity_pos_t circleRadius) const; | |||||
/** | |||||
* Create a PathGoal from a move request. | * Create a PathGoal from a move request. | ||||
* @returns true if the goal was successfully created. | * @returns true if the goal was successfully created. | ||||
*/ | */ | ||||
bool ComputeGoal(PathGoal& out, const MoveRequest& moveRequest) const; | bool ComputeGoal(PathGoal& out, const MoveRequest& moveRequest) const; | ||||
/** | /** | ||||
* Start moving to the given goal, from our current position 'from'. | * Compute a path to the given goal from the given position. | ||||
* Might go in a straight line immediately, or might start an asynchronous | * Might go in a straight line immediately, or might start an asynchronous path request. | ||||
* path request. | |||||
*/ | */ | ||||
void BeginPathing(const CFixedVector2D& from, const PathGoal& goal); | void ComputePathToGoal(const CFixedVector2D& from, const PathGoal& goal); | ||||
/** | /** | ||||
* Start an asynchronous long path query. | * Start an asynchronous long path query. | ||||
*/ | */ | ||||
void RequestLongPath(const CFixedVector2D& from, const PathGoal& goal); | void RequestLongPath(const CFixedVector2D& from, const PathGoal& goal); | ||||
/** | /** | ||||
* Start an asynchronous short path query. | * Start an asynchronous short path query. | ||||
*/ | */ | ||||
void RequestShortPath(const CFixedVector2D& from, const PathGoal& goal, bool avoidMovingUnits); | void RequestShortPath(const CFixedVector2D& from, const PathGoal& goal, bool avoidMovingUnits); | ||||
/** | /** | ||||
* General handler for MoveTo interface functions. | |||||
*/ | |||||
bool MoveTo(MoveRequest request); | |||||
/** | |||||
* Convert a path into a renderable list of lines | * Convert a path into a renderable list of lines | ||||
*/ | */ | ||||
void RenderPath(const WaypointPath& path, std::vector<SOverlayLine>& lines, CColor color); | void RenderPath(const WaypointPath& path, std::vector<SOverlayLine>& lines, CColor color); | ||||
void RenderSubmit(SceneCollector& collector); | void RenderSubmit(SceneCollector& collector); | ||||
}; | }; | ||||
REGISTER_COMPONENT_TYPE(UnitMotion) | REGISTER_COMPONENT_TYPE(UnitMotion) | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | if (!m_LongPath.m_Waypoints.empty()) | ||||
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)) | ||||
return; | return; | ||||
BeginPathing(pos, goal); | ComputePathToGoal(pos, goal); | ||||
} | } | ||||
void CCmpUnitMotion::Move(fixed dt) | void CCmpUnitMotion::Move(fixed dt) | ||||
{ | { | ||||
PROFILE("Move"); | PROFILE("Move"); | ||||
// If we were idle and will still be, we can return. | // If we were idle and will still be, we can return. | ||||
// TODO: this will need to be removed if pushing is implemented. | // TODO: this will need to be removed if pushing is implemented. | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | else if (!wasObstructed) | ||||
m_FailedPathComputations = 0; | m_FailedPathComputations = 0; | ||||
// We may need to recompute our path sometimes (e.g. if our target moves). | // 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. | // Since we request paths asynchronously anyways, this does not need to be done before moving. | ||||
if (!wentStraight && PathingUpdateNeeded(pos)) | if (!wentStraight && PathingUpdateNeeded(pos)) | ||||
{ | { | ||||
PathGoal goal; | PathGoal goal; | ||||
if (ComputeGoal(goal, m_MoveRequest)) | if (ComputeGoal(goal, m_MoveRequest)) | ||||
BeginPathing(pos, goal); | ComputePathToGoal(pos, goal); | ||||
} | } | ||||
} | } | ||||
bool CCmpUnitMotion::PossiblyAtDestination() const | bool CCmpUnitMotion::PossiblyAtDestination() const | ||||
{ | { | ||||
if (m_MoveRequest.m_Type == MoveRequest::NONE) | if (m_MoveRequest.m_Type == MoveRequest::NONE) | ||||
return false; | return false; | ||||
▲ Show 20 Lines • Show All 103 Lines • ▼ Show 20 Lines | else | ||||
return true; | return true; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
void CCmpUnitMotion::UpdateMovementState(entity_pos_t speed) | |||||
{ | |||||
CmpPtr<ICmpObstruction> cmpObstruction(GetEntityHandle()); | |||||
CmpPtr<ICmpVisual> cmpVisual(GetEntityHandle()); | |||||
// Moved last turn, didn't this turn. | |||||
if (speed == fixed::Zero() && m_CurSpeed > fixed::Zero()) | |||||
{ | |||||
if (cmpObstruction) | |||||
cmpObstruction->SetMovingFlag(false); | |||||
if (cmpVisual) | |||||
cmpVisual->SelectMovementAnimation("idle", fixed::FromInt(1)); | |||||
} | |||||
// Moved this turn, didn't last turn | |||||
else if (speed > fixed::Zero() && m_CurSpeed == fixed::Zero()) | |||||
{ | |||||
if (cmpObstruction) | |||||
cmpObstruction->SetMovingFlag(true); | |||||
if (cmpVisual) | |||||
cmpVisual->SelectMovementAnimation(m_Speed > m_WalkSpeed ? "run" : "walk", m_Speed); | |||||
} | |||||
// Speed change, update the visual actor if necessary. | |||||
else if (speed != m_CurSpeed && cmpVisual) | |||||
cmpVisual->SelectMovementAnimation(m_Speed > m_WalkSpeed ? "run" : "walk", m_Speed); | |||||
m_CurSpeed = speed; | |||||
} | |||||
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; | ||||
CFixedVector2D pos = cmpPosition->GetPosition2D(); | CFixedVector2D pos = cmpPosition->GetPosition2D(); | ||||
// Oops, we hit something (very likely another unit). | // Oops, we hit something (very likely another unit). | ||||
// If we still have long waypoints, try and compute a short path | // If we still have long waypoints, try and compute a short path | ||||
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 }; | PathGoal goal = { PathGoal::POINT, m_LongPath.m_Waypoints.back().x, m_LongPath.m_Waypoints.back().z }; | ||||
RequestShortPath(pos, goal, false); | RequestShortPath(pos, goal, false); | ||||
return true; | return true; | ||||
} | } | ||||
// Else, just entirely recompute | // Else, just entirely recompute | ||||
PathGoal goal; | PathGoal goal; | ||||
if (!ComputeGoal(goal, m_MoveRequest)) | if (!ComputeGoal(goal, m_MoveRequest)) | ||||
return false; | return false; | ||||
BeginPathing(pos, goal); | ComputePathToGoal(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; | ||||
} | } | ||||
bool CCmpUnitMotion::TargetHasValidPosition(const MoveRequest& moveRequest) const | bool CCmpUnitMotion::TargetHasValidPosition(const MoveRequest& moveRequest) const | ||||
{ | { | ||||
if (moveRequest.m_Type != MoveRequest::ENTITY) | if (moveRequest.m_Type != MoveRequest::ENTITY) | ||||
▲ Show 20 Lines • Show All 134 Lines • ▼ Show 20 Lines | entity_pos_t maxRange = m_MoveRequest.m_MaxRange < entity_pos_t::Zero() ? m_MoveRequest.m_MaxRange : | ||||
m_MoveRequest.m_MaxRange + distance / TARGET_UNCERTAINTY_MULTIPLIER; | m_MoveRequest.m_MaxRange + distance / TARGET_UNCERTAINTY_MULTIPLIER; | ||||
if (cmpObstructionManager->AreShapesInRange(shape, estimatedTargetShape, minRange, maxRange, false)) | if (cmpObstructionManager->AreShapesInRange(shape, estimatedTargetShape, minRange, maxRange, false)) | ||||
return false; | return false; | ||||
return true; | return true; | ||||
} | } | ||||
bool CCmpUnitMotion::PathIsShort(const WaypointPath& path, const CFixedVector2D& from, entity_pos_t minDistance) const | |||||
{ | |||||
CFixedVector2D prev = from; | |||||
entity_pos_t distLeft = minDistance; | |||||
for (ssize_t i = (ssize_t)path.m_Waypoints.size()-1; i >= 0; --i) | |||||
{ | |||||
// Check if the next path segment is longer than the requested minimum | |||||
CFixedVector2D waypoint(path.m_Waypoints[i].x, path.m_Waypoints[i].z); | |||||
CFixedVector2D delta = waypoint - prev; | |||||
if (delta.CompareLength(distLeft) > 0) | |||||
return false; | |||||
// Still short enough - prepare to check the next segment | |||||
distLeft -= delta.Length(); | |||||
prev = waypoint; | |||||
} | |||||
// Reached the end of the path before exceeding minDistance | |||||
return true; | |||||
} | |||||
void CCmpUnitMotion::FaceTowardsPoint(entity_pos_t x, entity_pos_t z) | void CCmpUnitMotion::FaceTowardsPoint(entity_pos_t x, entity_pos_t z) | ||||
{ | { | ||||
CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle()); | CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle()); | ||||
if (!cmpPosition || !cmpPosition->IsInWorld()) | if (!cmpPosition || !cmpPosition->IsInWorld()) | ||||
return; | return; | ||||
CFixedVector2D pos = cmpPosition->GetPosition2D(); | CFixedVector2D pos = cmpPosition->GetPosition2D(); | ||||
FaceTowardsPointFromPos(pos, x, z); | FaceTowardsPointFromPos(pos, x, z); | ||||
▲ Show 20 Lines • Show All 134 Lines • ▼ Show 20 Lines | else | ||||
out.hw = targetObstruction.hw + delta; | out.hw = targetObstruction.hw + delta; | ||||
out.hh = targetObstruction.hh + delta; | out.hh = targetObstruction.hh + delta; | ||||
} | } | ||||
} | } | ||||
// Do nothing in particular in case we are already in range. | // Do nothing in particular in case we are already in range. | ||||
return true; | return true; | ||||
} | } | ||||
void CCmpUnitMotion::BeginPathing(const CFixedVector2D& from, const PathGoal& goal) | void CCmpUnitMotion::ComputePathToGoal(const CFixedVector2D& from, const PathGoal& goal) | ||||
{ | { | ||||
m_ExpectedPathTicket.clear(); | |||||
#if DISABLE_PATHFINDER | #if DISABLE_PATHFINDER | ||||
{ | { | ||||
CmpPtr<ICmpPathfinder> cmpPathfinder (GetSimContext(), SYSTEM_ENTITY); | CmpPtr<ICmpPathfinder> cmpPathfinder (GetSimContext(), SYSTEM_ENTITY); | ||||
CFixedVector2D goalPos = m_FinalGoal.NearestPointOnGoal(from); | CFixedVector2D goalPos = m_FinalGoal.NearestPointOnGoal(from); | ||||
m_LongPath.m_Waypoints.clear(); | m_LongPath.m_Waypoints.clear(); | ||||
m_ShortPath.m_Waypoints.clear(); | m_ShortPath.m_Waypoints.clear(); | ||||
m_ShortPath.m_Waypoints.emplace_back(Waypoint{ goalPos.X, goalPos.Y }); | m_ShortPath.m_Waypoints.emplace_back(Waypoint{ goalPos.X, goalPos.Y }); | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | 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); | searchRange = std::min(goal.hw, SHORT_PATH_MIN_SEARCH_RANGE * 2); | ||||
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::MoveTo(MoveRequest request) | ||||
{ | { | ||||
PROFILE("MoveToPointRange"); | PROFILE("MoveTo"); | ||||
MoveRequest moveRequest(CFixedVector2D(x, z), minRange, maxRange); | |||||
PathGoal goal; | |||||
if (!ComputeGoal(goal, moveRequest)) | |||||
return false; | |||||
CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle()); | CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle()); | ||||
if (!cmpPosition || !cmpPosition->IsInWorld()) | if (!cmpPosition || !cmpPosition->IsInWorld()) | ||||
return false; | return false; | ||||
m_MoveRequest = moveRequest; | |||||
m_FailedPathComputations = 0; | |||||
m_PretendLongPathIsCorrect = false; | |||||
BeginPathing(cmpPosition->GetPosition2D(), goal); | |||||
return true; | |||||
} | |||||
bool CCmpUnitMotion::MoveToTargetRange(entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange) | |||||
{ | |||||
PROFILE("MoveToTargetRange"); | |||||
MoveRequest moveRequest(target, minRange, maxRange); | |||||
PathGoal goal; | PathGoal goal; | ||||
if (!ComputeGoal(goal, request)) | |||||
if (!ComputeGoal(goal, moveRequest)) | |||||
return false; | return false; | ||||
CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle()); | m_MoveRequest = request; | ||||
if (!cmpPosition || !cmpPosition->IsInWorld()) | |||||
return false; | |||||
m_MoveRequest = moveRequest; | |||||
m_FailedPathComputations = 0; | m_FailedPathComputations = 0; | ||||
m_PretendLongPathIsCorrect = false; | m_PretendLongPathIsCorrect = false; | ||||
BeginPathing(cmpPosition->GetPosition2D(), goal); | ComputePathToGoal(cmpPosition->GetPosition2D(), goal); | ||||
return true; | return true; | ||||
} | } | ||||
void CCmpUnitMotion::MoveToFormationOffset(entity_id_t target, entity_pos_t x, entity_pos_t z) | |||||
{ | |||||
MoveRequest moveRequest(target, CFixedVector2D(x, z)); | |||||
PathGoal goal; | |||||
if (!ComputeGoal(goal, moveRequest)) | |||||
return; | |||||
CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), target); | |||||
if (!cmpPosition || !cmpPosition->IsInWorld()) | |||||
return; | |||||
m_MoveRequest = moveRequest; | |||||
m_FailedPathComputations = 0; | |||||
m_PretendLongPathIsCorrect = false; | |||||
BeginPathing(cmpPosition->GetPosition2D(), goal); | |||||
} | |||||
void CCmpUnitMotion::RenderPath(const WaypointPath& path, std::vector<SOverlayLine>& lines, CColor color) | void CCmpUnitMotion::RenderPath(const WaypointPath& path, std::vector<SOverlayLine>& lines, CColor color) | ||||
{ | { | ||||
bool floating = false; | bool floating = false; | ||||
CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle()); | CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle()); | ||||
if (cmpPosition) | if (cmpPosition) | ||||
floating = cmpPosition->CanFloat(); | floating = cmpPosition->CanFloat(); | ||||
lines.clear(); | lines.clear(); | ||||
Show All 35 Lines |
Wildfire Games · Phabricator