nav_agent_2d.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /**************************************************************************/
  2. /* nav_agent_2d.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "nav_agent_2d.h"
  31. #include "nav_map_2d.h"
  32. void NavAgent2D::set_avoidance_enabled(bool p_enabled) {
  33. avoidance_enabled = p_enabled;
  34. _update_rvo_agent_properties();
  35. }
  36. void NavAgent2D::_update_rvo_agent_properties() {
  37. rvo_agent.neighborDist_ = neighbor_distance;
  38. rvo_agent.maxNeighbors_ = max_neighbors;
  39. rvo_agent.timeHorizon_ = time_horizon_agents;
  40. rvo_agent.timeHorizonObst_ = time_horizon_obstacles;
  41. rvo_agent.radius_ = radius;
  42. rvo_agent.maxSpeed_ = max_speed;
  43. rvo_agent.position_ = RVO2D::Vector2(position.x, position.y);
  44. // Replacing the internal velocity directly causes major jitter / bugs due to unpredictable velocity jumps, left line here for testing.
  45. //rvo_agent.velocity_ = RVO2D::Vector2(velocity.x, velocity.y);
  46. rvo_agent.prefVelocity_ = RVO2D::Vector2(velocity.x, velocity.y);
  47. rvo_agent.avoidance_layers_ = avoidance_layers;
  48. rvo_agent.avoidance_mask_ = avoidance_mask;
  49. rvo_agent.avoidance_priority_ = avoidance_priority;
  50. if (map != nullptr) {
  51. if (avoidance_enabled) {
  52. map->set_agent_as_controlled(this);
  53. } else {
  54. map->remove_agent_as_controlled(this);
  55. }
  56. }
  57. agent_dirty = true;
  58. request_sync();
  59. }
  60. void NavAgent2D::set_map(NavMap2D *p_map) {
  61. if (map == p_map) {
  62. return;
  63. }
  64. cancel_sync_request();
  65. if (map) {
  66. map->remove_agent(this);
  67. }
  68. map = p_map;
  69. agent_dirty = true;
  70. if (map) {
  71. map->add_agent(this);
  72. if (avoidance_enabled) {
  73. map->set_agent_as_controlled(this);
  74. }
  75. request_sync();
  76. }
  77. }
  78. bool NavAgent2D::is_map_changed() {
  79. if (map) {
  80. bool is_changed = map->get_iteration_id() != last_map_iteration_id;
  81. last_map_iteration_id = map->get_iteration_id();
  82. return is_changed;
  83. } else {
  84. return false;
  85. }
  86. }
  87. void NavAgent2D::set_avoidance_callback(Callable p_callback) {
  88. avoidance_callback = p_callback;
  89. }
  90. bool NavAgent2D::has_avoidance_callback() const {
  91. return avoidance_callback.is_valid();
  92. }
  93. void NavAgent2D::dispatch_avoidance_callback() {
  94. if (!avoidance_callback.is_valid()) {
  95. return;
  96. }
  97. Vector3 new_velocity;
  98. new_velocity = Vector3(rvo_agent.velocity_.x(), 0.0, rvo_agent.velocity_.y());
  99. if (clamp_speed) {
  100. new_velocity = new_velocity.limit_length(max_speed);
  101. }
  102. // Invoke the callback with the new velocity.
  103. avoidance_callback.call(new_velocity);
  104. }
  105. void NavAgent2D::set_neighbor_distance(real_t p_neighbor_distance) {
  106. neighbor_distance = p_neighbor_distance;
  107. rvo_agent.neighborDist_ = neighbor_distance;
  108. agent_dirty = true;
  109. request_sync();
  110. }
  111. void NavAgent2D::set_max_neighbors(int p_max_neighbors) {
  112. max_neighbors = p_max_neighbors;
  113. rvo_agent.maxNeighbors_ = max_neighbors;
  114. agent_dirty = true;
  115. request_sync();
  116. }
  117. void NavAgent2D::set_time_horizon_agents(real_t p_time_horizon) {
  118. time_horizon_agents = p_time_horizon;
  119. rvo_agent.timeHorizon_ = time_horizon_agents;
  120. agent_dirty = true;
  121. request_sync();
  122. }
  123. void NavAgent2D::set_time_horizon_obstacles(real_t p_time_horizon) {
  124. time_horizon_obstacles = p_time_horizon;
  125. rvo_agent.timeHorizonObst_ = time_horizon_obstacles;
  126. agent_dirty = true;
  127. request_sync();
  128. }
  129. void NavAgent2D::set_radius(real_t p_radius) {
  130. radius = p_radius;
  131. rvo_agent.radius_ = radius;
  132. agent_dirty = true;
  133. request_sync();
  134. }
  135. void NavAgent2D::set_max_speed(real_t p_max_speed) {
  136. max_speed = p_max_speed;
  137. if (avoidance_enabled) {
  138. rvo_agent.maxSpeed_ = max_speed;
  139. }
  140. agent_dirty = true;
  141. request_sync();
  142. }
  143. void NavAgent2D::set_position(const Vector2 &p_position) {
  144. position = p_position;
  145. if (avoidance_enabled) {
  146. rvo_agent.position_ = RVO2D::Vector2(p_position.x, p_position.y);
  147. }
  148. agent_dirty = true;
  149. request_sync();
  150. }
  151. void NavAgent2D::set_target_position(const Vector2 &p_target_position) {
  152. target_position = p_target_position;
  153. }
  154. void NavAgent2D::set_velocity(const Vector2 &p_velocity) {
  155. // Sets the "wanted" velocity for an agent as a suggestion
  156. // This velocity is not guaranteed, RVO simulation will only try to fulfill it
  157. velocity = p_velocity;
  158. if (avoidance_enabled) {
  159. rvo_agent.prefVelocity_ = RVO2D::Vector2(velocity.x, velocity.y);
  160. }
  161. agent_dirty = true;
  162. request_sync();
  163. }
  164. void NavAgent2D::set_velocity_forced(const Vector2 &p_velocity) {
  165. // This function replaces the internal rvo simulation velocity
  166. // should only be used after the agent was teleported
  167. // as it destroys consistency in movement in cramped situations
  168. // use velocity instead to update with a safer "suggestion"
  169. velocity_forced = p_velocity;
  170. if (avoidance_enabled) {
  171. rvo_agent.velocity_ = RVO2D::Vector2(p_velocity.x, p_velocity.y);
  172. }
  173. agent_dirty = true;
  174. request_sync();
  175. }
  176. void NavAgent2D::update() {
  177. // Updates this agent with the calculated results from the rvo simulation
  178. if (avoidance_enabled) {
  179. velocity = Vector2(rvo_agent.velocity_.x(), rvo_agent.velocity_.y());
  180. }
  181. }
  182. void NavAgent2D::set_avoidance_mask(uint32_t p_mask) {
  183. avoidance_mask = p_mask;
  184. rvo_agent.avoidance_mask_ = avoidance_mask;
  185. agent_dirty = true;
  186. request_sync();
  187. }
  188. void NavAgent2D::set_avoidance_layers(uint32_t p_layers) {
  189. avoidance_layers = p_layers;
  190. rvo_agent.avoidance_layers_ = avoidance_layers;
  191. agent_dirty = true;
  192. request_sync();
  193. }
  194. void NavAgent2D::set_avoidance_priority(real_t p_priority) {
  195. ERR_FAIL_COND_MSG(p_priority < 0.0, "Avoidance priority must be between 0.0 and 1.0 inclusive.");
  196. ERR_FAIL_COND_MSG(p_priority > 1.0, "Avoidance priority must be between 0.0 and 1.0 inclusive.");
  197. avoidance_priority = p_priority;
  198. rvo_agent.avoidance_priority_ = avoidance_priority;
  199. agent_dirty = true;
  200. request_sync();
  201. }
  202. bool NavAgent2D::is_dirty() const {
  203. return agent_dirty;
  204. }
  205. void NavAgent2D::sync() {
  206. agent_dirty = false;
  207. }
  208. const Dictionary NavAgent2D::get_avoidance_data() const {
  209. // Returns debug data from RVO simulation internals of this agent.
  210. Dictionary _avoidance_data;
  211. _avoidance_data["max_neighbors"] = int(rvo_agent.maxNeighbors_);
  212. _avoidance_data["max_speed"] = float(rvo_agent.maxSpeed_);
  213. _avoidance_data["neighbor_distance"] = float(rvo_agent.neighborDist_);
  214. _avoidance_data["new_velocity"] = Vector2(rvo_agent.newVelocity_.x(), rvo_agent.newVelocity_.y());
  215. _avoidance_data["velocity"] = Vector2(rvo_agent.velocity_.x(), rvo_agent.velocity_.y());
  216. _avoidance_data["position"] = Vector2(rvo_agent.position_.x(), rvo_agent.position_.y());
  217. _avoidance_data["preferred_velocity"] = Vector2(rvo_agent.prefVelocity_.x(), rvo_agent.prefVelocity_.y());
  218. _avoidance_data["radius"] = float(rvo_agent.radius_);
  219. _avoidance_data["time_horizon_agents"] = float(rvo_agent.timeHorizon_);
  220. _avoidance_data["time_horizon_obstacles"] = float(rvo_agent.timeHorizonObst_);
  221. _avoidance_data["avoidance_layers"] = int(rvo_agent.avoidance_layers_);
  222. _avoidance_data["avoidance_mask"] = int(rvo_agent.avoidance_mask_);
  223. _avoidance_data["avoidance_priority"] = float(rvo_agent.avoidance_priority_);
  224. return _avoidance_data;
  225. }
  226. void NavAgent2D::set_paused(bool p_paused) {
  227. if (paused == p_paused) {
  228. return;
  229. }
  230. paused = p_paused;
  231. if (map) {
  232. if (paused) {
  233. map->remove_agent_as_controlled(this);
  234. } else {
  235. map->set_agent_as_controlled(this);
  236. }
  237. }
  238. }
  239. bool NavAgent2D::get_paused() const {
  240. return paused;
  241. }
  242. void NavAgent2D::request_sync() {
  243. if (map && !sync_dirty_request_list_element.in_list()) {
  244. map->add_agent_sync_dirty_request(&sync_dirty_request_list_element);
  245. }
  246. }
  247. void NavAgent2D::cancel_sync_request() {
  248. if (map && sync_dirty_request_list_element.in_list()) {
  249. map->remove_agent_sync_dirty_request(&sync_dirty_request_list_element);
  250. }
  251. }
  252. NavAgent2D::NavAgent2D() :
  253. sync_dirty_request_list_element(this) {
  254. }
  255. NavAgent2D::~NavAgent2D() {
  256. cancel_sync_request();
  257. }