Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/navigation_2d/nav_agent_2d.cpp
10277 views
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
31
#include "nav_agent_2d.h"
32
33
#include "nav_map_2d.h"
34
35
void NavAgent2D::set_avoidance_enabled(bool p_enabled) {
36
avoidance_enabled = p_enabled;
37
_update_rvo_agent_properties();
38
}
39
40
void NavAgent2D::_update_rvo_agent_properties() {
41
rvo_agent.neighborDist_ = neighbor_distance;
42
rvo_agent.maxNeighbors_ = max_neighbors;
43
rvo_agent.timeHorizon_ = time_horizon_agents;
44
rvo_agent.timeHorizonObst_ = time_horizon_obstacles;
45
rvo_agent.radius_ = radius;
46
rvo_agent.maxSpeed_ = max_speed;
47
rvo_agent.position_ = RVO2D::Vector2(position.x, position.y);
48
// Replacing the internal velocity directly causes major jitter / bugs due to unpredictable velocity jumps, left line here for testing.
49
//rvo_agent.velocity_ = RVO2D::Vector2(velocity.x, velocity.y);
50
rvo_agent.prefVelocity_ = RVO2D::Vector2(velocity.x, velocity.y);
51
rvo_agent.avoidance_layers_ = avoidance_layers;
52
rvo_agent.avoidance_mask_ = avoidance_mask;
53
rvo_agent.avoidance_priority_ = avoidance_priority;
54
55
if (map != nullptr) {
56
if (avoidance_enabled) {
57
map->set_agent_as_controlled(this);
58
} else {
59
map->remove_agent_as_controlled(this);
60
}
61
}
62
agent_dirty = true;
63
64
request_sync();
65
}
66
67
void NavAgent2D::set_map(NavMap2D *p_map) {
68
if (map == p_map) {
69
return;
70
}
71
72
cancel_sync_request();
73
74
if (map) {
75
map->remove_agent(this);
76
}
77
78
map = p_map;
79
agent_dirty = true;
80
81
if (map) {
82
map->add_agent(this);
83
if (avoidance_enabled) {
84
map->set_agent_as_controlled(this);
85
}
86
87
request_sync();
88
}
89
}
90
91
bool NavAgent2D::is_map_changed() {
92
if (map) {
93
bool is_changed = map->get_iteration_id() != last_map_iteration_id;
94
last_map_iteration_id = map->get_iteration_id();
95
return is_changed;
96
} else {
97
return false;
98
}
99
}
100
101
void NavAgent2D::set_avoidance_callback(Callable p_callback) {
102
avoidance_callback = p_callback;
103
}
104
105
bool NavAgent2D::has_avoidance_callback() const {
106
return avoidance_callback.is_valid();
107
}
108
109
void NavAgent2D::dispatch_avoidance_callback() {
110
if (!avoidance_callback.is_valid()) {
111
return;
112
}
113
114
Vector2 new_velocity;
115
116
new_velocity = Vector2(rvo_agent.velocity_.x(), rvo_agent.velocity_.y());
117
118
if (clamp_speed) {
119
new_velocity = new_velocity.limit_length(max_speed);
120
}
121
122
// Invoke the callback with the new velocity.
123
avoidance_callback.call(new_velocity);
124
}
125
126
void NavAgent2D::set_neighbor_distance(real_t p_neighbor_distance) {
127
neighbor_distance = p_neighbor_distance;
128
rvo_agent.neighborDist_ = neighbor_distance;
129
agent_dirty = true;
130
131
request_sync();
132
}
133
134
void NavAgent2D::set_max_neighbors(int p_max_neighbors) {
135
max_neighbors = p_max_neighbors;
136
rvo_agent.maxNeighbors_ = max_neighbors;
137
agent_dirty = true;
138
139
request_sync();
140
}
141
142
void NavAgent2D::set_time_horizon_agents(real_t p_time_horizon) {
143
time_horizon_agents = p_time_horizon;
144
rvo_agent.timeHorizon_ = time_horizon_agents;
145
agent_dirty = true;
146
147
request_sync();
148
}
149
150
void NavAgent2D::set_time_horizon_obstacles(real_t p_time_horizon) {
151
time_horizon_obstacles = p_time_horizon;
152
rvo_agent.timeHorizonObst_ = time_horizon_obstacles;
153
agent_dirty = true;
154
155
request_sync();
156
}
157
158
void NavAgent2D::set_radius(real_t p_radius) {
159
radius = p_radius;
160
rvo_agent.radius_ = radius;
161
agent_dirty = true;
162
163
request_sync();
164
}
165
166
void NavAgent2D::set_max_speed(real_t p_max_speed) {
167
max_speed = p_max_speed;
168
if (avoidance_enabled) {
169
rvo_agent.maxSpeed_ = max_speed;
170
}
171
agent_dirty = true;
172
173
request_sync();
174
}
175
176
void NavAgent2D::set_position(const Vector2 &p_position) {
177
position = p_position;
178
if (avoidance_enabled) {
179
rvo_agent.position_ = RVO2D::Vector2(p_position.x, p_position.y);
180
}
181
agent_dirty = true;
182
183
request_sync();
184
}
185
186
void NavAgent2D::set_target_position(const Vector2 &p_target_position) {
187
target_position = p_target_position;
188
}
189
190
void NavAgent2D::set_velocity(const Vector2 &p_velocity) {
191
// Sets the "wanted" velocity for an agent as a suggestion
192
// This velocity is not guaranteed, RVO simulation will only try to fulfill it
193
velocity = p_velocity;
194
if (avoidance_enabled) {
195
rvo_agent.prefVelocity_ = RVO2D::Vector2(velocity.x, velocity.y);
196
}
197
agent_dirty = true;
198
199
request_sync();
200
}
201
202
void NavAgent2D::set_velocity_forced(const Vector2 &p_velocity) {
203
// This function replaces the internal rvo simulation velocity
204
// should only be used after the agent was teleported
205
// as it destroys consistency in movement in cramped situations
206
// use velocity instead to update with a safer "suggestion"
207
velocity_forced = p_velocity;
208
if (avoidance_enabled) {
209
rvo_agent.velocity_ = RVO2D::Vector2(p_velocity.x, p_velocity.y);
210
}
211
agent_dirty = true;
212
213
request_sync();
214
}
215
216
void NavAgent2D::update() {
217
// Updates this agent with the calculated results from the rvo simulation
218
if (avoidance_enabled) {
219
velocity = Vector2(rvo_agent.velocity_.x(), rvo_agent.velocity_.y());
220
}
221
}
222
223
void NavAgent2D::set_avoidance_mask(uint32_t p_mask) {
224
avoidance_mask = p_mask;
225
rvo_agent.avoidance_mask_ = avoidance_mask;
226
agent_dirty = true;
227
228
request_sync();
229
}
230
231
void NavAgent2D::set_avoidance_layers(uint32_t p_layers) {
232
avoidance_layers = p_layers;
233
rvo_agent.avoidance_layers_ = avoidance_layers;
234
agent_dirty = true;
235
236
request_sync();
237
}
238
239
void NavAgent2D::set_avoidance_priority(real_t p_priority) {
240
ERR_FAIL_COND_MSG(p_priority < 0.0, "Avoidance priority must be between 0.0 and 1.0 inclusive.");
241
ERR_FAIL_COND_MSG(p_priority > 1.0, "Avoidance priority must be between 0.0 and 1.0 inclusive.");
242
avoidance_priority = p_priority;
243
rvo_agent.avoidance_priority_ = avoidance_priority;
244
agent_dirty = true;
245
246
request_sync();
247
}
248
249
bool NavAgent2D::is_dirty() const {
250
return agent_dirty;
251
}
252
253
void NavAgent2D::sync() {
254
agent_dirty = false;
255
}
256
257
const Dictionary NavAgent2D::get_avoidance_data() const {
258
// Returns debug data from RVO simulation internals of this agent.
259
Dictionary _avoidance_data;
260
261
_avoidance_data["max_neighbors"] = int(rvo_agent.maxNeighbors_);
262
_avoidance_data["max_speed"] = float(rvo_agent.maxSpeed_);
263
_avoidance_data["neighbor_distance"] = float(rvo_agent.neighborDist_);
264
_avoidance_data["new_velocity"] = Vector2(rvo_agent.newVelocity_.x(), rvo_agent.newVelocity_.y());
265
_avoidance_data["velocity"] = Vector2(rvo_agent.velocity_.x(), rvo_agent.velocity_.y());
266
_avoidance_data["position"] = Vector2(rvo_agent.position_.x(), rvo_agent.position_.y());
267
_avoidance_data["preferred_velocity"] = Vector2(rvo_agent.prefVelocity_.x(), rvo_agent.prefVelocity_.y());
268
_avoidance_data["radius"] = float(rvo_agent.radius_);
269
_avoidance_data["time_horizon_agents"] = float(rvo_agent.timeHorizon_);
270
_avoidance_data["time_horizon_obstacles"] = float(rvo_agent.timeHorizonObst_);
271
_avoidance_data["avoidance_layers"] = int(rvo_agent.avoidance_layers_);
272
_avoidance_data["avoidance_mask"] = int(rvo_agent.avoidance_mask_);
273
_avoidance_data["avoidance_priority"] = float(rvo_agent.avoidance_priority_);
274
return _avoidance_data;
275
}
276
277
void NavAgent2D::set_paused(bool p_paused) {
278
if (paused == p_paused) {
279
return;
280
}
281
282
paused = p_paused;
283
284
if (map) {
285
if (paused) {
286
map->remove_agent_as_controlled(this);
287
} else {
288
map->set_agent_as_controlled(this);
289
}
290
}
291
}
292
293
bool NavAgent2D::get_paused() const {
294
return paused;
295
}
296
297
void NavAgent2D::request_sync() {
298
if (map && !sync_dirty_request_list_element.in_list()) {
299
map->add_agent_sync_dirty_request(&sync_dirty_request_list_element);
300
}
301
}
302
303
void NavAgent2D::cancel_sync_request() {
304
if (map && sync_dirty_request_list_element.in_list()) {
305
map->remove_agent_sync_dirty_request(&sync_dirty_request_list_element);
306
}
307
}
308
309
NavAgent2D::NavAgent2D() :
310
sync_dirty_request_list_element(this) {
311
}
312
313
NavAgent2D::~NavAgent2D() {
314
cancel_sync_request();
315
}
316
317