Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/navigation_3d/nav_agent_3d.cpp
10277 views
1
/**************************************************************************/
2
/* nav_agent_3d.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_3d.h"
32
33
#include "nav_map_3d.h"
34
35
void NavAgent3D::set_avoidance_enabled(bool p_enabled) {
36
avoidance_enabled = p_enabled;
37
_update_rvo_agent_properties();
38
}
39
40
void NavAgent3D::set_use_3d_avoidance(bool p_enabled) {
41
use_3d_avoidance = p_enabled;
42
_update_rvo_agent_properties();
43
}
44
45
void NavAgent3D::_update_rvo_agent_properties() {
46
if (use_3d_avoidance) {
47
rvo_agent_3d.neighborDist_ = neighbor_distance;
48
rvo_agent_3d.maxNeighbors_ = max_neighbors;
49
rvo_agent_3d.timeHorizon_ = time_horizon_agents;
50
rvo_agent_3d.timeHorizonObst_ = time_horizon_obstacles;
51
rvo_agent_3d.radius_ = radius;
52
rvo_agent_3d.maxSpeed_ = max_speed;
53
rvo_agent_3d.position_ = RVO3D::Vector3(position.x, position.y, position.z);
54
// Replacing the internal velocity directly causes major jitter / bugs due to unpredictable velocity jumps, left line here for testing.
55
//rvo_agent_3d.velocity_ = RVO3D::Vector3(velocity.x, velocity.y ,velocity.z);
56
rvo_agent_3d.prefVelocity_ = RVO3D::Vector3(velocity.x, velocity.y, velocity.z);
57
rvo_agent_3d.height_ = height;
58
rvo_agent_3d.avoidance_layers_ = avoidance_layers;
59
rvo_agent_3d.avoidance_mask_ = avoidance_mask;
60
rvo_agent_3d.avoidance_priority_ = avoidance_priority;
61
} else {
62
rvo_agent_2d.neighborDist_ = neighbor_distance;
63
rvo_agent_2d.maxNeighbors_ = max_neighbors;
64
rvo_agent_2d.timeHorizon_ = time_horizon_agents;
65
rvo_agent_2d.timeHorizonObst_ = time_horizon_obstacles;
66
rvo_agent_2d.radius_ = radius;
67
rvo_agent_2d.maxSpeed_ = max_speed;
68
rvo_agent_2d.position_ = RVO2D::Vector2(position.x, position.z);
69
rvo_agent_2d.elevation_ = position.y;
70
// Replacing the internal velocity directly causes major jitter / bugs due to unpredictable velocity jumps, left line here for testing.
71
//rvo_agent_2d.velocity_ = RVO2D::Vector2(velocity.x, velocity.z);
72
rvo_agent_2d.prefVelocity_ = RVO2D::Vector2(velocity.x, velocity.z);
73
rvo_agent_2d.height_ = height;
74
rvo_agent_2d.avoidance_layers_ = avoidance_layers;
75
rvo_agent_2d.avoidance_mask_ = avoidance_mask;
76
rvo_agent_2d.avoidance_priority_ = avoidance_priority;
77
}
78
79
if (map != nullptr) {
80
if (avoidance_enabled) {
81
map->set_agent_as_controlled(this);
82
} else {
83
map->remove_agent_as_controlled(this);
84
}
85
}
86
agent_dirty = true;
87
88
request_sync();
89
}
90
91
void NavAgent3D::set_map(NavMap3D *p_map) {
92
if (map == p_map) {
93
return;
94
}
95
96
cancel_sync_request();
97
98
if (map) {
99
map->remove_agent(this);
100
}
101
102
map = p_map;
103
agent_dirty = true;
104
105
if (map) {
106
map->add_agent(this);
107
if (avoidance_enabled) {
108
map->set_agent_as_controlled(this);
109
}
110
111
request_sync();
112
}
113
}
114
115
bool NavAgent3D::is_map_changed() {
116
if (map) {
117
bool is_changed = map->get_iteration_id() != last_map_iteration_id;
118
last_map_iteration_id = map->get_iteration_id();
119
return is_changed;
120
} else {
121
return false;
122
}
123
}
124
125
void NavAgent3D::set_avoidance_callback(Callable p_callback) {
126
avoidance_callback = p_callback;
127
}
128
129
bool NavAgent3D::has_avoidance_callback() const {
130
return avoidance_callback.is_valid();
131
}
132
133
void NavAgent3D::dispatch_avoidance_callback() {
134
if (!avoidance_callback.is_valid()) {
135
return;
136
}
137
138
Vector3 new_velocity;
139
140
if (use_3d_avoidance) {
141
new_velocity = Vector3(rvo_agent_3d.velocity_.x(), rvo_agent_3d.velocity_.y(), rvo_agent_3d.velocity_.z());
142
} else {
143
new_velocity = Vector3(rvo_agent_2d.velocity_.x(), 0.0, rvo_agent_2d.velocity_.y());
144
}
145
146
if (clamp_speed) {
147
new_velocity = new_velocity.limit_length(max_speed);
148
}
149
150
// Invoke the callback with the new velocity.
151
avoidance_callback.call(new_velocity);
152
}
153
154
void NavAgent3D::set_neighbor_distance(real_t p_neighbor_distance) {
155
neighbor_distance = p_neighbor_distance;
156
if (use_3d_avoidance) {
157
rvo_agent_3d.neighborDist_ = neighbor_distance;
158
} else {
159
rvo_agent_2d.neighborDist_ = neighbor_distance;
160
}
161
agent_dirty = true;
162
163
request_sync();
164
}
165
166
void NavAgent3D::set_max_neighbors(int p_max_neighbors) {
167
max_neighbors = p_max_neighbors;
168
if (use_3d_avoidance) {
169
rvo_agent_3d.maxNeighbors_ = max_neighbors;
170
} else {
171
rvo_agent_2d.maxNeighbors_ = max_neighbors;
172
}
173
agent_dirty = true;
174
175
request_sync();
176
}
177
178
void NavAgent3D::set_time_horizon_agents(real_t p_time_horizon) {
179
time_horizon_agents = p_time_horizon;
180
if (use_3d_avoidance) {
181
rvo_agent_3d.timeHorizon_ = time_horizon_agents;
182
} else {
183
rvo_agent_2d.timeHorizon_ = time_horizon_agents;
184
}
185
agent_dirty = true;
186
187
request_sync();
188
}
189
190
void NavAgent3D::set_time_horizon_obstacles(real_t p_time_horizon) {
191
time_horizon_obstacles = p_time_horizon;
192
if (use_3d_avoidance) {
193
rvo_agent_3d.timeHorizonObst_ = time_horizon_obstacles;
194
} else {
195
rvo_agent_2d.timeHorizonObst_ = time_horizon_obstacles;
196
}
197
agent_dirty = true;
198
199
request_sync();
200
}
201
202
void NavAgent3D::set_radius(real_t p_radius) {
203
radius = p_radius;
204
if (use_3d_avoidance) {
205
rvo_agent_3d.radius_ = radius;
206
} else {
207
rvo_agent_2d.radius_ = radius;
208
}
209
agent_dirty = true;
210
211
request_sync();
212
}
213
214
void NavAgent3D::set_height(real_t p_height) {
215
height = p_height;
216
if (use_3d_avoidance) {
217
rvo_agent_3d.height_ = height;
218
} else {
219
rvo_agent_2d.height_ = height;
220
}
221
agent_dirty = true;
222
223
request_sync();
224
}
225
226
void NavAgent3D::set_max_speed(real_t p_max_speed) {
227
max_speed = p_max_speed;
228
if (avoidance_enabled) {
229
if (use_3d_avoidance) {
230
rvo_agent_3d.maxSpeed_ = max_speed;
231
} else {
232
rvo_agent_2d.maxSpeed_ = max_speed;
233
}
234
}
235
agent_dirty = true;
236
237
request_sync();
238
}
239
240
void NavAgent3D::set_position(const Vector3 p_position) {
241
position = p_position;
242
if (avoidance_enabled) {
243
if (use_3d_avoidance) {
244
rvo_agent_3d.position_ = RVO3D::Vector3(p_position.x, p_position.y, p_position.z);
245
} else {
246
rvo_agent_2d.elevation_ = p_position.y;
247
rvo_agent_2d.position_ = RVO2D::Vector2(p_position.x, p_position.z);
248
}
249
}
250
agent_dirty = true;
251
252
request_sync();
253
}
254
255
void NavAgent3D::set_target_position(const Vector3 p_target_position) {
256
target_position = p_target_position;
257
}
258
259
void NavAgent3D::set_velocity(const Vector3 p_velocity) {
260
// Sets the "wanted" velocity for an agent as a suggestion
261
// This velocity is not guaranteed, RVO simulation will only try to fulfill it
262
velocity = p_velocity;
263
if (avoidance_enabled) {
264
if (use_3d_avoidance) {
265
rvo_agent_3d.prefVelocity_ = RVO3D::Vector3(velocity.x, velocity.y, velocity.z);
266
} else {
267
rvo_agent_2d.prefVelocity_ = RVO2D::Vector2(velocity.x, velocity.z);
268
}
269
}
270
agent_dirty = true;
271
272
request_sync();
273
}
274
275
void NavAgent3D::set_velocity_forced(const Vector3 p_velocity) {
276
// This function replaces the internal rvo simulation velocity
277
// should only be used after the agent was teleported
278
// as it destroys consistency in movement in cramped situations
279
// use velocity instead to update with a safer "suggestion"
280
velocity_forced = p_velocity;
281
if (avoidance_enabled) {
282
if (use_3d_avoidance) {
283
rvo_agent_3d.velocity_ = RVO3D::Vector3(p_velocity.x, p_velocity.y, p_velocity.z);
284
} else {
285
rvo_agent_2d.velocity_ = RVO2D::Vector2(p_velocity.x, p_velocity.z);
286
}
287
}
288
agent_dirty = true;
289
290
request_sync();
291
}
292
293
void NavAgent3D::update() {
294
// Updates this agent with the calculated results from the rvo simulation
295
if (avoidance_enabled) {
296
if (use_3d_avoidance) {
297
velocity = Vector3(rvo_agent_3d.velocity_.x(), rvo_agent_3d.velocity_.y(), rvo_agent_3d.velocity_.z());
298
} else {
299
velocity = Vector3(rvo_agent_2d.velocity_.x(), 0.0, rvo_agent_2d.velocity_.y());
300
}
301
}
302
}
303
304
void NavAgent3D::set_avoidance_mask(uint32_t p_mask) {
305
avoidance_mask = p_mask;
306
if (use_3d_avoidance) {
307
rvo_agent_3d.avoidance_mask_ = avoidance_mask;
308
} else {
309
rvo_agent_2d.avoidance_mask_ = avoidance_mask;
310
}
311
agent_dirty = true;
312
313
request_sync();
314
}
315
316
void NavAgent3D::set_avoidance_layers(uint32_t p_layers) {
317
avoidance_layers = p_layers;
318
if (use_3d_avoidance) {
319
rvo_agent_3d.avoidance_layers_ = avoidance_layers;
320
} else {
321
rvo_agent_2d.avoidance_layers_ = avoidance_layers;
322
}
323
agent_dirty = true;
324
325
request_sync();
326
}
327
328
void NavAgent3D::set_avoidance_priority(real_t p_priority) {
329
ERR_FAIL_COND_MSG(p_priority < 0.0, "Avoidance priority must be between 0.0 and 1.0 inclusive.");
330
ERR_FAIL_COND_MSG(p_priority > 1.0, "Avoidance priority must be between 0.0 and 1.0 inclusive.");
331
avoidance_priority = p_priority;
332
if (use_3d_avoidance) {
333
rvo_agent_3d.avoidance_priority_ = avoidance_priority;
334
} else {
335
rvo_agent_2d.avoidance_priority_ = avoidance_priority;
336
}
337
agent_dirty = true;
338
339
request_sync();
340
}
341
342
bool NavAgent3D::is_dirty() const {
343
return agent_dirty;
344
}
345
346
void NavAgent3D::sync() {
347
agent_dirty = false;
348
}
349
350
const Dictionary NavAgent3D::get_avoidance_data() const {
351
// Returns debug data from RVO simulation internals of this agent.
352
Dictionary _avoidance_data;
353
if (use_3d_avoidance) {
354
_avoidance_data["max_neighbors"] = int(rvo_agent_3d.maxNeighbors_);
355
_avoidance_data["max_speed"] = float(rvo_agent_3d.maxSpeed_);
356
_avoidance_data["neighbor_distance"] = float(rvo_agent_3d.neighborDist_);
357
_avoidance_data["new_velocity"] = Vector3(rvo_agent_3d.newVelocity_.x(), rvo_agent_3d.newVelocity_.y(), rvo_agent_3d.newVelocity_.z());
358
_avoidance_data["velocity"] = Vector3(rvo_agent_3d.velocity_.x(), rvo_agent_3d.velocity_.y(), rvo_agent_3d.velocity_.z());
359
_avoidance_data["position"] = Vector3(rvo_agent_3d.position_.x(), rvo_agent_3d.position_.y(), rvo_agent_3d.position_.z());
360
_avoidance_data["preferred_velocity"] = Vector3(rvo_agent_3d.prefVelocity_.x(), rvo_agent_3d.prefVelocity_.y(), rvo_agent_3d.prefVelocity_.z());
361
_avoidance_data["radius"] = float(rvo_agent_3d.radius_);
362
_avoidance_data["time_horizon_agents"] = float(rvo_agent_3d.timeHorizon_);
363
_avoidance_data["time_horizon_obstacles"] = 0.0;
364
_avoidance_data["height"] = float(rvo_agent_3d.height_);
365
_avoidance_data["avoidance_layers"] = int(rvo_agent_3d.avoidance_layers_);
366
_avoidance_data["avoidance_mask"] = int(rvo_agent_3d.avoidance_mask_);
367
_avoidance_data["avoidance_priority"] = float(rvo_agent_3d.avoidance_priority_);
368
} else {
369
_avoidance_data["max_neighbors"] = int(rvo_agent_2d.maxNeighbors_);
370
_avoidance_data["max_speed"] = float(rvo_agent_2d.maxSpeed_);
371
_avoidance_data["neighbor_distance"] = float(rvo_agent_2d.neighborDist_);
372
_avoidance_data["new_velocity"] = Vector3(rvo_agent_2d.newVelocity_.x(), 0.0, rvo_agent_2d.newVelocity_.y());
373
_avoidance_data["velocity"] = Vector3(rvo_agent_2d.velocity_.x(), 0.0, rvo_agent_2d.velocity_.y());
374
_avoidance_data["position"] = Vector3(rvo_agent_2d.position_.x(), 0.0, rvo_agent_2d.position_.y());
375
_avoidance_data["preferred_velocity"] = Vector3(rvo_agent_2d.prefVelocity_.x(), 0.0, rvo_agent_2d.prefVelocity_.y());
376
_avoidance_data["radius"] = float(rvo_agent_2d.radius_);
377
_avoidance_data["time_horizon_agents"] = float(rvo_agent_2d.timeHorizon_);
378
_avoidance_data["time_horizon_obstacles"] = float(rvo_agent_2d.timeHorizonObst_);
379
_avoidance_data["height"] = float(rvo_agent_2d.height_);
380
_avoidance_data["avoidance_layers"] = int(rvo_agent_2d.avoidance_layers_);
381
_avoidance_data["avoidance_mask"] = int(rvo_agent_2d.avoidance_mask_);
382
_avoidance_data["avoidance_priority"] = float(rvo_agent_2d.avoidance_priority_);
383
}
384
return _avoidance_data;
385
}
386
387
void NavAgent3D::set_paused(bool p_paused) {
388
if (paused == p_paused) {
389
return;
390
}
391
392
paused = p_paused;
393
394
if (map) {
395
if (paused) {
396
map->remove_agent_as_controlled(this);
397
} else {
398
map->set_agent_as_controlled(this);
399
}
400
}
401
}
402
403
bool NavAgent3D::get_paused() const {
404
return paused;
405
}
406
407
void NavAgent3D::request_sync() {
408
if (map && !sync_dirty_request_list_element.in_list()) {
409
map->add_agent_sync_dirty_request(&sync_dirty_request_list_element);
410
}
411
}
412
413
void NavAgent3D::cancel_sync_request() {
414
if (map && sync_dirty_request_list_element.in_list()) {
415
map->remove_agent_sync_dirty_request(&sync_dirty_request_list_element);
416
}
417
}
418
419
NavAgent3D::NavAgent3D() :
420
sync_dirty_request_list_element(this) {
421
}
422
423
NavAgent3D::~NavAgent3D() {
424
cancel_sync_request();
425
}
426
427