AINavigation.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  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
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell 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
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "AINavigation.h"
  23. #include "AIController.h"
  24. AINavigation::AINavigation(AIController* controller)
  25. {
  26. mControllerRef = controller;
  27. }
  28. NavMesh* AINavigation::findNavMesh() const
  29. {
  30. GameBase* gbo = dynamic_cast<GameBase*>(mControllerRef->getAIInfo()->mObj.getPointer());
  31. // Search for NavMeshes that contain us entirely with the smallest possible
  32. // volume.
  33. NavMesh* mesh = NULL;
  34. SimSet* set = NavMesh::getServerSet();
  35. for (U32 i = 0; i < set->size(); i++)
  36. {
  37. NavMesh* m = static_cast<NavMesh*>(set->at(i));
  38. if (m->getWorldBox().isContained(gbo->getWorldBox()))
  39. {
  40. if (!mesh || m->getWorldBox().getVolume() < mesh->getWorldBox().getVolume())
  41. mesh = m;
  42. }
  43. }
  44. return mesh;
  45. }
  46. void AINavigation::updateNavMesh()
  47. {
  48. GameBase* gbo = dynamic_cast<GameBase*>(mControllerRef->getAIInfo()->mObj.getPointer());
  49. NavMesh* old = mNavMesh;
  50. if (mNavMesh.isNull())
  51. mNavMesh = findNavMesh();
  52. else
  53. {
  54. if (!mNavMesh->getWorldBox().isContained(gbo->getWorldBox()))
  55. mNavMesh = findNavMesh();
  56. }
  57. // See if we need to update our path.
  58. if (mNavMesh != old && !mPathData.path.isNull())
  59. {
  60. setPathDestination(mPathData.path->mTo);
  61. }
  62. }
  63. void AINavigation::moveToNode(S32 node)
  64. {
  65. if (mPathData.path.isNull())
  66. return;
  67. // -1 is shorthand for 'last path node'.
  68. if (node == -1)
  69. node = mPathData.path->size() - 1;
  70. // Consider slowing down on the last path node.
  71. setMoveDestination(mPathData.path->getNode(node), false);
  72. // Check flags for this segment.
  73. if (mPathData.index)
  74. {
  75. U16 flags = mPathData.path->getFlags(node - 1);
  76. // Jump if we must.
  77. if (flags & LedgeFlag)
  78. mJump = Ledge;
  79. else if (flags & JumpFlag)
  80. mJump = Now;
  81. else
  82. // Catch pathing errors.
  83. mJump = None;
  84. }
  85. // Store current index.
  86. mPathData.index = node;
  87. }
  88. void AINavigation::repath()
  89. {
  90. // Ineffectual if we don't have a path, or are using someone else's.
  91. if (mPathData.path.isNull() || !mPathData.owned)
  92. return;
  93. // If we're following, get their position.
  94. mPathData.path->mTo = mControllerRef->getGoal()->getPosition();
  95. // Update from position and replan.
  96. mPathData.path->mFrom = mControllerRef->getAIInfo()->getPosition();
  97. mPathData.path->plan();
  98. // Move to first node (skip start pos).
  99. moveToNode(1);
  100. }
  101. Point3F AINavigation::getPathDestination() const
  102. {
  103. if (!mPathData.path.isNull())
  104. return mPathData.path->mTo;
  105. return Point3F(0, 0, 0);
  106. }
  107. void AINavigation::setMoveDestination(const Point3F& location, bool slowdown)
  108. {
  109. mMoveDestination = location;
  110. mControllerRef->mMovement.mMoveState = AIController::ModeMove;
  111. mControllerRef->mMovement.mMoveSlowdown = slowdown;
  112. mControllerRef->mMovement.mMoveStuckTestCountdown = mControllerRef->mControllerData->mMoveStuckTestDelay;
  113. }
  114. void AINavigation::onReachDestination()
  115. {
  116. #ifdef TORQUE_NAVIGATION_ENABLED
  117. if (!getPath().isNull())
  118. {
  119. if (mPathData.index == getPath()->size() - 1)
  120. {
  121. // Handle looping paths.
  122. if (getPath()->mIsLooping)
  123. moveToNode(0);
  124. // Otherwise end path.
  125. else
  126. {
  127. clearPath();
  128. getCtrl()->throwCallback("onReachDestination");
  129. }
  130. }
  131. else
  132. {
  133. moveToNode(mPathData.index + 1);
  134. // Throw callback every time if we're on a looping path.
  135. //if(mPathData.path->mIsLooping)
  136. //throwCallback("onReachDestination");
  137. }
  138. }
  139. else
  140. #endif
  141. getCtrl()->throwCallback("onReachDestination");
  142. }
  143. bool AINavigation::setPathDestination(const Point3F& pos)
  144. {
  145. if (!mNavMesh)
  146. updateNavMesh();
  147. // If we can't find a mesh, just move regularly.
  148. if (!mNavMesh)
  149. {
  150. //setMoveDestination(pos);
  151. mControllerRef->throwCallback("onPathFailed");
  152. return false;
  153. }
  154. // Create a new path.
  155. NavPath* path = new NavPath();
  156. path->mMesh = mNavMesh;
  157. path->mFrom = mControllerRef->getAIInfo()->getPosition();
  158. path->mTo = pos;
  159. path->mFromSet = path->mToSet = true;
  160. path->mAlwaysRender = true;
  161. path->mLinkTypes = mControllerRef->mControllerData->mLinkTypes;
  162. path->mXray = true;
  163. // Paths plan automatically upon being registered.
  164. if (!path->registerObject())
  165. {
  166. delete path;
  167. return false;
  168. }
  169. if (path->success())
  170. {
  171. // Clear any current path we might have.
  172. clearPath();
  173. mControllerRef->clearCover();
  174. clearFollow();
  175. // Store new path.
  176. mPathData.path = path;
  177. mPathData.owned = true;
  178. // Skip node 0, which we are currently standing on.
  179. moveToNode(1);
  180. mControllerRef->throwCallback("onPathSuccess");
  181. return true;
  182. }
  183. else
  184. {
  185. // Just move normally if we can't path.
  186. //setMoveDestination(pos, true);
  187. //return;
  188. mControllerRef->throwCallback("onPathFailed");
  189. path->deleteObject();
  190. return false;
  191. }
  192. }
  193. void AINavigation::followObject(AIInfo* targ)
  194. {
  195. if (!targ) return;
  196. if (targ->getDist() < mControllerRef->mControllerData->mMoveTolerance)
  197. return;
  198. if (setPathDestination(targ->getPosition()))
  199. {
  200. mControllerRef->clearCover();
  201. mControllerRef->setGoal(targ);
  202. }
  203. }
  204. void AINavigation::followObject(SceneObject* obj, F32 radius)
  205. {
  206. mControllerRef->setGoal(obj, radius);
  207. followObject(mControllerRef->getGoal());
  208. }
  209. void AINavigation::clearFollow()
  210. {
  211. mControllerRef->clearGoal();
  212. }
  213. void AINavigation::followNavPath(NavPath* path)
  214. {
  215. // Get rid of our current path.
  216. clearPath();
  217. mControllerRef->clearCover();
  218. clearFollow();
  219. // Follow new path.
  220. mPathData.path = path;
  221. mPathData.owned = false;
  222. // Start from 0 since we might not already be there.
  223. moveToNode(0);
  224. }
  225. void AINavigation::clearPath()
  226. {
  227. // Only delete if we own the path.
  228. if (!mPathData.path.isNull() && mPathData.owned)
  229. mPathData.path->deleteObject();
  230. // Reset path data.
  231. mPathData = PathData();
  232. }
  233. DefineEngineMethod(AIController, setMoveDestination, void, (Point3F goal, bool slowDown), (true),
  234. "@brief Tells the AI to move to the location provided\n\n"
  235. "@param goal Coordinates in world space representing location to move to.\n"
  236. "@param slowDown A boolean value. If set to true, the bot will slow down "
  237. "when it gets within 5-meters of its move destination. If false, the bot "
  238. "will stop abruptly when it reaches the move destination. By default, this is true.\n\n"
  239. "@note Upon reaching a move destination, the bot will clear its move destination and "
  240. "calls to getMoveDestination will return \"0 0 0\"."
  241. "@see getMoveDestination()\n")
  242. {
  243. object->getNav()->setMoveDestination(goal, slowDown);
  244. }