CrowdManager.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. //
  2. // Copyright (c) 2008-2016 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "../Precompiled.h"
  23. #include "../Core/Context.h"
  24. #include "../Core/Profiler.h"
  25. #include "../Graphics/DebugRenderer.h"
  26. #include "../IO/Log.h"
  27. #include "../Navigation/CrowdAgent.h"
  28. #include "../Navigation/CrowdManager.h"
  29. #include "../Navigation/DynamicNavigationMesh.h"
  30. #include "../Navigation/NavigationEvents.h"
  31. #include "../Scene/Node.h"
  32. #include "../Scene/Scene.h"
  33. #include "../Scene/SceneEvents.h"
  34. // ATOMIC BEGIN
  35. #include <DetourCrowd/include/DetourCrowd.h>
  36. // ATOMIC END
  37. #include "../DebugNew.h"
  38. namespace Atomic
  39. {
  40. extern const char* NAVIGATION_CATEGORY;
  41. static const unsigned DEFAULT_MAX_AGENTS = 512;
  42. static const float DEFAULT_MAX_AGENT_RADIUS = 0.f;
  43. void CrowdAgentUpdateCallback(dtCrowdAgent* ag, float dt)
  44. {
  45. static_cast<CrowdAgent*>(ag->params.userData)->OnCrowdUpdate(ag, dt);
  46. }
  47. CrowdManager::CrowdManager(Context* context) :
  48. Component(context),
  49. crowd_(0),
  50. navigationMesh_(0),
  51. navigationMeshId_(0),
  52. maxAgents_(DEFAULT_MAX_AGENTS),
  53. maxAgentRadius_(DEFAULT_MAX_AGENT_RADIUS),
  54. numQueryFilterTypes_(0),
  55. numObstacleAvoidanceTypes_(0)
  56. {
  57. // The actual buffer is allocated inside dtCrowd, we only track the number of "slots" being configured explicitly
  58. numAreas_.Reserve(DT_CROWD_MAX_QUERY_FILTER_TYPE);
  59. for (unsigned i = 0; i < DT_CROWD_MAX_QUERY_FILTER_TYPE; ++i)
  60. numAreas_.Push(0);
  61. }
  62. CrowdManager::~CrowdManager()
  63. {
  64. dtFreeCrowd(crowd_);
  65. crowd_ = 0;
  66. }
  67. void CrowdManager::RegisterObject(Context* context)
  68. {
  69. context->RegisterFactory<CrowdManager>(NAVIGATION_CATEGORY);
  70. ATOMIC_ATTRIBUTE("Max Agents", unsigned, maxAgents_, DEFAULT_MAX_AGENTS, AM_DEFAULT);
  71. ATOMIC_ATTRIBUTE("Max Agent Radius", float, maxAgentRadius_, DEFAULT_MAX_AGENT_RADIUS, AM_DEFAULT);
  72. ATOMIC_ATTRIBUTE("Navigation Mesh", unsigned, navigationMeshId_, 0, AM_DEFAULT | AM_COMPONENTID);
  73. ATOMIC_MIXED_ACCESSOR_ATTRIBUTE("Filter Types", GetQueryFilterTypesAttr, SetQueryFilterTypesAttr, VariantVector,
  74. Variant::emptyVariantVector, AM_DEFAULT);
  75. ATOMIC_MIXED_ACCESSOR_ATTRIBUTE("Obstacle Avoidance Types", GetObstacleAvoidanceTypesAttr, SetObstacleAvoidanceTypesAttr,
  76. VariantVector, Variant::emptyVariantVector, AM_DEFAULT);
  77. }
  78. void CrowdManager::ApplyAttributes()
  79. {
  80. // Values from Editor, saved-file, or network must be checked before applying
  81. maxAgents_ = Max(1U, maxAgents_);
  82. maxAgentRadius_ = Max(0.f, maxAgentRadius_);
  83. bool navMeshChange = false;
  84. Scene* scene = GetScene();
  85. if (scene && navigationMeshId_)
  86. {
  87. NavigationMesh* navMesh = dynamic_cast<NavigationMesh*>(scene->GetComponent(navigationMeshId_));
  88. if (navMesh)
  89. {
  90. navMeshChange = navMesh != navigationMesh_;
  91. navigationMesh_ = navMesh;
  92. }
  93. }
  94. // In case of receiving an invalid component id, revert it back to the existing navmesh component id (if any)
  95. navigationMeshId_ = navigationMesh_ ? navigationMesh_->GetID() : 0;
  96. // If the Detour crowd initialization parameters have changed then recreate it
  97. if (crowd_ && (navMeshChange || crowd_->getAgentCount() != maxAgents_ || crowd_->getMaxAgentRadius() != maxAgentRadius_))
  98. CreateCrowd();
  99. }
  100. void CrowdManager::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
  101. {
  102. if (debug && crowd_)
  103. {
  104. // Current position-to-target line
  105. for (int i = 0; i < crowd_->getAgentCount(); i++)
  106. {
  107. const dtCrowdAgent* ag = crowd_->getAgent(i);
  108. if (!ag->active)
  109. continue;
  110. // Draw CrowdAgent shape (from its radius & height)
  111. CrowdAgent* crowdAgent = static_cast<CrowdAgent*>(ag->params.userData);
  112. crowdAgent->DrawDebugGeometry(debug, depthTest);
  113. // Draw move target if any
  114. if (crowdAgent->GetTargetState() == CA_TARGET_NONE)
  115. continue;
  116. Color color(0.6f, 0.2f, 0.2f, 1.0f);
  117. // Draw line to target
  118. Vector3 pos1(ag->npos[0], ag->npos[1], ag->npos[2]);
  119. Vector3 pos2;
  120. for (int i = 0; i < ag->ncorners; ++i)
  121. {
  122. pos2.x_ = ag->cornerVerts[i * 3];
  123. pos2.y_ = ag->cornerVerts[i * 3 + 1];
  124. pos2.z_ = ag->cornerVerts[i * 3 + 2];
  125. debug->AddLine(pos1, pos2, color, depthTest);
  126. pos1 = pos2;
  127. }
  128. pos2.x_ = ag->targetPos[0];
  129. pos2.y_ = ag->targetPos[1];
  130. pos2.z_ = ag->targetPos[2];
  131. debug->AddLine(pos1, pos2, color, depthTest);
  132. // Draw target circle
  133. debug->AddSphere(Sphere(pos2, 0.5f), color, depthTest);
  134. }
  135. }
  136. }
  137. void CrowdManager::DrawDebugGeometry(bool depthTest)
  138. {
  139. Scene* scene = GetScene();
  140. if (scene)
  141. {
  142. DebugRenderer* debug = scene->GetComponent<DebugRenderer>();
  143. if (debug)
  144. DrawDebugGeometry(debug, depthTest);
  145. }
  146. }
  147. void CrowdManager::SetCrowdTarget(const Vector3& position, Node* node)
  148. {
  149. if (!crowd_)
  150. return;
  151. PODVector<CrowdAgent*> agents = GetAgents(node, false); // Get all crowd agent components
  152. Vector3 moveTarget(position);
  153. for (unsigned i = 0; i < agents.Size(); ++i)
  154. {
  155. // Give application a chance to determine the desired crowd formation when they reach the target position
  156. CrowdAgent* agent = agents[i];
  157. using namespace CrowdAgentFormation;
  158. VariantMap& map = GetEventDataMap();
  159. map[P_NODE] = agent->GetNode();
  160. map[P_CROWD_AGENT] = agent;
  161. map[P_INDEX] = i;
  162. map[P_SIZE] = agents.Size();
  163. map[P_POSITION] = moveTarget; // Expect the event handler will modify this position accordingly
  164. SendEvent(E_CROWD_AGENT_FORMATION, map);
  165. moveTarget = map[P_POSITION].GetVector3();
  166. agent->SetTargetPosition(moveTarget);
  167. }
  168. }
  169. void CrowdManager::SetCrowdVelocity(const Vector3& velocity, Node* node)
  170. {
  171. if (!crowd_)
  172. return;
  173. PODVector<CrowdAgent*> agents = GetAgents(node, true); // Get only crowd agent components already in the crowd
  174. for (unsigned i = 0; i < agents.Size(); ++i)
  175. agents[i]->SetTargetVelocity(velocity);
  176. }
  177. void CrowdManager::ResetCrowdTarget(Node* node)
  178. {
  179. if (!crowd_)
  180. return;
  181. PODVector<CrowdAgent*> agents = GetAgents(node, true);
  182. for (unsigned i = 0; i < agents.Size(); ++i)
  183. agents[i]->ResetTarget();
  184. }
  185. void CrowdManager::SetMaxAgents(unsigned maxAgents)
  186. {
  187. if (maxAgents != maxAgents_ && maxAgents > 0)
  188. {
  189. maxAgents_ = maxAgents;
  190. CreateCrowd();
  191. MarkNetworkUpdate();
  192. }
  193. }
  194. void CrowdManager::SetMaxAgentRadius(float maxAgentRadius)
  195. {
  196. if (maxAgentRadius != maxAgentRadius_ && maxAgentRadius > 0.f)
  197. {
  198. maxAgentRadius_ = maxAgentRadius;
  199. CreateCrowd();
  200. MarkNetworkUpdate();
  201. }
  202. }
  203. void CrowdManager::SetNavigationMesh(NavigationMesh* navMesh)
  204. {
  205. if (navMesh != navigationMesh_) // It is possible to reset navmesh pointer back to 0
  206. {
  207. navigationMesh_ = navMesh;
  208. navigationMeshId_ = navMesh ? navMesh->GetID() : 0;
  209. CreateCrowd();
  210. MarkNetworkUpdate();
  211. }
  212. }
  213. void CrowdManager::SetQueryFilterTypesAttr(const VariantVector& value)
  214. {
  215. if (!crowd_)
  216. return;
  217. unsigned index = 0;
  218. unsigned queryFilterType = 0;
  219. numQueryFilterTypes_ = index < value.Size() ? Min(value[index++].GetUInt(), (unsigned)DT_CROWD_MAX_QUERY_FILTER_TYPE) : 0;
  220. while (queryFilterType < numQueryFilterTypes_)
  221. {
  222. if (index + 3 <= value.Size())
  223. {
  224. dtQueryFilter* filter = crowd_->getEditableFilter(queryFilterType);
  225. assert(filter);
  226. filter->setIncludeFlags((unsigned short)value[index++].GetUInt());
  227. filter->setExcludeFlags((unsigned short)value[index++].GetUInt());
  228. unsigned prevNumAreas = numAreas_[queryFilterType];
  229. numAreas_[queryFilterType] = Min(value[index++].GetUInt(), (unsigned)DT_MAX_AREAS);
  230. // Must loop thru based on previous number of areas, the new area cost (if any) can only be set in the next attribute get/set iteration
  231. if (index + prevNumAreas <= value.Size())
  232. {
  233. for (unsigned i = 0; i < prevNumAreas; ++i)
  234. filter->setAreaCost(i, value[index++].GetFloat());
  235. }
  236. }
  237. ++queryFilterType;
  238. }
  239. }
  240. void CrowdManager::SetIncludeFlags(unsigned queryFilterType, unsigned short flags)
  241. {
  242. dtQueryFilter* filter = const_cast<dtQueryFilter*>(GetDetourQueryFilter(queryFilterType));
  243. if (filter)
  244. {
  245. filter->setIncludeFlags(flags);
  246. if (numQueryFilterTypes_ < queryFilterType + 1)
  247. numQueryFilterTypes_ = queryFilterType + 1;
  248. MarkNetworkUpdate();
  249. }
  250. }
  251. void CrowdManager::SetExcludeFlags(unsigned queryFilterType, unsigned short flags)
  252. {
  253. dtQueryFilter* filter = const_cast<dtQueryFilter*>(GetDetourQueryFilter(queryFilterType));
  254. if (filter)
  255. {
  256. filter->setExcludeFlags(flags);
  257. if (numQueryFilterTypes_ < queryFilterType + 1)
  258. numQueryFilterTypes_ = queryFilterType + 1;
  259. MarkNetworkUpdate();
  260. }
  261. }
  262. void CrowdManager::SetAreaCost(unsigned queryFilterType, unsigned areaID, float cost)
  263. {
  264. dtQueryFilter* filter = const_cast<dtQueryFilter*>(GetDetourQueryFilter(queryFilterType));
  265. if (filter && areaID < DT_MAX_AREAS)
  266. {
  267. filter->setAreaCost((int)areaID, cost);
  268. if (numQueryFilterTypes_ < queryFilterType + 1)
  269. numQueryFilterTypes_ = queryFilterType + 1;
  270. if (numAreas_[queryFilterType] < areaID + 1)
  271. numAreas_[queryFilterType] = areaID + 1;
  272. MarkNetworkUpdate();
  273. }
  274. }
  275. void CrowdManager::SetObstacleAvoidanceTypesAttr(const VariantVector& value)
  276. {
  277. if (!crowd_)
  278. return;
  279. unsigned index = 0;
  280. unsigned obstacleAvoidanceType = 0;
  281. numObstacleAvoidanceTypes_ = index < value.Size() ? Min(value[index++].GetUInt(), (unsigned)DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS) : 0;
  282. while (obstacleAvoidanceType < numObstacleAvoidanceTypes_)
  283. {
  284. if (index + 10 <= value.Size())
  285. {
  286. dtObstacleAvoidanceParams params;
  287. params.velBias = value[index++].GetFloat();
  288. params.weightDesVel = value[index++].GetFloat();
  289. params.weightCurVel = value[index++].GetFloat();
  290. params.weightSide = value[index++].GetFloat();
  291. params.weightToi = value[index++].GetFloat();
  292. params.horizTime = value[index++].GetFloat();
  293. params.gridSize = (unsigned char)value[index++].GetUInt();
  294. params.adaptiveDivs = (unsigned char)value[index++].GetUInt();
  295. params.adaptiveRings = (unsigned char)value[index++].GetUInt();
  296. params.adaptiveDepth = (unsigned char)value[index++].GetUInt();
  297. crowd_->setObstacleAvoidanceParams(obstacleAvoidanceType, &params);
  298. }
  299. ++obstacleAvoidanceType;
  300. }
  301. }
  302. void CrowdManager::SetObstacleAvoidanceParams(unsigned obstacleAvoidanceType, const CrowdObstacleAvoidanceParams& params)
  303. {
  304. if (crowd_ && obstacleAvoidanceType < DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS)
  305. {
  306. crowd_->setObstacleAvoidanceParams(obstacleAvoidanceType, reinterpret_cast<const dtObstacleAvoidanceParams*>(&params));
  307. if (numObstacleAvoidanceTypes_ < obstacleAvoidanceType + 1)
  308. numObstacleAvoidanceTypes_ = obstacleAvoidanceType + 1;
  309. MarkNetworkUpdate();
  310. }
  311. }
  312. Vector3 CrowdManager::FindNearestPoint(const Vector3& point, int queryFilterType, dtPolyRef* nearestRef)
  313. {
  314. if (nearestRef)
  315. *nearestRef = 0;
  316. return crowd_ && navigationMesh_ ?
  317. navigationMesh_->FindNearestPoint(point, Vector3(crowd_->getQueryExtents()), crowd_->getFilter(queryFilterType), nearestRef) : point;
  318. }
  319. Vector3 CrowdManager::MoveAlongSurface(const Vector3& start, const Vector3& end, int queryFilterType, int maxVisited)
  320. {
  321. return crowd_ && navigationMesh_ ?
  322. navigationMesh_->MoveAlongSurface(start, end, Vector3(crowd_->getQueryExtents()), maxVisited, crowd_->getFilter(queryFilterType)) :
  323. end;
  324. }
  325. void CrowdManager::FindPath(PODVector<Vector3>& dest, const Vector3& start, const Vector3& end, int queryFilterType)
  326. {
  327. if (crowd_ && navigationMesh_)
  328. navigationMesh_->FindPath(dest, start, end, Vector3(crowd_->getQueryExtents()), crowd_->getFilter(queryFilterType));
  329. }
  330. Vector3 CrowdManager::GetRandomPoint(int queryFilterType, dtPolyRef* randomRef)
  331. {
  332. if (randomRef)
  333. *randomRef = 0;
  334. return crowd_ && navigationMesh_ ? navigationMesh_->GetRandomPoint(crowd_->getFilter(queryFilterType), randomRef) :
  335. Vector3::ZERO;
  336. }
  337. Vector3 CrowdManager::GetRandomPointInCircle(const Vector3& center, float radius, int queryFilterType, dtPolyRef* randomRef)
  338. {
  339. if (randomRef)
  340. *randomRef = 0;
  341. return crowd_ && navigationMesh_ ?
  342. navigationMesh_->GetRandomPointInCircle(center, radius, Vector3(crowd_->getQueryExtents()),
  343. crowd_->getFilter(queryFilterType), randomRef) : center;
  344. }
  345. float CrowdManager::GetDistanceToWall(const Vector3& point, float radius, int queryFilterType, Vector3* hitPos, Vector3* hitNormal)
  346. {
  347. if (hitPos)
  348. *hitPos = Vector3::ZERO;
  349. if (hitNormal)
  350. *hitNormal = Vector3::DOWN;
  351. return crowd_ && navigationMesh_ ?
  352. navigationMesh_->GetDistanceToWall(point, radius, Vector3(crowd_->getQueryExtents()), crowd_->getFilter(queryFilterType),
  353. hitPos, hitNormal) : radius;
  354. }
  355. Vector3 CrowdManager::Raycast(const Vector3& start, const Vector3& end, int queryFilterType, Vector3* hitNormal)
  356. {
  357. if (hitNormal)
  358. *hitNormal = Vector3::DOWN;
  359. return crowd_ && navigationMesh_ ?
  360. navigationMesh_->Raycast(start, end, Vector3(crowd_->getQueryExtents()), crowd_->getFilter(queryFilterType), hitNormal)
  361. : end;
  362. }
  363. unsigned CrowdManager::GetNumAreas(unsigned queryFilterType) const
  364. {
  365. return queryFilterType < numQueryFilterTypes_ ? numAreas_[queryFilterType] : 0;
  366. }
  367. VariantVector CrowdManager::GetQueryFilterTypesAttr() const
  368. {
  369. VariantVector ret;
  370. if (crowd_)
  371. {
  372. unsigned totalNumAreas = 0;
  373. for (unsigned i = 0; i < numQueryFilterTypes_; ++i)
  374. totalNumAreas += numAreas_[i];
  375. ret.Reserve(numQueryFilterTypes_ * 3 + totalNumAreas + 1);
  376. ret.Push(numQueryFilterTypes_);
  377. for (unsigned i = 0; i < numQueryFilterTypes_; ++i)
  378. {
  379. const dtQueryFilter* filter = crowd_->getFilter(i);
  380. assert(filter);
  381. ret.Push(filter->getIncludeFlags());
  382. ret.Push(filter->getExcludeFlags());
  383. ret.Push(numAreas_[i]);
  384. for (unsigned j = 0; j < numAreas_[i]; ++j)
  385. ret.Push(filter->getAreaCost(j));
  386. }
  387. }
  388. else
  389. ret.Push(0);
  390. return ret;
  391. }
  392. unsigned short CrowdManager::GetIncludeFlags(unsigned queryFilterType) const
  393. {
  394. if (queryFilterType >= numQueryFilterTypes_)
  395. ATOMIC_LOGWARNINGF("Query filter type %d is not configured yet, returning the default include flags initialized by dtCrowd",
  396. queryFilterType);
  397. const dtQueryFilter* filter = GetDetourQueryFilter(queryFilterType);
  398. return (unsigned short)(filter ? filter->getIncludeFlags() : 0xffff);
  399. }
  400. unsigned short CrowdManager::GetExcludeFlags(unsigned queryFilterType) const
  401. {
  402. if (queryFilterType >= numQueryFilterTypes_)
  403. ATOMIC_LOGWARNINGF("Query filter type %d is not configured yet, returning the default exclude flags initialized by dtCrowd",
  404. queryFilterType);
  405. const dtQueryFilter* filter = GetDetourQueryFilter(queryFilterType);
  406. return (unsigned short)(filter ? filter->getExcludeFlags() : 0);
  407. }
  408. float CrowdManager::GetAreaCost(unsigned queryFilterType, unsigned areaID) const
  409. {
  410. if (queryFilterType >= numQueryFilterTypes_ || areaID >= numAreas_[queryFilterType])
  411. ATOMIC_LOGWARNINGF(
  412. "Query filter type %d and/or area id %d are not configured yet, returning the default area cost initialized by dtCrowd",
  413. queryFilterType, areaID);
  414. const dtQueryFilter* filter = GetDetourQueryFilter(queryFilterType);
  415. return filter ? filter->getAreaCost((int)areaID) : 1.f;
  416. }
  417. VariantVector CrowdManager::GetObstacleAvoidanceTypesAttr() const
  418. {
  419. VariantVector ret;
  420. if (crowd_)
  421. {
  422. ret.Reserve(numObstacleAvoidanceTypes_ * 10 + 1);
  423. ret.Push(numObstacleAvoidanceTypes_);
  424. for (unsigned i = 0; i < numObstacleAvoidanceTypes_; ++i)
  425. {
  426. const dtObstacleAvoidanceParams* params = crowd_->getObstacleAvoidanceParams(i);
  427. assert(params);
  428. ret.Push(params->velBias);
  429. ret.Push(params->weightDesVel);
  430. ret.Push(params->weightCurVel);
  431. ret.Push(params->weightSide);
  432. ret.Push(params->weightToi);
  433. ret.Push(params->horizTime);
  434. ret.Push(params->gridSize);
  435. ret.Push(params->adaptiveDivs);
  436. ret.Push(params->adaptiveRings);
  437. ret.Push(params->adaptiveDepth);
  438. }
  439. }
  440. else
  441. ret.Push(0);
  442. return ret;
  443. }
  444. const CrowdObstacleAvoidanceParams& CrowdManager::GetObstacleAvoidanceParams(unsigned obstacleAvoidanceType) const
  445. {
  446. static const CrowdObstacleAvoidanceParams EMPTY_PARAMS = CrowdObstacleAvoidanceParams();
  447. const dtObstacleAvoidanceParams* params = crowd_ ? crowd_->getObstacleAvoidanceParams(obstacleAvoidanceType) : 0;
  448. return params ? *reinterpret_cast<const CrowdObstacleAvoidanceParams*>(params) : EMPTY_PARAMS;
  449. }
  450. PODVector<CrowdAgent*> CrowdManager::GetAgents(Node* node, bool inCrowdFilter) const
  451. {
  452. if (!node)
  453. node = GetScene();
  454. PODVector<CrowdAgent*> agents;
  455. node->GetComponents<CrowdAgent>(agents, true);
  456. if (inCrowdFilter)
  457. {
  458. PODVector<CrowdAgent*>::Iterator i = agents.Begin();
  459. while (i != agents.End())
  460. {
  461. if ((*i)->IsInCrowd())
  462. ++i;
  463. else
  464. i = agents.Erase(i);
  465. }
  466. }
  467. return agents;
  468. }
  469. bool CrowdManager::CreateCrowd()
  470. {
  471. if (!navigationMesh_ || !navigationMesh_->InitializeQuery())
  472. return false;
  473. // Preserve the existing crowd configuration before recreating it
  474. VariantVector queryFilterTypeConfiguration, obstacleAvoidanceTypeConfiguration;
  475. bool recreate = crowd_ != 0;
  476. if (recreate)
  477. {
  478. queryFilterTypeConfiguration = GetQueryFilterTypesAttr();
  479. obstacleAvoidanceTypeConfiguration = GetObstacleAvoidanceTypesAttr();
  480. dtFreeCrowd(crowd_);
  481. }
  482. crowd_ = dtAllocCrowd();
  483. // Initialize the crowd
  484. if (maxAgentRadius_ == 0.f)
  485. maxAgentRadius_ = navigationMesh_->GetAgentRadius();
  486. if (!crowd_->init(maxAgents_, maxAgentRadius_, navigationMesh_->navMesh_, CrowdAgentUpdateCallback))
  487. {
  488. ATOMIC_LOGERROR("Could not initialize DetourCrowd");
  489. return false;
  490. }
  491. if (recreate)
  492. {
  493. // Reconfigure the newly initialized crowd
  494. SetQueryFilterTypesAttr(queryFilterTypeConfiguration);
  495. SetObstacleAvoidanceTypesAttr(obstacleAvoidanceTypeConfiguration);
  496. // Re-add the existing crowd agents
  497. PODVector<CrowdAgent*> agents = GetAgents();
  498. for (unsigned i = 0; i < agents.Size(); ++i)
  499. {
  500. // Keep adding until the crowd cannot take it anymore
  501. if (agents[i]->AddAgentToCrowd(true) == -1)
  502. {
  503. ATOMIC_LOGWARNINGF("CrowdManager: %d crowd agents orphaned", agents.Size() - i);
  504. break;
  505. }
  506. }
  507. }
  508. return true;
  509. }
  510. int CrowdManager::AddAgent(CrowdAgent* agent, const Vector3& pos)
  511. {
  512. if (!crowd_ || !navigationMesh_ || !agent)
  513. return -1;
  514. dtCrowdAgentParams params;
  515. params.userData = agent;
  516. if (agent->radius_ == 0.f)
  517. agent->radius_ = navigationMesh_->GetAgentRadius();
  518. if (agent->height_ == 0.f)
  519. agent->height_ = navigationMesh_->GetAgentHeight();
  520. // dtCrowd::addAgent() requires the query filter type to find the nearest position on navmesh as the initial agent's position
  521. params.queryFilterType = (unsigned char)agent->GetQueryFilterType();
  522. return crowd_->addAgent(pos.Data(), &params);
  523. }
  524. void CrowdManager::RemoveAgent(CrowdAgent* agent)
  525. {
  526. if (!crowd_ || !agent)
  527. return;
  528. dtCrowdAgent* agt = crowd_->getEditableAgent(agent->GetAgentCrowdId());
  529. if (agt)
  530. agt->params.userData = 0;
  531. crowd_->removeAgent(agent->GetAgentCrowdId());
  532. }
  533. void CrowdManager::OnSceneSet(Scene* scene)
  534. {
  535. // Subscribe to the scene subsystem update, which will trigger the crowd update step, and grab a reference
  536. // to the scene's NavigationMesh
  537. if (scene)
  538. {
  539. if (scene != node_)
  540. {
  541. ATOMIC_LOGERROR("CrowdManager is a scene component and should only be attached to the scene node");
  542. return;
  543. }
  544. SubscribeToEvent(scene, E_SCENESUBSYSTEMUPDATE, ATOMIC_HANDLER(CrowdManager, HandleSceneSubsystemUpdate));
  545. // Attempt to auto discover a NavigationMesh component (or its derivative) under the scene node
  546. NavigationMesh* navMesh = scene->GetDerivedComponent<NavigationMesh>(true);
  547. if (navMesh)
  548. {
  549. navigationMesh_ = navMesh;
  550. navigationMeshId_ = navMesh->GetID();
  551. CreateCrowd();
  552. SubscribeToEvent(navMesh->GetNode(), E_NAVIGATION_MESH_REBUILT, ATOMIC_HANDLER(CrowdManager, HandleNavMeshChanged));
  553. SubscribeToEvent(navMesh->GetNode(), E_COMPONENTREMOVED, ATOMIC_HANDLER(CrowdManager, HandleNavMeshChanged));
  554. }
  555. }
  556. else
  557. {
  558. UnsubscribeFromEvent(E_SCENESUBSYSTEMUPDATE);
  559. UnsubscribeFromEvent(E_NAVIGATION_MESH_REBUILT);
  560. UnsubscribeFromEvent(E_COMPONENTREMOVED);
  561. navigationMesh_ = 0;
  562. }
  563. }
  564. void CrowdManager::Update(float delta)
  565. {
  566. assert(crowd_ && navigationMesh_);
  567. ATOMIC_PROFILE(UpdateCrowd);
  568. crowd_->update(delta, 0);
  569. }
  570. const dtCrowdAgent* CrowdManager::GetDetourCrowdAgent(int agent) const
  571. {
  572. return crowd_ ? crowd_->getAgent(agent) : 0;
  573. }
  574. const dtQueryFilter* CrowdManager::GetDetourQueryFilter(unsigned queryFilterType) const
  575. {
  576. return crowd_ ? crowd_->getFilter(queryFilterType) : 0;
  577. }
  578. void CrowdManager::HandleSceneSubsystemUpdate(StringHash eventType, VariantMap& eventData)
  579. {
  580. // Perform update tick as long as the crowd is initialized and the associated navmesh has not been removed
  581. if (crowd_ && navigationMesh_)
  582. {
  583. using namespace SceneSubsystemUpdate;
  584. if (IsEnabledEffective())
  585. Update(eventData[P_TIMESTEP].GetFloat());
  586. }
  587. }
  588. void CrowdManager::HandleNavMeshChanged(StringHash eventType, VariantMap& eventData)
  589. {
  590. NavigationMesh* navMesh;
  591. if (eventType == E_NAVIGATION_MESH_REBUILT)
  592. {
  593. // The mesh being rebuilt may not have existed before
  594. navMesh = static_cast<NavigationMesh*>(eventData[NavigationMeshRebuilt::P_MESH].GetPtr());
  595. }
  596. else
  597. {
  598. // eventType == E_COMPONENTREMOVED
  599. navMesh = static_cast<NavigationMesh*>(eventData[ComponentRemoved::P_COMPONENT].GetPtr());
  600. // Only interested in navmesh component being used to initialized the crowd
  601. if (navMesh != navigationMesh_)
  602. return;
  603. // Since this is a component removed event, reset our own navmesh pointer
  604. navMesh = 0;
  605. }
  606. SetNavigationMesh(navMesh);
  607. }
  608. }