DetourCrowd.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. //
  2. // Copyright (c) 2009-2010 Mikko Mononen [email protected]
  3. //
  4. // This software is provided 'as-is', without any express or implied
  5. // warranty. In no event will the authors be held liable for any damages
  6. // arising from the use of this software.
  7. // Permission is granted to anyone to use this software for any purpose,
  8. // including commercial applications, and to alter it and redistribute it
  9. // freely, subject to the following restrictions:
  10. // 1. The origin of this software must not be misrepresented; you must not
  11. // claim that you wrote the original software. If you use this software
  12. // in a product, an acknowledgment in the product documentation would be
  13. // appreciated but is not required.
  14. // 2. Altered source versions must be plainly marked as such, and must not be
  15. // misrepresented as being the original software.
  16. // 3. This notice may not be removed or altered from any source distribution.
  17. //
  18. // Modified by Yao Wei Tjong for Urho3D
  19. #ifndef DETOURCROWD_H
  20. #define DETOURCROWD_H
  21. // ATOMIC BEGIN
  22. #include "../../Detour/include/DetourNavMeshQuery.h"
  23. // ATOMIC END
  24. #include "DetourObstacleAvoidance.h"
  25. #include "DetourLocalBoundary.h"
  26. #include "DetourPathCorridor.h"
  27. #include "DetourProximityGrid.h"
  28. #include "DetourPathQueue.h"
  29. /// The maximum number of neighbors that a crowd agent can take into account
  30. /// for steering decisions.
  31. /// @ingroup crowd
  32. static const int DT_CROWDAGENT_MAX_NEIGHBOURS = 6;
  33. /// The maximum number of corners a crowd agent will look ahead in the path.
  34. /// This value is used for sizing the crowd agent corner buffers.
  35. /// Due to the behavior of the crowd manager, the actual number of useful
  36. /// corners will be one less than this number.
  37. /// @ingroup crowd
  38. static const int DT_CROWDAGENT_MAX_CORNERS = 4;
  39. /// The maximum number of crowd avoidance configurations supported by the
  40. /// crowd manager.
  41. /// @ingroup crowd
  42. /// @see dtObstacleAvoidanceParams, dtCrowd::setObstacleAvoidanceParams(), dtCrowd::getObstacleAvoidanceParams(),
  43. /// dtCrowdAgentParams::obstacleAvoidanceType
  44. static const int DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS = 8;
  45. /// The maximum number of query filter types supported by the crowd manager.
  46. /// @ingroup crowd
  47. /// @see dtQueryFilter, dtCrowd::getFilter() dtCrowd::getEditableFilter(),
  48. /// dtCrowdAgentParams::queryFilterType
  49. static const int DT_CROWD_MAX_QUERY_FILTER_TYPE = 16;
  50. /// Provides neighbor data for agents managed by the crowd.
  51. /// @ingroup crowd
  52. /// @see dtCrowdAgent::neis, dtCrowd
  53. struct dtCrowdNeighbour
  54. {
  55. int idx; ///< The index of the neighbor in the crowd.
  56. float dist; ///< The distance between the current agent and the neighbor.
  57. };
  58. /// The type of navigation mesh polygon the agent is currently traversing.
  59. /// @ingroup crowd
  60. enum CrowdAgentState
  61. {
  62. DT_CROWDAGENT_STATE_INVALID, ///< The agent is not in a valid state.
  63. DT_CROWDAGENT_STATE_WALKING, ///< The agent is traversing a normal navigation mesh polygon.
  64. DT_CROWDAGENT_STATE_OFFMESH, ///< The agent is traversing an off-mesh connection.
  65. };
  66. /// Configuration parameters for a crowd agent.
  67. /// @ingroup crowd
  68. struct dtCrowdAgentParams
  69. {
  70. float radius; ///< Agent radius. [Limit: >= 0]
  71. float height; ///< Agent height. [Limit: > 0]
  72. float maxAcceleration; ///< Maximum allowed acceleration. [Limit: >= 0]
  73. float maxSpeed; ///< Maximum allowed speed. [Limit: >= 0]
  74. /// Defines how close a collision element must be before it is considered for steering behaviors. [Limits: > 0]
  75. float collisionQueryRange;
  76. float pathOptimizationRange; ///< The path visibility optimization range. [Limit: > 0]
  77. /// How aggresive the agent manager should be at avoiding collisions with this agent. [Limit: >= 0]
  78. float separationWeight;
  79. /// Flags that impact steering behavior. (See: #UpdateFlags)
  80. unsigned char updateFlags;
  81. /// The index of the avoidance configuration to use for the agent.
  82. /// [Limits: 0 <= value <= #DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS]
  83. unsigned char obstacleAvoidanceType;
  84. /// The index of the query filter used by this agent.
  85. unsigned char queryFilterType;
  86. /// User defined data attached to the agent.
  87. void* userData;
  88. };
  89. enum MoveRequestState
  90. {
  91. DT_CROWDAGENT_TARGET_NONE = 0,
  92. DT_CROWDAGENT_TARGET_FAILED,
  93. DT_CROWDAGENT_TARGET_VALID,
  94. DT_CROWDAGENT_TARGET_REQUESTING,
  95. DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE,
  96. DT_CROWDAGENT_TARGET_WAITING_FOR_PATH,
  97. DT_CROWDAGENT_TARGET_VELOCITY,
  98. };
  99. /// Represents an agent managed by a #dtCrowd object.
  100. /// @ingroup crowd
  101. struct dtCrowdAgent
  102. {
  103. /// True if the agent is active, false if the agent is in an unused slot in the agent pool.
  104. bool active;
  105. /// The type of mesh polygon the agent is traversing. (See: #CrowdAgentState)
  106. unsigned char state;
  107. /// True if the agent has valid path (targetState == DT_CROWDAGENT_TARGET_VALID) and the path does not lead to the requested position, else false.
  108. bool partial;
  109. /// The path corridor the agent is using.
  110. dtPathCorridor corridor;
  111. /// The local boundary data for the agent.
  112. dtLocalBoundary boundary;
  113. /// Time since the agent's path corridor was optimized.
  114. float topologyOptTime;
  115. /// The known neighbors of the agent.
  116. dtCrowdNeighbour neis[DT_CROWDAGENT_MAX_NEIGHBOURS];
  117. /// The number of neighbors.
  118. int nneis;
  119. /// The desired speed.
  120. float desiredSpeed;
  121. float npos[3]; ///< The current agent position. [(x, y, z)]
  122. float disp[3];
  123. float dvel[3]; ///< The desired velocity of the agent. [(x, y, z)]
  124. float nvel[3];
  125. float vel[3]; ///< The actual velocity of the agent. [(x, y, z)]
  126. /// The agent's configuration parameters.
  127. dtCrowdAgentParams params;
  128. /// The local path corridor corners for the agent. (Staight path.) [(x, y, z) * #ncorners]
  129. float cornerVerts[DT_CROWDAGENT_MAX_CORNERS*3];
  130. /// The local path corridor corner flags. (See: #dtStraightPathFlags) [(flags) * #ncorners]
  131. unsigned char cornerFlags[DT_CROWDAGENT_MAX_CORNERS];
  132. /// The reference id of the polygon being entered at the corner. [(polyRef) * #ncorners]
  133. dtPolyRef cornerPolys[DT_CROWDAGENT_MAX_CORNERS];
  134. /// The number of corners.
  135. int ncorners;
  136. unsigned char targetState; ///< State of the movement request.
  137. dtPolyRef targetRef; ///< Target polyref of the movement request.
  138. float targetPos[3]; ///< Target position of the movement request (or velocity in case of DT_CROWDAGENT_TARGET_VELOCITY).
  139. dtPathQueueRef targetPathqRef; ///< Path finder ref.
  140. bool targetReplan; ///< Flag indicating that the current path is being replanned.
  141. float targetReplanTime; /// <Time since the agent's target was replanned.
  142. };
  143. struct dtCrowdAgentAnimation
  144. {
  145. bool active;
  146. float initPos[3], startPos[3], endPos[3];
  147. dtPolyRef polyRef;
  148. float t, tmax;
  149. };
  150. /// Crowd agent update flags.
  151. /// @ingroup crowd
  152. /// @see dtCrowdAgentParams::updateFlags
  153. enum UpdateFlags
  154. {
  155. DT_CROWD_ANTICIPATE_TURNS = 1,
  156. DT_CROWD_OBSTACLE_AVOIDANCE = 2,
  157. DT_CROWD_SEPARATION = 4,
  158. DT_CROWD_OPTIMIZE_VIS = 8, ///< Use #dtPathCorridor::optimizePathVisibility() to optimize the agent path.
  159. DT_CROWD_OPTIMIZE_TOPO = 16, ///< Use dtPathCorridor::optimizePathTopology() to optimize the agent path.
  160. };
  161. struct dtCrowdAgentDebugInfo
  162. {
  163. int idx;
  164. float optStart[3], optEnd[3];
  165. dtObstacleAvoidanceDebugData* vod;
  166. };
  167. // Urho3D: Add update callback support
  168. /// Type for the update callback.
  169. typedef void (*dtUpdateCallback)(dtCrowdAgent* ag, float dt);
  170. /// Provides local steering behaviors for a group of agents.
  171. /// @ingroup crowd
  172. class dtCrowd
  173. {
  174. dtUpdateCallback m_updateCallback;
  175. int m_maxAgents;
  176. dtCrowdAgent* m_agents;
  177. dtCrowdAgent** m_activeAgents;
  178. dtCrowdAgentAnimation* m_agentAnims;
  179. dtPathQueue m_pathq;
  180. dtObstacleAvoidanceParams m_obstacleQueryParams[DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS];
  181. dtObstacleAvoidanceQuery* m_obstacleQuery;
  182. dtProximityGrid* m_grid;
  183. dtPolyRef* m_pathResult;
  184. int m_maxPathResult;
  185. float m_ext[3];
  186. dtQueryFilter m_filters[DT_CROWD_MAX_QUERY_FILTER_TYPE];
  187. float m_maxAgentRadius;
  188. int m_velocitySampleCount;
  189. dtNavMeshQuery* m_navquery;
  190. void updateTopologyOptimization(dtCrowdAgent** agents, const int nagents, const float dt);
  191. void updateMoveRequest(const float dt);
  192. void checkPathValidity(dtCrowdAgent** agents, const int nagents, const float dt);
  193. inline int getAgentIndex(const dtCrowdAgent* agent) const { return (int)(agent - m_agents); }
  194. bool requestMoveTargetReplan(const int idx, dtPolyRef ref, const float* pos);
  195. void purge();
  196. public:
  197. dtCrowd();
  198. ~dtCrowd();
  199. // Urho3D: Add update callback support
  200. /// Initializes the crowd.
  201. /// @param[in] maxAgents The maximum number of agents the crowd can manage. [Limit: >= 1]
  202. /// @param[in] maxAgentRadius The maximum radius of any agent that will be added to the crowd. [Limit: > 0]
  203. /// @param[in] nav The navigation mesh to use for planning.
  204. /// @param[in] cb The update callback.
  205. /// @return True if the initialization succeeded.
  206. bool init(const int maxAgents, const float maxAgentRadius, dtNavMesh* nav, dtUpdateCallback cb = 0);
  207. /// Sets the shared avoidance configuration for the specified index.
  208. /// @param[in] idx The index. [Limits: 0 <= value < #DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS]
  209. /// @param[in] params The new configuration.
  210. void setObstacleAvoidanceParams(const int idx, const dtObstacleAvoidanceParams* params);
  211. /// Gets the shared avoidance configuration for the specified index.
  212. /// @param[in] idx The index of the configuration to retreive.
  213. /// [Limits: 0 <= value < #DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS]
  214. /// @return The requested configuration.
  215. const dtObstacleAvoidanceParams* getObstacleAvoidanceParams(const int idx) const;
  216. /// Gets the specified agent from the pool.
  217. /// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
  218. /// @return The requested agent.
  219. const dtCrowdAgent* getAgent(const int idx);
  220. /// Gets the specified agent from the pool.
  221. /// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
  222. /// @return The requested agent.
  223. dtCrowdAgent* getEditableAgent(const int idx);
  224. /// The maximum number of agents that can be managed by the object.
  225. /// @return The maximum number of agents.
  226. int getAgentCount() const;
  227. // Urho3D: Add missing getter
  228. /// The maximum radius of any agent that will be added to the crowd.
  229. /// @return The maximum radius of any agent.
  230. float getMaxAgentRadius() const { return m_maxAgentRadius; }
  231. /// Adds a new agent to the crowd.
  232. /// @param[in] pos The requested position of the agent. [(x, y, z)]
  233. /// @param[in] params The configutation of the agent.
  234. /// @return The index of the agent in the agent pool. Or -1 if the agent could not be added.
  235. int addAgent(const float* pos, const dtCrowdAgentParams* params);
  236. /// Updates the specified agent's configuration.
  237. /// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
  238. /// @param[in] params The new agent configuration.
  239. void updateAgentParameters(const int idx, const dtCrowdAgentParams* params);
  240. /// Removes the agent from the crowd.
  241. /// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
  242. void removeAgent(const int idx);
  243. /// Submits a new move request for the specified agent.
  244. /// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
  245. /// @param[in] ref The position's polygon reference.
  246. /// @param[in] pos The position within the polygon. [(x, y, z)]
  247. /// @return True if the request was successfully submitted.
  248. bool requestMoveTarget(const int idx, dtPolyRef ref, const float* pos);
  249. /// Submits a new move request for the specified agent.
  250. /// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
  251. /// @param[in] vel The movement velocity. [(x, y, z)]
  252. /// @return True if the request was successfully submitted.
  253. bool requestMoveVelocity(const int idx, const float* vel);
  254. /// Resets any request for the specified agent.
  255. /// @param[in] idx The agent index. [Limits: 0 <= value < #getAgentCount()]
  256. /// @return True if the request was successfully reseted.
  257. bool resetMoveTarget(const int idx);
  258. /// Gets the active agents int the agent pool.
  259. /// @param[out] agents An array of agent pointers. [(#dtCrowdAgent *) * maxAgents]
  260. /// @param[in] maxAgents The size of the crowd agent array.
  261. /// @return The number of agents returned in @p agents.
  262. int getActiveAgents(dtCrowdAgent** agents, const int maxAgents);
  263. /// Updates the steering and positions of all agents.
  264. /// @param[in] dt The time, in seconds, to update the simulation. [Limit: > 0]
  265. /// @param[out] debug A debug object to load with debug information. [Opt]
  266. void update(const float dt, dtCrowdAgentDebugInfo* debug);
  267. /// Gets the filter used by the crowd.
  268. /// @return The filter used by the crowd.
  269. inline const dtQueryFilter* getFilter(const int i) const { return (i >= 0 && i < DT_CROWD_MAX_QUERY_FILTER_TYPE) ? &m_filters[i] : 0; }
  270. /// Gets the filter used by the crowd.
  271. /// @return The filter used by the crowd.
  272. inline dtQueryFilter* getEditableFilter(const int i) { return (i >= 0 && i < DT_CROWD_MAX_QUERY_FILTER_TYPE) ? &m_filters[i] : 0; }
  273. /// Gets the search extents [(x, y, z)] used by the crowd for query operations.
  274. /// @return The search extents used by the crowd. [(x, y, z)]
  275. const float* getQueryExtents() const { return m_ext; }
  276. /// Gets the velocity sample count.
  277. /// @return The velocity sample count.
  278. inline int getVelocitySampleCount() const { return m_velocitySampleCount; }
  279. /// Gets the crowd's proximity grid.
  280. /// @return The crowd's proximity grid.
  281. const dtProximityGrid* getGrid() const { return m_grid; }
  282. /// Gets the crowd's path request queue.
  283. /// @return The crowd's path request queue.
  284. const dtPathQueue* getPathQueue() const { return &m_pathq; }
  285. /// Gets the query object used by the crowd.
  286. const dtNavMeshQuery* getNavMeshQuery() const { return m_navquery; }
  287. };
  288. /// Allocates a crowd object using the Detour allocator.
  289. /// @return A crowd object that is ready for initialization, or null on failure.
  290. /// @ingroup crowd
  291. dtCrowd* dtAllocCrowd();
  292. /// Frees the specified crowd object using the Detour allocator.
  293. /// @param[in] ptr A crowd object allocated using #dtAllocCrowd
  294. /// @ingroup crowd
  295. void dtFreeCrowd(dtCrowd* ptr);
  296. #endif // DETOURCROWD_H
  297. ///////////////////////////////////////////////////////////////////////////
  298. // This section contains detailed documentation for members that don't have
  299. // a source file. It reduces clutter in the main section of the header.
  300. /**
  301. @defgroup crowd Crowd
  302. Members in this module implement local steering and dynamic avoidance features.
  303. The crowd is the big beast of the navigation features. It not only handles a
  304. lot of the path management for you, but also local steering and dynamic
  305. avoidance between members of the crowd. I.e. It can keep your agents from
  306. running into each other.
  307. Main class: #dtCrowd
  308. The #dtNavMeshQuery and #dtPathCorridor classes provide perfectly good, easy
  309. to use path planning features. But in the end they only give you points that
  310. your navigation client should be moving toward. When it comes to deciding things
  311. like agent velocity and steering to avoid other agents, that is up to you to
  312. implement. Unless, of course, you decide to use #dtCrowd.
  313. Basically, you add an agent to the crowd, providing various configuration
  314. settings such as maximum speed and acceleration. You also provide a local
  315. target to more toward. The crowd manager then provides, with every update, the
  316. new agent position and velocity for the frame. The movement will be
  317. constrained to the navigation mesh, and steering will be applied to ensure
  318. agents managed by the crowd do not collide with each other.
  319. This is very powerful feature set. But it comes with limitations.
  320. The biggest limitation is that you must give control of the agent's position
  321. completely over to the crowd manager. You can update things like maximum speed
  322. and acceleration. But in order for the crowd manager to do its thing, it can't
  323. allow you to constantly be giving it overrides to position and velocity. So
  324. you give up direct control of the agent's movement. It belongs to the crowd.
  325. The second biggest limitation revolves around the fact that the crowd manager
  326. deals with local planning. So the agent's target should never be more than
  327. 256 polygons aways from its current position. If it is, you risk
  328. your agent failing to reach its target. So you may still need to do long
  329. distance planning and provide the crowd manager with intermediate targets.
  330. Other significant limitations:
  331. - All agents using the crowd manager will use the same #dtQueryFilter.
  332. - Crowd management is relatively expensive. The maximum agents under crowd
  333. management at any one time is between 20 and 30. A good place to start
  334. is a maximum of 25 agents for 0.5ms per frame.
  335. @note This is a summary list of members. Use the index or search
  336. feature to find minor members.
  337. @struct dtCrowdAgentParams
  338. @see dtCrowdAgent, dtCrowd::addAgent(), dtCrowd::updateAgentParameters()
  339. @var dtCrowdAgentParams::obstacleAvoidanceType
  340. @par
  341. #dtCrowd permits agents to use different avoidance configurations. This value
  342. is the index of the #dtObstacleAvoidanceParams within the crowd.
  343. @see dtObstacleAvoidanceParams, dtCrowd::setObstacleAvoidanceParams(),
  344. dtCrowd::getObstacleAvoidanceParams()
  345. @var dtCrowdAgentParams::collisionQueryRange
  346. @par
  347. Collision elements include other agents and navigation mesh boundaries.
  348. This value is often based on the agent radius and/or maximum speed. E.g. radius * 8
  349. @var dtCrowdAgentParams::pathOptimizationRange
  350. @par
  351. Only applicalbe if #updateFlags includes the #DT_CROWD_OPTIMIZE_VIS flag.
  352. This value is often based on the agent radius. E.g. radius * 30
  353. @see dtPathCorridor::optimizePathVisibility()
  354. @var dtCrowdAgentParams::separationWeight
  355. @par
  356. A higher value will result in agents trying to stay farther away from each other at
  357. the cost of more difficult steering in tight spaces.
  358. */