DetourCrowd.cpp 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465
  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 Lasse Oorni, Yao Wei Tjong, 1vanK and cosmy1 for Urho3D
  19. #define _USE_MATH_DEFINES
  20. #include <string.h>
  21. #include <float.h>
  22. #include <stdlib.h>
  23. #include <new>
  24. #include "DetourCrowd.h"
  25. #include "DetourNavMesh.h"
  26. #include "DetourNavMeshQuery.h"
  27. #include "DetourObstacleAvoidance.h"
  28. #include "DetourCommon.h"
  29. #include "DetourMath.h"
  30. #include "DetourAssert.h"
  31. #include "DetourAlloc.h"
  32. dtCrowd* dtAllocCrowd()
  33. {
  34. void* mem = dtAlloc(sizeof(dtCrowd), DT_ALLOC_PERM);
  35. if (!mem) return 0;
  36. return new(mem) dtCrowd;
  37. }
  38. void dtFreeCrowd(dtCrowd* ptr)
  39. {
  40. if (!ptr) return;
  41. ptr->~dtCrowd();
  42. dtFree(ptr);
  43. }
  44. static const int MAX_ITERS_PER_UPDATE = 100;
  45. static const int MAX_PATHQUEUE_NODES = 4096;
  46. static const int MAX_COMMON_NODES = 512;
  47. inline float tween(const float t, const float t0, const float t1)
  48. {
  49. return dtClamp((t-t0) / (t1-t0), 0.0f, 1.0f);
  50. }
  51. static void integrate(dtCrowdAgent* ag, const float dt)
  52. {
  53. // Fake dynamic constraint.
  54. const float maxDelta = ag->params.maxAcceleration * dt;
  55. float dv[3];
  56. dtVsub(dv, ag->nvel, ag->vel);
  57. float ds = dtVlen(dv);
  58. if (ds > maxDelta)
  59. dtVscale(dv, dv, maxDelta/ds);
  60. dtVadd(ag->vel, ag->vel, dv);
  61. // Integrate
  62. if (dtVlen(ag->vel) > 0.0001f)
  63. dtVmad(ag->npos, ag->npos, ag->vel, dt);
  64. else
  65. dtVset(ag->vel,0,0,0);
  66. }
  67. static bool overOffmeshConnection(const dtCrowdAgent* ag, const float radius)
  68. {
  69. if (!ag->ncorners)
  70. return false;
  71. const bool offMeshConnection = (ag->cornerFlags[ag->ncorners-1] & DT_STRAIGHTPATH_OFFMESH_CONNECTION) ? true : false;
  72. if (offMeshConnection)
  73. {
  74. const float distSq = dtVdist2DSqr(ag->npos, &ag->cornerVerts[(ag->ncorners-1)*3]);
  75. if (distSq < radius*radius)
  76. return true;
  77. }
  78. return false;
  79. }
  80. static float getDistanceToGoal(const dtCrowdAgent* ag, const float range)
  81. {
  82. if (!ag->ncorners)
  83. return range;
  84. const bool endOfPath = (ag->cornerFlags[ag->ncorners-1] & DT_STRAIGHTPATH_END) ? true : false;
  85. if (endOfPath)
  86. return dtMin(dtVdist2D(ag->npos, &ag->cornerVerts[(ag->ncorners-1)*3]), range);
  87. return range;
  88. }
  89. static void calcSmoothSteerDirection(const dtCrowdAgent* ag, float* dir)
  90. {
  91. if (!ag->ncorners)
  92. {
  93. dtVset(dir, 0,0,0);
  94. return;
  95. }
  96. const int ip0 = 0;
  97. const int ip1 = dtMin(1, ag->ncorners-1);
  98. const float* p0 = &ag->cornerVerts[ip0*3];
  99. const float* p1 = &ag->cornerVerts[ip1*3];
  100. float dir0[3], dir1[3];
  101. dtVsub(dir0, p0, ag->npos);
  102. dtVsub(dir1, p1, ag->npos);
  103. dir0[1] = 0;
  104. dir1[1] = 0;
  105. float len0 = dtVlen(dir0);
  106. float len1 = dtVlen(dir1);
  107. if (len1 > 0.001f)
  108. dtVscale(dir1,dir1,1.0f/len1);
  109. dir[0] = dir0[0] - dir1[0]*len0*0.5f;
  110. dir[1] = 0;
  111. dir[2] = dir0[2] - dir1[2]*len0*0.5f;
  112. dtVnormalize(dir);
  113. }
  114. static void calcStraightSteerDirection(const dtCrowdAgent* ag, float* dir)
  115. {
  116. if (!ag->ncorners)
  117. {
  118. dtVset(dir, 0,0,0);
  119. return;
  120. }
  121. dtVsub(dir, &ag->cornerVerts[0], ag->npos);
  122. dir[1] = 0;
  123. dtVnormalize(dir);
  124. }
  125. static int addNeighbour(const int idx, const float dist,
  126. dtCrowdNeighbour* neis, const int nneis, const int maxNeis)
  127. {
  128. // Insert neighbour based on the distance.
  129. dtCrowdNeighbour* nei = 0;
  130. if (!nneis)
  131. {
  132. nei = &neis[nneis];
  133. }
  134. else if (dist >= neis[nneis-1].dist)
  135. {
  136. if (nneis >= maxNeis)
  137. return nneis;
  138. nei = &neis[nneis];
  139. }
  140. else
  141. {
  142. int i;
  143. for (i = 0; i < nneis; ++i)
  144. if (dist <= neis[i].dist)
  145. break;
  146. const int tgt = i+1;
  147. const int n = dtMin(nneis-i, maxNeis-tgt);
  148. dtAssert(tgt+n <= maxNeis);
  149. if (n > 0)
  150. memmove(&neis[tgt], &neis[i], sizeof(dtCrowdNeighbour)*n);
  151. nei = &neis[i];
  152. }
  153. memset(nei, 0, sizeof(dtCrowdNeighbour));
  154. nei->idx = idx;
  155. nei->dist = dist;
  156. return dtMin(nneis+1, maxNeis);
  157. }
  158. static int getNeighbours(const float* pos, const float height, const float range,
  159. const dtCrowdAgent* skip, dtCrowdNeighbour* result, const int maxResult,
  160. dtCrowdAgent** agents, const int /*nagents*/, dtProximityGrid* grid)
  161. {
  162. int n = 0;
  163. static const int MAX_NEIS = 32;
  164. unsigned short ids[MAX_NEIS];
  165. int nids = grid->queryItems(pos[0]-range, pos[2]-range,
  166. pos[0]+range, pos[2]+range,
  167. ids, MAX_NEIS);
  168. for (int i = 0; i < nids; ++i)
  169. {
  170. const dtCrowdAgent* ag = agents[ids[i]];
  171. if (ag == skip) continue;
  172. // Check for overlap.
  173. float diff[3];
  174. dtVsub(diff, pos, ag->npos);
  175. if (dtMathFabs(diff[1]) >= (height+ag->params.height)/2.0f)
  176. continue;
  177. diff[1] = 0;
  178. const float distSqr = dtVlenSqr(diff);
  179. if (distSqr > dtSqr(range))
  180. continue;
  181. n = addNeighbour(ids[i], distSqr, result, n, maxResult);
  182. }
  183. return n;
  184. }
  185. static int addToOptQueue(dtCrowdAgent* newag, dtCrowdAgent** agents, const int nagents, const int maxAgents)
  186. {
  187. // Insert neighbour based on greatest time.
  188. int slot = 0;
  189. if (!nagents)
  190. {
  191. slot = nagents;
  192. }
  193. else if (newag->topologyOptTime <= agents[nagents-1]->topologyOptTime)
  194. {
  195. if (nagents >= maxAgents)
  196. return nagents;
  197. slot = nagents;
  198. }
  199. else
  200. {
  201. int i;
  202. for (i = 0; i < nagents; ++i)
  203. if (newag->topologyOptTime >= agents[i]->topologyOptTime)
  204. break;
  205. const int tgt = i+1;
  206. const int n = dtMin(nagents-i, maxAgents-tgt);
  207. dtAssert(tgt+n <= maxAgents);
  208. if (n > 0)
  209. memmove(&agents[tgt], &agents[i], sizeof(dtCrowdAgent*)*n);
  210. slot = i;
  211. }
  212. agents[slot] = newag;
  213. return dtMin(nagents+1, maxAgents);
  214. }
  215. static int addToPathQueue(dtCrowdAgent* newag, dtCrowdAgent** agents, const int nagents, const int maxAgents)
  216. {
  217. // Insert neighbour based on greatest time.
  218. int slot = 0;
  219. if (!nagents)
  220. {
  221. slot = nagents;
  222. }
  223. else if (newag->targetReplanTime <= agents[nagents-1]->targetReplanTime)
  224. {
  225. if (nagents >= maxAgents)
  226. return nagents;
  227. slot = nagents;
  228. }
  229. else
  230. {
  231. int i;
  232. for (i = 0; i < nagents; ++i)
  233. if (newag->targetReplanTime >= agents[i]->targetReplanTime)
  234. break;
  235. const int tgt = i+1;
  236. const int n = dtMin(nagents-i, maxAgents-tgt);
  237. dtAssert(tgt+n <= maxAgents);
  238. if (n > 0)
  239. memmove(&agents[tgt], &agents[i], sizeof(dtCrowdAgent*)*n);
  240. slot = i;
  241. }
  242. agents[slot] = newag;
  243. return dtMin(nagents+1, maxAgents);
  244. }
  245. /**
  246. @class dtCrowd
  247. @par
  248. This is the core class of the @ref crowd module. See the @ref crowd documentation for a summary
  249. of the crowd features.
  250. A common method for setting up the crowd is as follows:
  251. -# Allocate the crowd using #dtAllocCrowd.
  252. -# Initialize the crowd using #init().
  253. -# Set the avoidance configurations using #setObstacleAvoidanceParams().
  254. -# Add agents using #addAgent() and make an initial movement request using #requestMoveTarget().
  255. A common process for managing the crowd is as follows:
  256. -# Call #update() to allow the crowd to manage its agents.
  257. -# Retrieve agent information using #getActiveAgents().
  258. -# Make movement requests using #requestMoveTarget() when movement goal changes.
  259. -# Repeat every frame.
  260. Some agent configuration settings can be updated using #updateAgentParameters(). But the crowd owns the
  261. agent position. So it is not possible to update an active agent's position. If agent position
  262. must be fed back into the crowd, the agent must be removed and re-added.
  263. Notes:
  264. - Path related information is available for newly added agents only after an #update() has been
  265. performed.
  266. - Agent objects are kept in a pool and re-used. So it is important when using agent objects to check the value of
  267. #dtCrowdAgent::active to determine if the agent is actually in use or not.
  268. - This class is meant to provide 'local' movement. There is a limit of 256 polygons in the path corridor.
  269. So it is not meant to provide automatic pathfinding services over long distances.
  270. @see dtAllocCrowd(), dtFreeCrowd(), init(), dtCrowdAgent
  271. */
  272. dtCrowd::dtCrowd() :
  273. // Urho3D: Add update callback support
  274. m_updateCallback(0),
  275. m_maxAgents(0),
  276. m_agents(0),
  277. m_activeAgents(0),
  278. m_agentAnims(0),
  279. m_obstacleQuery(0),
  280. m_grid(0),
  281. m_pathResult(0),
  282. m_maxPathResult(0),
  283. m_maxAgentRadius(0),
  284. m_velocitySampleCount(0),
  285. m_navquery(0)
  286. {
  287. // Urho3D: initialize all class members
  288. memset(&m_ext, 0, sizeof(m_ext));
  289. memset(&m_obstacleQueryParams, 0, sizeof(m_obstacleQueryParams));
  290. }
  291. dtCrowd::~dtCrowd()
  292. {
  293. purge();
  294. }
  295. void dtCrowd::purge()
  296. {
  297. for (int i = 0; i < m_maxAgents; ++i)
  298. m_agents[i].~dtCrowdAgent();
  299. dtFree(m_agents);
  300. m_agents = 0;
  301. m_maxAgents = 0;
  302. dtFree(m_activeAgents);
  303. m_activeAgents = 0;
  304. dtFree(m_agentAnims);
  305. m_agentAnims = 0;
  306. dtFree(m_pathResult);
  307. m_pathResult = 0;
  308. dtFreeProximityGrid(m_grid);
  309. m_grid = 0;
  310. dtFreeObstacleAvoidanceQuery(m_obstacleQuery);
  311. m_obstacleQuery = 0;
  312. dtFreeNavMeshQuery(m_navquery);
  313. m_navquery = 0;
  314. }
  315. // Urho3D: Add update callback support
  316. /// @par
  317. ///
  318. /// May be called more than once to purge and re-initialize the crowd.
  319. bool dtCrowd::init(const int maxAgents, const float maxAgentRadius, dtNavMesh* nav, dtUpdateCallback cb)
  320. {
  321. purge();
  322. m_updateCallback = cb;
  323. m_maxAgents = maxAgents;
  324. m_maxAgentRadius = maxAgentRadius;
  325. dtVset(m_ext, m_maxAgentRadius*2.0f,m_maxAgentRadius*1.5f,m_maxAgentRadius*2.0f);
  326. m_grid = dtAllocProximityGrid();
  327. if (!m_grid)
  328. return false;
  329. if (!m_grid->init(m_maxAgents*4, maxAgentRadius*3))
  330. return false;
  331. m_obstacleQuery = dtAllocObstacleAvoidanceQuery();
  332. if (!m_obstacleQuery)
  333. return false;
  334. if (!m_obstacleQuery->init(6, 8))
  335. return false;
  336. // Init obstacle query params.
  337. memset(m_obstacleQueryParams, 0, sizeof(m_obstacleQueryParams));
  338. for (int i = 0; i < DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS; ++i)
  339. {
  340. dtObstacleAvoidanceParams* params = &m_obstacleQueryParams[i];
  341. params->velBias = 0.4f;
  342. params->weightDesVel = 2.0f;
  343. params->weightCurVel = 0.75f;
  344. params->weightSide = 0.75f;
  345. params->weightToi = 2.5f;
  346. params->horizTime = 2.5f;
  347. params->gridSize = 33;
  348. params->adaptiveDivs = 7;
  349. params->adaptiveRings = 2;
  350. params->adaptiveDepth = 5;
  351. }
  352. // Allocate temp buffer for merging paths.
  353. m_maxPathResult = 256;
  354. m_pathResult = (dtPolyRef*)dtAlloc(sizeof(dtPolyRef)*m_maxPathResult, DT_ALLOC_PERM);
  355. if (!m_pathResult)
  356. return false;
  357. if (!m_pathq.init(m_maxPathResult, MAX_PATHQUEUE_NODES, nav))
  358. return false;
  359. m_agents = (dtCrowdAgent*)dtAlloc(sizeof(dtCrowdAgent)*m_maxAgents, DT_ALLOC_PERM);
  360. if (!m_agents)
  361. return false;
  362. m_activeAgents = (dtCrowdAgent**)dtAlloc(sizeof(dtCrowdAgent*)*m_maxAgents, DT_ALLOC_PERM);
  363. if (!m_activeAgents)
  364. return false;
  365. m_agentAnims = (dtCrowdAgentAnimation*)dtAlloc(sizeof(dtCrowdAgentAnimation)*m_maxAgents, DT_ALLOC_PERM);
  366. if (!m_agentAnims)
  367. return false;
  368. for (int i = 0; i < m_maxAgents; ++i)
  369. {
  370. new(&m_agents[i]) dtCrowdAgent();
  371. m_agents[i].active = false;
  372. if (!m_agents[i].corridor.init(m_maxPathResult))
  373. return false;
  374. }
  375. for (int i = 0; i < m_maxAgents; ++i)
  376. {
  377. m_agentAnims[i].active = false;
  378. }
  379. // The navquery is mostly used for local searches, no need for large node pool.
  380. m_navquery = dtAllocNavMeshQuery();
  381. if (!m_navquery)
  382. return false;
  383. if (dtStatusFailed(m_navquery->init(nav, MAX_COMMON_NODES)))
  384. return false;
  385. return true;
  386. }
  387. void dtCrowd::setObstacleAvoidanceParams(const int idx, const dtObstacleAvoidanceParams* params)
  388. {
  389. if (idx >= 0 && idx < DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS)
  390. memcpy(&m_obstacleQueryParams[idx], params, sizeof(dtObstacleAvoidanceParams));
  391. }
  392. const dtObstacleAvoidanceParams* dtCrowd::getObstacleAvoidanceParams(const int idx) const
  393. {
  394. if (idx >= 0 && idx < DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS)
  395. return &m_obstacleQueryParams[idx];
  396. return 0;
  397. }
  398. int dtCrowd::getAgentCount() const
  399. {
  400. return m_maxAgents;
  401. }
  402. /// @par
  403. ///
  404. /// Agents in the pool may not be in use. Check #dtCrowdAgent.active before using the returned object.
  405. const dtCrowdAgent* dtCrowd::getAgent(const int idx)
  406. {
  407. if (idx < 0 || idx >= m_maxAgents)
  408. return 0;
  409. return &m_agents[idx];
  410. }
  411. ///
  412. /// Agents in the pool may not be in use. Check #dtCrowdAgent.active before using the returned object.
  413. dtCrowdAgent* dtCrowd::getEditableAgent(const int idx)
  414. {
  415. if (idx < 0 || idx >= m_maxAgents)
  416. return 0;
  417. return &m_agents[idx];
  418. }
  419. void dtCrowd::updateAgentParameters(const int idx, const dtCrowdAgentParams* params)
  420. {
  421. if (idx < 0 || idx >= m_maxAgents)
  422. return;
  423. memcpy(&m_agents[idx].params, params, sizeof(dtCrowdAgentParams));
  424. }
  425. /// @par
  426. ///
  427. /// The agent's position will be constrained to the surface of the navigation mesh.
  428. int dtCrowd::addAgent(const float* pos, const dtCrowdAgentParams* params)
  429. {
  430. // Find empty slot.
  431. int idx = -1;
  432. for (int i = 0; i < m_maxAgents; ++i)
  433. {
  434. if (!m_agents[i].active)
  435. {
  436. idx = i;
  437. break;
  438. }
  439. }
  440. if (idx == -1)
  441. return -1;
  442. dtCrowdAgent* ag = &m_agents[idx];
  443. updateAgentParameters(idx, params);
  444. // Find nearest position on navmesh and place the agent there.
  445. float nearest[3];
  446. dtPolyRef ref = 0;
  447. dtVcopy(nearest, pos);
  448. dtStatus status = m_navquery->findNearestPoly(pos, m_ext, &m_filters[ag->params.queryFilterType], &ref, nearest);
  449. if (dtStatusFailed(status))
  450. {
  451. dtVcopy(nearest, pos);
  452. ref = 0;
  453. }
  454. ag->corridor.reset(ref, nearest);
  455. ag->boundary.reset();
  456. ag->partial = false;
  457. ag->topologyOptTime = 0;
  458. ag->targetReplanTime = 0;
  459. ag->nneis = 0;
  460. dtVset(ag->dvel, 0,0,0);
  461. dtVset(ag->nvel, 0,0,0);
  462. dtVset(ag->vel, 0,0,0);
  463. dtVcopy(ag->npos, nearest);
  464. ag->desiredSpeed = 0;
  465. if (ref)
  466. ag->state = DT_CROWDAGENT_STATE_WALKING;
  467. else
  468. ag->state = DT_CROWDAGENT_STATE_INVALID;
  469. ag->targetState = DT_CROWDAGENT_TARGET_NONE;
  470. ag->active = true;
  471. // Urho3D: added to fix illegal memory access when ncorners is queried before the agent has updated
  472. ag->ncorners = 0;
  473. return idx;
  474. }
  475. /// @par
  476. ///
  477. /// The agent is deactivated and will no longer be processed. Its #dtCrowdAgent object
  478. /// is not removed from the pool. It is marked as inactive so that it is available for reuse.
  479. void dtCrowd::removeAgent(const int idx)
  480. {
  481. if (idx >= 0 && idx < m_maxAgents)
  482. {
  483. m_agents[idx].active = false;
  484. }
  485. }
  486. bool dtCrowd::requestMoveTargetReplan(const int idx, dtPolyRef ref, const float* pos)
  487. {
  488. if (idx < 0 || idx >= m_maxAgents)
  489. return false;
  490. dtCrowdAgent* ag = &m_agents[idx];
  491. // Initialize request.
  492. ag->targetRef = ref;
  493. dtVcopy(ag->targetPos, pos);
  494. ag->targetPathqRef = DT_PATHQ_INVALID;
  495. ag->targetReplan = true;
  496. if (ag->targetRef)
  497. ag->targetState = DT_CROWDAGENT_TARGET_REQUESTING;
  498. else
  499. ag->targetState = DT_CROWDAGENT_TARGET_FAILED;
  500. return true;
  501. }
  502. /// @par
  503. ///
  504. /// This method is used when a new target is set.
  505. ///
  506. /// The position will be constrained to the surface of the navigation mesh.
  507. ///
  508. /// The request will be processed during the next #update().
  509. bool dtCrowd::requestMoveTarget(const int idx, dtPolyRef ref, const float* pos)
  510. {
  511. if (idx < 0 || idx >= m_maxAgents)
  512. return false;
  513. if (!ref)
  514. return false;
  515. dtCrowdAgent* ag = &m_agents[idx];
  516. // Initialize request.
  517. ag->targetRef = ref;
  518. dtVcopy(ag->targetPos, pos);
  519. ag->targetPathqRef = DT_PATHQ_INVALID;
  520. ag->targetReplan = false;
  521. if (ag->targetRef)
  522. ag->targetState = DT_CROWDAGENT_TARGET_REQUESTING;
  523. else
  524. ag->targetState = DT_CROWDAGENT_TARGET_FAILED;
  525. return true;
  526. }
  527. bool dtCrowd::requestMoveVelocity(const int idx, const float* vel)
  528. {
  529. if (idx < 0 || idx >= m_maxAgents)
  530. return false;
  531. dtCrowdAgent* ag = &m_agents[idx];
  532. // Initialize request.
  533. ag->targetRef = 0;
  534. dtVcopy(ag->targetPos, vel);
  535. ag->targetPathqRef = DT_PATHQ_INVALID;
  536. ag->targetReplan = false;
  537. ag->targetState = DT_CROWDAGENT_TARGET_VELOCITY;
  538. return true;
  539. }
  540. bool dtCrowd::resetMoveTarget(const int idx)
  541. {
  542. if (idx < 0 || idx >= m_maxAgents)
  543. return false;
  544. dtCrowdAgent* ag = &m_agents[idx];
  545. // Initialize request.
  546. ag->targetRef = 0;
  547. dtVset(ag->targetPos, 0,0,0);
  548. ag->targetPathqRef = DT_PATHQ_INVALID;
  549. ag->targetReplan = false;
  550. ag->targetState = DT_CROWDAGENT_TARGET_NONE;
  551. return true;
  552. }
  553. int dtCrowd::getActiveAgents(dtCrowdAgent** agents, const int maxAgents)
  554. {
  555. int n = 0;
  556. for (int i = 0; i < m_maxAgents; ++i)
  557. {
  558. if (!m_agents[i].active) continue;
  559. if (n < maxAgents)
  560. agents[n++] = &m_agents[i];
  561. }
  562. return n;
  563. }
  564. void dtCrowd::updateMoveRequest(const float /*dt*/)
  565. {
  566. const int PATH_MAX_AGENTS = 8;
  567. dtCrowdAgent* queue[PATH_MAX_AGENTS];
  568. int nqueue = 0;
  569. // Fire off new requests.
  570. for (int i = 0; i < m_maxAgents; ++i)
  571. {
  572. dtCrowdAgent* ag = &m_agents[i];
  573. if (!ag->active)
  574. continue;
  575. if (ag->state == DT_CROWDAGENT_STATE_INVALID)
  576. continue;
  577. if (ag->targetState == DT_CROWDAGENT_TARGET_NONE || ag->targetState == DT_CROWDAGENT_TARGET_VELOCITY)
  578. continue;
  579. if (ag->targetState == DT_CROWDAGENT_TARGET_REQUESTING)
  580. {
  581. const dtPolyRef* path = ag->corridor.getPath();
  582. const int npath = ag->corridor.getPathCount();
  583. dtAssert(npath);
  584. static const int MAX_RES = 32;
  585. float reqPos[3];
  586. dtPolyRef reqPath[MAX_RES]; // The path to the request location
  587. int reqPathCount = 0;
  588. // Quick search towards the goal.
  589. static const int MAX_ITER = 20;
  590. m_navquery->initSlicedFindPath(path[0], ag->targetRef, ag->npos, ag->targetPos, &m_filters[ag->params.queryFilterType]);
  591. m_navquery->updateSlicedFindPath(MAX_ITER, 0);
  592. dtStatus status = 0;
  593. if (ag->targetReplan) // && npath > 10)
  594. {
  595. // Try to use existing steady path during replan if possible.
  596. status = m_navquery->finalizeSlicedFindPathPartial(path, npath, reqPath, &reqPathCount, MAX_RES);
  597. }
  598. else
  599. {
  600. // Try to move towards target when goal changes.
  601. status = m_navquery->finalizeSlicedFindPath(reqPath, &reqPathCount, MAX_RES);
  602. }
  603. if (!dtStatusFailed(status) && reqPathCount > 0)
  604. {
  605. // In progress or succeed.
  606. if (reqPath[reqPathCount-1] != ag->targetRef)
  607. {
  608. // Partial path, constrain target position inside the last polygon.
  609. status = m_navquery->closestPointOnPoly(reqPath[reqPathCount-1], ag->targetPos, reqPos, 0);
  610. if (dtStatusFailed(status))
  611. reqPathCount = 0;
  612. }
  613. else
  614. {
  615. dtVcopy(reqPos, ag->targetPos);
  616. }
  617. }
  618. else
  619. {
  620. reqPathCount = 0;
  621. }
  622. if (!reqPathCount)
  623. {
  624. // Could not find path, start the request from current location.
  625. dtVcopy(reqPos, ag->npos);
  626. reqPath[0] = path[0];
  627. reqPathCount = 1;
  628. }
  629. ag->corridor.setCorridor(reqPos, reqPath, reqPathCount);
  630. ag->boundary.reset();
  631. ag->partial = false;
  632. if (reqPath[reqPathCount-1] == ag->targetRef)
  633. {
  634. ag->targetState = DT_CROWDAGENT_TARGET_VALID;
  635. ag->targetReplanTime = 0.0;
  636. }
  637. else
  638. {
  639. // The path is longer or potentially unreachable, full plan.
  640. ag->targetState = DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE;
  641. }
  642. }
  643. if (ag->targetState == DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE)
  644. {
  645. nqueue = addToPathQueue(ag, queue, nqueue, PATH_MAX_AGENTS);
  646. }
  647. }
  648. for (int i = 0; i < nqueue; ++i)
  649. {
  650. dtCrowdAgent* ag = queue[i];
  651. ag->targetPathqRef = m_pathq.request(ag->corridor.getLastPoly(), ag->targetRef,
  652. ag->corridor.getTarget(), ag->targetPos, &m_filters[ag->params.queryFilterType]);
  653. if (ag->targetPathqRef != DT_PATHQ_INVALID)
  654. ag->targetState = DT_CROWDAGENT_TARGET_WAITING_FOR_PATH;
  655. }
  656. // Update requests.
  657. m_pathq.update(MAX_ITERS_PER_UPDATE);
  658. dtStatus status;
  659. // Process path results.
  660. for (int i = 0; i < m_maxAgents; ++i)
  661. {
  662. dtCrowdAgent* ag = &m_agents[i];
  663. if (!ag->active)
  664. continue;
  665. if (ag->targetState == DT_CROWDAGENT_TARGET_NONE || ag->targetState == DT_CROWDAGENT_TARGET_VELOCITY)
  666. continue;
  667. if (ag->targetState == DT_CROWDAGENT_TARGET_WAITING_FOR_PATH)
  668. {
  669. // Poll path queue.
  670. status = m_pathq.getRequestStatus(ag->targetPathqRef);
  671. if (dtStatusFailed(status))
  672. {
  673. // Path find failed, retry if the target location is still valid.
  674. ag->targetPathqRef = DT_PATHQ_INVALID;
  675. if (ag->targetRef)
  676. ag->targetState = DT_CROWDAGENT_TARGET_REQUESTING;
  677. else
  678. ag->targetState = DT_CROWDAGENT_TARGET_FAILED;
  679. ag->targetReplanTime = 0.0;
  680. }
  681. else if (dtStatusSucceed(status))
  682. {
  683. const dtPolyRef* path = ag->corridor.getPath();
  684. const int npath = ag->corridor.getPathCount();
  685. dtAssert(npath);
  686. // Apply results.
  687. float targetPos[3];
  688. dtVcopy(targetPos, ag->targetPos);
  689. dtPolyRef* res = m_pathResult;
  690. bool valid = true;
  691. int nres = 0;
  692. status = m_pathq.getPathResult(ag->targetPathqRef, res, &nres, m_maxPathResult);
  693. if (dtStatusFailed(status) || !nres)
  694. valid = false;
  695. if (dtStatusDetail(status, DT_PARTIAL_RESULT))
  696. ag->partial = true;
  697. else
  698. ag->partial = false;
  699. // Merge result and existing path.
  700. // The agent might have moved whilst the request is
  701. // being processed, so the path may have changed.
  702. // We assume that the end of the path is at the same location
  703. // where the request was issued.
  704. // The last ref in the old path should be the same as
  705. // the location where the request was issued..
  706. if (valid && path[npath-1] != res[0])
  707. valid = false;
  708. if (valid)
  709. {
  710. // Put the old path infront of the old path.
  711. if (npath > 1)
  712. {
  713. // Make space for the old path.
  714. if ((npath-1)+nres > m_maxPathResult)
  715. nres = m_maxPathResult - (npath-1);
  716. memmove(res+npath-1, res, sizeof(dtPolyRef)*nres);
  717. // Copy old path in the beginning.
  718. memcpy(res, path, sizeof(dtPolyRef)*(npath-1));
  719. nres += npath-1;
  720. // Remove trackbacks
  721. for (int j = 0; j < nres; ++j)
  722. {
  723. if (j-1 >= 0 && j+1 < nres)
  724. {
  725. if (res[j-1] == res[j+1])
  726. {
  727. memmove(res+(j-1), res+(j+1), sizeof(dtPolyRef)*(nres-(j+1)));
  728. nres -= 2;
  729. j -= 2;
  730. }
  731. }
  732. }
  733. }
  734. // Check for partial path.
  735. if (res[nres-1] != ag->targetRef)
  736. {
  737. // Partial path, constrain target position inside the last polygon.
  738. float nearest[3];
  739. status = m_navquery->closestPointOnPoly(res[nres-1], targetPos, nearest, 0);
  740. if (dtStatusSucceed(status))
  741. dtVcopy(targetPos, nearest);
  742. else
  743. valid = false;
  744. }
  745. }
  746. if (valid)
  747. {
  748. // Set current corridor.
  749. ag->corridor.setCorridor(targetPos, res, nres);
  750. // Force to update boundary.
  751. ag->boundary.reset();
  752. ag->targetState = DT_CROWDAGENT_TARGET_VALID;
  753. }
  754. else
  755. {
  756. // Something went wrong.
  757. ag->targetState = DT_CROWDAGENT_TARGET_FAILED;
  758. }
  759. ag->targetReplanTime = 0.0;
  760. }
  761. }
  762. }
  763. }
  764. void dtCrowd::updateTopologyOptimization(dtCrowdAgent** agents, const int nagents, const float dt)
  765. {
  766. if (!nagents)
  767. return;
  768. const float OPT_TIME_THR = 0.5f; // seconds
  769. const int OPT_MAX_AGENTS = 1;
  770. dtCrowdAgent* queue[OPT_MAX_AGENTS];
  771. int nqueue = 0;
  772. for (int i = 0; i < nagents; ++i)
  773. {
  774. dtCrowdAgent* ag = agents[i];
  775. if (ag->state != DT_CROWDAGENT_STATE_WALKING)
  776. continue;
  777. if (ag->targetState == DT_CROWDAGENT_TARGET_NONE || ag->targetState == DT_CROWDAGENT_TARGET_VELOCITY)
  778. continue;
  779. if ((ag->params.updateFlags & DT_CROWD_OPTIMIZE_TOPO) == 0)
  780. continue;
  781. ag->topologyOptTime += dt;
  782. if (ag->topologyOptTime >= OPT_TIME_THR)
  783. nqueue = addToOptQueue(ag, queue, nqueue, OPT_MAX_AGENTS);
  784. }
  785. for (int i = 0; i < nqueue; ++i)
  786. {
  787. dtCrowdAgent* ag = queue[i];
  788. ag->corridor.optimizePathTopology(m_navquery, &m_filters[ag->params.queryFilterType]);
  789. ag->topologyOptTime = 0;
  790. }
  791. }
  792. void dtCrowd::checkPathValidity(dtCrowdAgent** agents, const int nagents, const float dt)
  793. {
  794. static const int CHECK_LOOKAHEAD = 10;
  795. static const float TARGET_REPLAN_DELAY = 1.0; // seconds
  796. for (int i = 0; i < nagents; ++i)
  797. {
  798. dtCrowdAgent* ag = agents[i];
  799. if (ag->state != DT_CROWDAGENT_STATE_WALKING)
  800. continue;
  801. ag->targetReplanTime += dt;
  802. bool replan = false;
  803. // First check that the current location is valid.
  804. const int idx = getAgentIndex(ag);
  805. float agentPos[3];
  806. dtPolyRef agentRef = ag->corridor.getFirstPoly();
  807. dtVcopy(agentPos, ag->npos);
  808. if (!m_navquery->isValidPolyRef(agentRef, &m_filters[ag->params.queryFilterType]))
  809. {
  810. // Current location is not valid, try to reposition.
  811. // TODO: this can snap agents, how to handle that?
  812. float nearest[3];
  813. dtVcopy(nearest, agentPos);
  814. agentRef = 0;
  815. m_navquery->findNearestPoly(ag->npos, m_ext, &m_filters[ag->params.queryFilterType], &agentRef, nearest);
  816. dtVcopy(agentPos, nearest);
  817. if (!agentRef)
  818. {
  819. // Could not find location in navmesh, set state to invalid.
  820. ag->corridor.reset(0, agentPos);
  821. ag->partial = false;
  822. ag->boundary.reset();
  823. ag->state = DT_CROWDAGENT_STATE_INVALID;
  824. continue;
  825. }
  826. // Make sure the first polygon is valid, but leave other valid
  827. // polygons in the path so that replanner can adjust the path better.
  828. ag->corridor.fixPathStart(agentRef, agentPos);
  829. // ag->corridor.trimInvalidPath(agentRef, agentPos, m_navquery, &m_filter);
  830. ag->boundary.reset();
  831. dtVcopy(ag->npos, agentPos);
  832. replan = true;
  833. }
  834. // If the agent does not have move target or is controlled by velocity, no need to recover the target nor replan.
  835. if (ag->targetState == DT_CROWDAGENT_TARGET_NONE || ag->targetState == DT_CROWDAGENT_TARGET_VELOCITY)
  836. continue;
  837. // Try to recover move request position.
  838. if (ag->targetState != DT_CROWDAGENT_TARGET_NONE && ag->targetState != DT_CROWDAGENT_TARGET_FAILED)
  839. {
  840. if (!m_navquery->isValidPolyRef(ag->targetRef, &m_filters[ag->params.queryFilterType]))
  841. {
  842. // Current target is not valid, try to reposition.
  843. float nearest[3];
  844. dtVcopy(nearest, ag->targetPos);
  845. ag->targetRef = 0;
  846. m_navquery->findNearestPoly(ag->targetPos, m_ext, &m_filters[ag->params.queryFilterType], &ag->targetRef, nearest);
  847. dtVcopy(ag->targetPos, nearest);
  848. replan = true;
  849. }
  850. if (!ag->targetRef)
  851. {
  852. // Failed to reposition target, fail moverequest.
  853. ag->corridor.reset(agentRef, agentPos);
  854. ag->partial = false;
  855. ag->targetState = DT_CROWDAGENT_TARGET_NONE;
  856. }
  857. }
  858. // If nearby corridor is not valid, replan.
  859. if (!ag->corridor.isValid(CHECK_LOOKAHEAD, m_navquery, &m_filters[ag->params.queryFilterType]))
  860. {
  861. // Fix current path.
  862. // ag->corridor.trimInvalidPath(agentRef, agentPos, m_navquery, &m_filter);
  863. // ag->boundary.reset();
  864. replan = true;
  865. }
  866. // If the end of the path is near and it is not the requested location, replan.
  867. if (ag->targetState == DT_CROWDAGENT_TARGET_VALID)
  868. {
  869. if (ag->targetReplanTime > TARGET_REPLAN_DELAY &&
  870. ag->corridor.getPathCount() < CHECK_LOOKAHEAD &&
  871. ag->corridor.getLastPoly() != ag->targetRef)
  872. replan = true;
  873. }
  874. // Try to replan path to goal.
  875. if (replan)
  876. {
  877. if (ag->targetState != DT_CROWDAGENT_TARGET_NONE)
  878. {
  879. requestMoveTargetReplan(idx, ag->targetRef, ag->targetPos);
  880. }
  881. }
  882. }
  883. }
  884. void dtCrowd::update(const float dt, dtCrowdAgentDebugInfo* debug)
  885. {
  886. m_velocitySampleCount = 0;
  887. const int debugIdx = debug ? debug->idx : -1;
  888. dtCrowdAgent** agents = m_activeAgents;
  889. int nagents = getActiveAgents(agents, m_maxAgents);
  890. // Check that all agents still have valid paths.
  891. checkPathValidity(agents, nagents, dt);
  892. // Update async move request and path finder.
  893. updateMoveRequest(dt);
  894. // Optimize path topology.
  895. updateTopologyOptimization(agents, nagents, dt);
  896. // Register agents to proximity grid.
  897. m_grid->clear();
  898. for (int i = 0; i < nagents; ++i)
  899. {
  900. dtCrowdAgent* ag = agents[i];
  901. const float* p = ag->npos;
  902. const float r = ag->params.radius;
  903. m_grid->addItem((unsigned short)i, p[0]-r, p[2]-r, p[0]+r, p[2]+r);
  904. }
  905. // Get nearby navmesh segments and agents to collide with.
  906. for (int i = 0; i < nagents; ++i)
  907. {
  908. dtCrowdAgent* ag = agents[i];
  909. if (ag->state != DT_CROWDAGENT_STATE_WALKING)
  910. continue;
  911. // Update the collision boundary after certain distance has been passed or
  912. // if it has become invalid.
  913. const float updateThr = ag->params.collisionQueryRange*0.25f;
  914. if (dtVdist2DSqr(ag->npos, ag->boundary.getCenter()) > dtSqr(updateThr) ||
  915. !ag->boundary.isValid(m_navquery, &m_filters[ag->params.queryFilterType]))
  916. {
  917. ag->boundary.update(ag->corridor.getFirstPoly(), ag->npos, ag->params.collisionQueryRange,
  918. m_navquery, &m_filters[ag->params.queryFilterType]);
  919. }
  920. // Query neighbour agents
  921. ag->nneis = getNeighbours(ag->npos, ag->params.height, ag->params.collisionQueryRange,
  922. ag, ag->neis, DT_CROWDAGENT_MAX_NEIGHBOURS,
  923. agents, nagents, m_grid);
  924. for (int j = 0; j < ag->nneis; j++)
  925. ag->neis[j].idx = getAgentIndex(agents[ag->neis[j].idx]);
  926. }
  927. // Find next corner to steer to.
  928. for (int i = 0; i < nagents; ++i)
  929. {
  930. dtCrowdAgent* ag = agents[i];
  931. if (ag->state != DT_CROWDAGENT_STATE_WALKING)
  932. continue;
  933. if (ag->targetState == DT_CROWDAGENT_TARGET_NONE || ag->targetState == DT_CROWDAGENT_TARGET_VELOCITY)
  934. continue;
  935. // Find corners for steering
  936. ag->ncorners = ag->corridor.findCorners(ag->cornerVerts, ag->cornerFlags, ag->cornerPolys,
  937. DT_CROWDAGENT_MAX_CORNERS, m_navquery, &m_filters[ag->params.queryFilterType]);
  938. // Check to see if the corner after the next corner is directly visible,
  939. // and short cut to there.
  940. if ((ag->params.updateFlags & DT_CROWD_OPTIMIZE_VIS) && ag->ncorners > 0)
  941. {
  942. const float* target = &ag->cornerVerts[dtMin(1,ag->ncorners-1)*3];
  943. ag->corridor.optimizePathVisibility(target, ag->params.pathOptimizationRange, m_navquery, &m_filters[ag->params.queryFilterType]);
  944. // Copy data for debug purposes.
  945. if (debugIdx == i)
  946. {
  947. dtVcopy(debug->optStart, ag->corridor.getPos());
  948. dtVcopy(debug->optEnd, target);
  949. }
  950. }
  951. else
  952. {
  953. // Copy data for debug purposes.
  954. if (debugIdx == i)
  955. {
  956. dtVset(debug->optStart, 0,0,0);
  957. dtVset(debug->optEnd, 0,0,0);
  958. }
  959. }
  960. }
  961. // Trigger off-mesh connections (depends on corners).
  962. for (int i = 0; i < nagents; ++i)
  963. {
  964. dtCrowdAgent* ag = agents[i];
  965. if (ag->state != DT_CROWDAGENT_STATE_WALKING)
  966. continue;
  967. if (ag->targetState == DT_CROWDAGENT_TARGET_NONE || ag->targetState == DT_CROWDAGENT_TARGET_VELOCITY)
  968. continue;
  969. // Check
  970. const float triggerRadius = ag->params.radius*2.25f;
  971. if (overOffmeshConnection(ag, triggerRadius))
  972. {
  973. // Prepare to off-mesh connection.
  974. const int idx = (int)(ag - m_agents);
  975. dtCrowdAgentAnimation* anim = &m_agentAnims[idx];
  976. // Adjust the path over the off-mesh connection.
  977. dtPolyRef refs[2];
  978. if (ag->corridor.moveOverOffmeshConnection(ag->cornerPolys[ag->ncorners-1], refs,
  979. anim->startPos, anim->endPos, m_navquery))
  980. {
  981. dtVcopy(anim->initPos, ag->npos);
  982. anim->polyRef = refs[1];
  983. anim->active = true;
  984. anim->t = 0.0f;
  985. anim->tmax = (dtVdist2D(anim->startPos, anim->endPos) / ag->params.maxSpeed) * 0.5f;
  986. ag->state = DT_CROWDAGENT_STATE_OFFMESH;
  987. ag->ncorners = 0;
  988. ag->nneis = 0;
  989. continue;
  990. }
  991. else
  992. {
  993. // Path validity check will ensure that bad/blocked connections will be replanned.
  994. }
  995. }
  996. }
  997. // Calculate steering.
  998. for (int i = 0; i < nagents; ++i)
  999. {
  1000. dtCrowdAgent* ag = agents[i];
  1001. if (ag->state != DT_CROWDAGENT_STATE_WALKING)
  1002. continue;
  1003. if (ag->targetState == DT_CROWDAGENT_TARGET_NONE)
  1004. continue;
  1005. float dvel[3] = {0,0,0};
  1006. if (ag->targetState == DT_CROWDAGENT_TARGET_VELOCITY)
  1007. {
  1008. dtVcopy(dvel, ag->targetPos);
  1009. ag->desiredSpeed = dtVlen(ag->targetPos);
  1010. }
  1011. else
  1012. {
  1013. // Calculate steering direction.
  1014. if (ag->params.updateFlags & DT_CROWD_ANTICIPATE_TURNS)
  1015. calcSmoothSteerDirection(ag, dvel);
  1016. else
  1017. calcStraightSteerDirection(ag, dvel);
  1018. // Calculate speed scale, which tells the agent to slowdown at the end of the path.
  1019. const float slowDownRadius = ag->params.radius*2; // TODO: make less hacky.
  1020. const float speedScale = getDistanceToGoal(ag, slowDownRadius) / slowDownRadius;
  1021. ag->desiredSpeed = ag->params.maxSpeed;
  1022. dtVscale(dvel, dvel, ag->desiredSpeed * speedScale);
  1023. }
  1024. // Separation
  1025. if (ag->params.updateFlags & DT_CROWD_SEPARATION)
  1026. {
  1027. const float separationDist = ag->params.collisionQueryRange;
  1028. const float invSeparationDist = 1.0f / separationDist;
  1029. const float separationWeight = ag->params.separationWeight;
  1030. float w = 0;
  1031. float disp[3] = {0,0,0};
  1032. for (int j = 0; j < ag->nneis; ++j)
  1033. {
  1034. const dtCrowdAgent* nei = &m_agents[ag->neis[j].idx];
  1035. float diff[3];
  1036. dtVsub(diff, ag->npos, nei->npos);
  1037. diff[1] = 0;
  1038. const float distSqr = dtVlenSqr(diff);
  1039. if (distSqr < 0.00001f)
  1040. continue;
  1041. if (distSqr > dtSqr(separationDist))
  1042. continue;
  1043. const float dist = dtMathSqrtf(distSqr);
  1044. const float weight = separationWeight * (1.0f - dtSqr(dist*invSeparationDist));
  1045. dtVmad(disp, disp, diff, weight/dist);
  1046. w += 1.0f;
  1047. }
  1048. if (w > 0.0001f)
  1049. {
  1050. // Adjust desired velocity.
  1051. dtVmad(dvel, dvel, disp, 1.0f/w);
  1052. // Clamp desired velocity to desired speed.
  1053. const float speedSqr = dtVlenSqr(dvel);
  1054. const float desiredSqr = dtSqr(ag->desiredSpeed);
  1055. if (speedSqr > desiredSqr)
  1056. dtVscale(dvel, dvel, desiredSqr/speedSqr);
  1057. }
  1058. }
  1059. // Set the desired velocity.
  1060. dtVcopy(ag->dvel, dvel);
  1061. }
  1062. // Velocity planning.
  1063. for (int i = 0; i < nagents; ++i)
  1064. {
  1065. dtCrowdAgent* ag = agents[i];
  1066. if (ag->state != DT_CROWDAGENT_STATE_WALKING)
  1067. continue;
  1068. if (ag->params.updateFlags & DT_CROWD_OBSTACLE_AVOIDANCE)
  1069. {
  1070. m_obstacleQuery->reset();
  1071. // Add neighbours as obstacles.
  1072. for (int j = 0; j < ag->nneis; ++j)
  1073. {
  1074. const dtCrowdAgent* nei = &m_agents[ag->neis[j].idx];
  1075. m_obstacleQuery->addCircle(nei->npos, nei->params.radius, nei->vel, nei->dvel);
  1076. }
  1077. // Append neighbour segments as obstacles.
  1078. for (int j = 0; j < ag->boundary.getSegmentCount(); ++j)
  1079. {
  1080. const float* s = ag->boundary.getSegment(j);
  1081. if (dtTriArea2D(ag->npos, s, s+3) < 0.0f)
  1082. continue;
  1083. m_obstacleQuery->addSegment(s, s+3);
  1084. }
  1085. dtObstacleAvoidanceDebugData* vod = 0;
  1086. if (debugIdx == i)
  1087. vod = debug->vod;
  1088. // Sample new safe velocity.
  1089. bool adaptive = true;
  1090. int ns = 0;
  1091. const dtObstacleAvoidanceParams* params = &m_obstacleQueryParams[ag->params.obstacleAvoidanceType];
  1092. if (adaptive)
  1093. {
  1094. ns = m_obstacleQuery->sampleVelocityAdaptive(ag->npos, ag->params.radius, ag->desiredSpeed,
  1095. ag->vel, ag->dvel, ag->nvel, params, vod);
  1096. }
  1097. else
  1098. {
  1099. ns = m_obstacleQuery->sampleVelocityGrid(ag->npos, ag->params.radius, ag->desiredSpeed,
  1100. ag->vel, ag->dvel, ag->nvel, params, vod);
  1101. }
  1102. m_velocitySampleCount += ns;
  1103. }
  1104. else
  1105. {
  1106. // If not using velocity planning, new velocity is directly the desired velocity.
  1107. dtVcopy(ag->nvel, ag->dvel);
  1108. }
  1109. }
  1110. // Integrate.
  1111. for (int i = 0; i < nagents; ++i)
  1112. {
  1113. dtCrowdAgent* ag = agents[i];
  1114. if (ag->state != DT_CROWDAGENT_STATE_WALKING)
  1115. continue;
  1116. integrate(ag, dt);
  1117. }
  1118. // Handle collisions.
  1119. static const float COLLISION_RESOLVE_FACTOR = 0.7f;
  1120. for (int iter = 0; iter < 4; ++iter)
  1121. {
  1122. for (int i = 0; i < nagents; ++i)
  1123. {
  1124. dtCrowdAgent* ag = agents[i];
  1125. const int idx0 = getAgentIndex(ag);
  1126. if (ag->state != DT_CROWDAGENT_STATE_WALKING)
  1127. continue;
  1128. dtVset(ag->disp, 0,0,0);
  1129. float w = 0;
  1130. for (int j = 0; j < ag->nneis; ++j)
  1131. {
  1132. const dtCrowdAgent* nei = &m_agents[ag->neis[j].idx];
  1133. const int idx1 = getAgentIndex(nei);
  1134. float diff[3];
  1135. dtVsub(diff, ag->npos, nei->npos);
  1136. diff[1] = 0;
  1137. float dist = dtVlenSqr(diff);
  1138. if (dist > dtSqr(ag->params.radius + nei->params.radius))
  1139. continue;
  1140. dist = dtMathSqrtf(dist);
  1141. float pen = (ag->params.radius + nei->params.radius) - dist;
  1142. if (dist < 0.0001f)
  1143. {
  1144. // Agents on top of each other, try to choose diverging separation directions.
  1145. if (idx0 > idx1)
  1146. dtVset(diff, -ag->dvel[2],0,ag->dvel[0]);
  1147. else
  1148. dtVset(diff, ag->dvel[2],0,-ag->dvel[0]);
  1149. pen = 0.01f;
  1150. }
  1151. else
  1152. {
  1153. pen = (1.0f/dist) * (pen*0.5f) * COLLISION_RESOLVE_FACTOR;
  1154. }
  1155. // Urho3D: Avoid tremble when another agent can not move away
  1156. if (ag->params.separationWeight < 0.0001f)
  1157. continue;
  1158. dtVmad(ag->disp, ag->disp, diff, pen);
  1159. w += 1.0f;
  1160. }
  1161. if (w > 0.0001f)
  1162. {
  1163. const float iw = 1.0f / w;
  1164. dtVscale(ag->disp, ag->disp, iw);
  1165. }
  1166. }
  1167. for (int i = 0; i < nagents; ++i)
  1168. {
  1169. dtCrowdAgent* ag = agents[i];
  1170. if (ag->state != DT_CROWDAGENT_STATE_WALKING)
  1171. continue;
  1172. dtVadd(ag->npos, ag->npos, ag->disp);
  1173. }
  1174. }
  1175. for (int i = 0; i < nagents; ++i)
  1176. {
  1177. dtCrowdAgent* ag = agents[i];
  1178. if (ag->state != DT_CROWDAGENT_STATE_WALKING)
  1179. continue;
  1180. // Move along navmesh.
  1181. ag->corridor.movePosition(ag->npos, m_navquery, &m_filters[ag->params.queryFilterType]);
  1182. // Get valid constrained position back.
  1183. dtVcopy(ag->npos, ag->corridor.getPos());
  1184. // If not using path, truncate the corridor to just one poly.
  1185. if (ag->targetState == DT_CROWDAGENT_TARGET_NONE || ag->targetState == DT_CROWDAGENT_TARGET_VELOCITY)
  1186. {
  1187. ag->corridor.reset(ag->corridor.getFirstPoly(), ag->npos);
  1188. ag->partial = false;
  1189. }
  1190. // Urho3D: Add update callback support
  1191. if (m_updateCallback)
  1192. (*m_updateCallback)(ag, dt);
  1193. }
  1194. // Update agents using off-mesh connection.
  1195. for (int i = 0; i < m_maxAgents; ++i)
  1196. {
  1197. dtCrowdAgentAnimation* anim = &m_agentAnims[i];
  1198. if (!anim->active)
  1199. continue;
  1200. dtCrowdAgent* ag = agents[i];
  1201. anim->t += dt;
  1202. if (anim->t > anim->tmax)
  1203. {
  1204. // Reset animation
  1205. anim->active = false;
  1206. // Prepare agent for walking.
  1207. ag->state = DT_CROWDAGENT_STATE_WALKING;
  1208. continue;
  1209. }
  1210. // Update position
  1211. const float ta = anim->tmax*0.15f;
  1212. const float tb = anim->tmax;
  1213. if (anim->t < ta)
  1214. {
  1215. const float u = tween(anim->t, 0.0, ta);
  1216. dtVlerp(ag->npos, anim->initPos, anim->startPos, u);
  1217. }
  1218. else
  1219. {
  1220. const float u = tween(anim->t, ta, tb);
  1221. dtVlerp(ag->npos, anim->startPos, anim->endPos, u);
  1222. }
  1223. // Update velocity.
  1224. dtVset(ag->vel, 0,0,0);
  1225. dtVset(ag->dvel, 0,0,0);
  1226. }
  1227. }