Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

246 lines
7.3 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // nav_path.h
  9. // Navigation Path encapsulation
  10. // Author: Michael S. Booth ([email protected]), November 2003
  11. #ifndef _NAV_PATH_H_
  12. #define _NAV_PATH_H_
  13. #include "cs_nav_area.h"
  14. #include "bot_util.h"
  15. class CImprovLocomotor;
  16. //--------------------------------------------------------------------------------------------------------
  17. /**
  18. * The CNavPath class encapsulates a path through space
  19. */
  20. class CNavPath
  21. {
  22. public:
  23. CNavPath( void )
  24. {
  25. m_segmentCount = 0;
  26. }
  27. struct PathSegment
  28. {
  29. CNavArea *area; ///< the area along the path
  30. NavTraverseType how; ///< how to enter this area from the previous one
  31. Vector pos; ///< our movement goal position at this point in the path
  32. const CNavLadder *ladder; ///< if "how" refers to a ladder, this is it
  33. };
  34. const PathSegment * operator[] ( int i ) const { return (i >= 0 && i < m_segmentCount) ? &m_path[i] : NULL; }
  35. const PathSegment *GetSegment( int i ) const { return (i >= 0 && i < m_segmentCount) ? &m_path[i] : NULL; }
  36. int GetSegmentCount( void ) const { return m_segmentCount; }
  37. const Vector &GetEndpoint( void ) const { return m_path[ m_segmentCount-1 ].pos; }
  38. bool IsAtEnd( const Vector &pos ) const; ///< return true if position is at the end of the path
  39. float GetLength( void ) const; ///< return length of path from start to finish
  40. bool GetPointAlongPath( float distAlong, Vector *pointOnPath ) const; ///< return point a given distance along the path - if distance is out of path bounds, point is clamped to start/end
  41. /// return the node index closest to the given distance along the path without going over - returns (-1) if error
  42. int GetSegmentIndexAlongPath( float distAlong ) const;
  43. bool IsValid( void ) const { return (m_segmentCount > 0); }
  44. void Invalidate( void ) { m_segmentCount = 0; }
  45. void Draw( const Vector &color = Vector( 1.0f, 0.3f, 0 ) ); ///< draw the path for debugging
  46. /// compute closest point on path to given point
  47. bool FindClosestPointOnPath( const Vector *worldPos, int startIndex, int endIndex, Vector *close ) const;
  48. void Optimize( void );
  49. /**
  50. * Compute shortest path from 'start' to 'goal' via A* algorithm.
  51. * If returns true, path was build to the goal position.
  52. * If returns false, path may either be invalid (use IsValid() to check), or valid but
  53. * doesn't reach all the way to the goal.
  54. */
  55. template< typename CostFunctor >
  56. bool Compute( const Vector &start, const Vector &goal, CostFunctor &costFunc )
  57. {
  58. Invalidate();
  59. CNavArea *startArea = TheNavMesh->GetNearestNavArea( start + Vector( 0.0f, 0.0f, 1.0f ) );
  60. if (startArea == NULL)
  61. {
  62. return false;
  63. }
  64. CNavArea *goalArea = TheNavMesh->GetNavArea( goal );
  65. // if we are already in the goal area, build trivial path
  66. if (startArea == goalArea)
  67. {
  68. BuildTrivialPath( start, goal );
  69. return true;
  70. }
  71. // make sure path end position is on the ground
  72. Vector pathEndPosition = goal;
  73. if (goalArea)
  74. {
  75. pathEndPosition.z = goalArea->GetZ( pathEndPosition );
  76. }
  77. else
  78. {
  79. TheNavMesh->GetGroundHeight( pathEndPosition, &pathEndPosition.z );
  80. }
  81. //
  82. // Compute shortest path to goal
  83. //
  84. CNavArea *closestArea;
  85. bool pathResult = NavAreaBuildPath( startArea, goalArea, &goal, costFunc, &closestArea );
  86. //
  87. // Build path by following parent links
  88. //
  89. // get count
  90. int count = 0;
  91. CNavArea *area;
  92. for( area = closestArea; area; area = area->GetParent() )
  93. {
  94. ++count;
  95. }
  96. // save room for endpoint
  97. if (count > MAX_PATH_SEGMENTS-1)
  98. {
  99. count = MAX_PATH_SEGMENTS-1;
  100. }
  101. if (count == 0)
  102. {
  103. return false;
  104. }
  105. if (count == 1)
  106. {
  107. BuildTrivialPath( start, goal );
  108. return true;
  109. }
  110. // build path
  111. m_segmentCount = count;
  112. for( area = closestArea; count && area; area = area->GetParent() )
  113. {
  114. --count;
  115. m_path[ count ].area = area;
  116. m_path[ count ].how = area->GetParentHow();
  117. }
  118. // compute path positions
  119. if (ComputePathPositions() == false)
  120. {
  121. //PrintIfWatched( "CNavPath::Compute: Error building path\n" );
  122. Invalidate();
  123. return false;
  124. }
  125. // append path end position
  126. m_path[ m_segmentCount ].area = closestArea;
  127. m_path[ m_segmentCount ].pos = pathEndPosition;
  128. m_path[ m_segmentCount ].ladder = NULL;
  129. m_path[ m_segmentCount ].how = NUM_TRAVERSE_TYPES;
  130. ++m_segmentCount;
  131. return pathResult;
  132. }
  133. private:
  134. enum { MAX_PATH_SEGMENTS = 256 };
  135. PathSegment m_path[ MAX_PATH_SEGMENTS ];
  136. int m_segmentCount;
  137. bool ComputePathPositions( void ); ///< determine actual path positions
  138. bool BuildTrivialPath( const Vector &start, const Vector &goal ); ///< utility function for when start and goal are in the same area
  139. int FindNextOccludedNode( int anchor ); ///< used by Optimize()
  140. };
  141. //--------------------------------------------------------------------------------------------------------
  142. /**
  143. * Monitor improv movement and determine if it becomes stuck
  144. */
  145. class CStuckMonitor
  146. {
  147. public:
  148. CStuckMonitor( void );
  149. void Reset( void );
  150. void Update( CImprovLocomotor *improv );
  151. bool IsStuck( void ) const { return m_isStuck; }
  152. float GetDuration( void ) const { return (m_isStuck) ? m_stuckTimer.GetElapsedTime() : 0.0f; }
  153. private:
  154. bool m_isStuck; ///< if true, we are stuck
  155. Vector m_stuckSpot; ///< the location where we became stuck
  156. IntervalTimer m_stuckTimer; ///< how long we have been stuck
  157. enum { MAX_VEL_SAMPLES = 5 };
  158. float m_avgVel[ MAX_VEL_SAMPLES ];
  159. int m_avgVelIndex;
  160. int m_avgVelCount;
  161. Vector m_lastCentroid;
  162. float m_lastTime;
  163. };
  164. //--------------------------------------------------------------------------------------------------------
  165. /**
  166. * The CNavPathFollower class implements path following behavior
  167. */
  168. class CNavPathFollower
  169. {
  170. public:
  171. CNavPathFollower( void );
  172. void SetImprov( CImprovLocomotor *improv ) { m_improv = improv; }
  173. void SetPath( CNavPath *path ) { m_path = path; }
  174. void Reset( void );
  175. #define DONT_AVOID_OBSTACLES false
  176. void Update( float deltaT, bool avoidObstacles = true ); ///< move improv along path
  177. void Debug( bool status ) { m_isDebug = status; } ///< turn debugging on/off
  178. bool IsStuck( void ) const { return m_stuckMonitor.IsStuck(); } ///< return true if improv is stuck
  179. void ResetStuck( void ) { m_stuckMonitor.Reset(); }
  180. float GetStuckDuration( void ) const { return m_stuckMonitor.GetDuration(); } ///< return how long we've been stuck
  181. void FeelerReflexAdjustment( Vector *goalPosition, float height = -1.0f ); ///< adjust goal position if "feelers" are touched
  182. private:
  183. CImprovLocomotor *m_improv; ///< who is doing the path following
  184. CNavPath *m_path; ///< the path being followed
  185. int m_segmentIndex; ///< the point on the path the improv is moving towards
  186. int m_behindIndex; ///< index of the node on the path just behind us
  187. Vector m_goal; ///< last computed follow goal
  188. bool m_isLadderStarted;
  189. bool m_isDebug;
  190. int FindOurPositionOnPath( Vector *close, bool local ) const; ///< return the closest point to our current position on current path
  191. int FindPathPoint( float aheadRange, Vector *point, int *prevIndex ); ///< compute a point a fixed distance ahead along our path.
  192. CStuckMonitor m_stuckMonitor;
  193. };
  194. #endif // _NAV_PATH_H_