Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/2d/navigation/navigation_agent_2d.cpp
9904 views
1
/**************************************************************************/
2
/* navigation_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 "navigation_agent_2d.h"
32
33
#include "core/math/geometry_2d.h"
34
#include "scene/2d/navigation/navigation_link_2d.h"
35
#include "scene/resources/world_2d.h"
36
#include "servers/navigation_server_2d.h"
37
38
void NavigationAgent2D::_bind_methods() {
39
ClassDB::bind_method(D_METHOD("get_rid"), &NavigationAgent2D::get_rid);
40
41
ClassDB::bind_method(D_METHOD("set_avoidance_enabled", "enabled"), &NavigationAgent2D::set_avoidance_enabled);
42
ClassDB::bind_method(D_METHOD("get_avoidance_enabled"), &NavigationAgent2D::get_avoidance_enabled);
43
44
ClassDB::bind_method(D_METHOD("set_path_desired_distance", "desired_distance"), &NavigationAgent2D::set_path_desired_distance);
45
ClassDB::bind_method(D_METHOD("get_path_desired_distance"), &NavigationAgent2D::get_path_desired_distance);
46
47
ClassDB::bind_method(D_METHOD("set_target_desired_distance", "desired_distance"), &NavigationAgent2D::set_target_desired_distance);
48
ClassDB::bind_method(D_METHOD("get_target_desired_distance"), &NavigationAgent2D::get_target_desired_distance);
49
50
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &NavigationAgent2D::set_radius);
51
ClassDB::bind_method(D_METHOD("get_radius"), &NavigationAgent2D::get_radius);
52
53
ClassDB::bind_method(D_METHOD("set_neighbor_distance", "neighbor_distance"), &NavigationAgent2D::set_neighbor_distance);
54
ClassDB::bind_method(D_METHOD("get_neighbor_distance"), &NavigationAgent2D::get_neighbor_distance);
55
56
ClassDB::bind_method(D_METHOD("set_max_neighbors", "max_neighbors"), &NavigationAgent2D::set_max_neighbors);
57
ClassDB::bind_method(D_METHOD("get_max_neighbors"), &NavigationAgent2D::get_max_neighbors);
58
59
ClassDB::bind_method(D_METHOD("set_time_horizon_agents", "time_horizon"), &NavigationAgent2D::set_time_horizon_agents);
60
ClassDB::bind_method(D_METHOD("get_time_horizon_agents"), &NavigationAgent2D::get_time_horizon_agents);
61
62
ClassDB::bind_method(D_METHOD("set_time_horizon_obstacles", "time_horizon"), &NavigationAgent2D::set_time_horizon_obstacles);
63
ClassDB::bind_method(D_METHOD("get_time_horizon_obstacles"), &NavigationAgent2D::get_time_horizon_obstacles);
64
65
ClassDB::bind_method(D_METHOD("set_max_speed", "max_speed"), &NavigationAgent2D::set_max_speed);
66
ClassDB::bind_method(D_METHOD("get_max_speed"), &NavigationAgent2D::get_max_speed);
67
68
ClassDB::bind_method(D_METHOD("set_path_max_distance", "max_speed"), &NavigationAgent2D::set_path_max_distance);
69
ClassDB::bind_method(D_METHOD("get_path_max_distance"), &NavigationAgent2D::get_path_max_distance);
70
71
ClassDB::bind_method(D_METHOD("set_navigation_layers", "navigation_layers"), &NavigationAgent2D::set_navigation_layers);
72
ClassDB::bind_method(D_METHOD("get_navigation_layers"), &NavigationAgent2D::get_navigation_layers);
73
74
ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationAgent2D::set_navigation_layer_value);
75
ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationAgent2D::get_navigation_layer_value);
76
77
ClassDB::bind_method(D_METHOD("set_pathfinding_algorithm", "pathfinding_algorithm"), &NavigationAgent2D::set_pathfinding_algorithm);
78
ClassDB::bind_method(D_METHOD("get_pathfinding_algorithm"), &NavigationAgent2D::get_pathfinding_algorithm);
79
80
ClassDB::bind_method(D_METHOD("set_path_postprocessing", "path_postprocessing"), &NavigationAgent2D::set_path_postprocessing);
81
ClassDB::bind_method(D_METHOD("get_path_postprocessing"), &NavigationAgent2D::get_path_postprocessing);
82
83
ClassDB::bind_method(D_METHOD("set_path_metadata_flags", "flags"), &NavigationAgent2D::set_path_metadata_flags);
84
ClassDB::bind_method(D_METHOD("get_path_metadata_flags"), &NavigationAgent2D::get_path_metadata_flags);
85
86
ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationAgent2D::set_navigation_map);
87
ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationAgent2D::get_navigation_map);
88
89
ClassDB::bind_method(D_METHOD("set_target_position", "position"), &NavigationAgent2D::set_target_position);
90
ClassDB::bind_method(D_METHOD("get_target_position"), &NavigationAgent2D::get_target_position);
91
92
ClassDB::bind_method(D_METHOD("set_simplify_path", "enabled"), &NavigationAgent2D::set_simplify_path);
93
ClassDB::bind_method(D_METHOD("get_simplify_path"), &NavigationAgent2D::get_simplify_path);
94
95
ClassDB::bind_method(D_METHOD("set_simplify_epsilon", "epsilon"), &NavigationAgent2D::set_simplify_epsilon);
96
ClassDB::bind_method(D_METHOD("get_simplify_epsilon"), &NavigationAgent2D::get_simplify_epsilon);
97
98
ClassDB::bind_method(D_METHOD("set_path_return_max_length", "length"), &NavigationAgent2D::set_path_return_max_length);
99
ClassDB::bind_method(D_METHOD("get_path_return_max_length"), &NavigationAgent2D::get_path_return_max_length);
100
101
ClassDB::bind_method(D_METHOD("set_path_return_max_radius", "radius"), &NavigationAgent2D::set_path_return_max_radius);
102
ClassDB::bind_method(D_METHOD("get_path_return_max_radius"), &NavigationAgent2D::get_path_return_max_radius);
103
104
ClassDB::bind_method(D_METHOD("set_path_search_max_polygons", "max_polygons"), &NavigationAgent2D::set_path_search_max_polygons);
105
ClassDB::bind_method(D_METHOD("get_path_search_max_polygons"), &NavigationAgent2D::get_path_search_max_polygons);
106
107
ClassDB::bind_method(D_METHOD("set_path_search_max_distance", "distance"), &NavigationAgent2D::set_path_search_max_distance);
108
ClassDB::bind_method(D_METHOD("get_path_search_max_distance"), &NavigationAgent2D::get_path_search_max_distance);
109
110
ClassDB::bind_method(D_METHOD("get_path_length"), &NavigationAgent2D::get_path_length);
111
112
ClassDB::bind_method(D_METHOD("get_next_path_position"), &NavigationAgent2D::get_next_path_position);
113
114
ClassDB::bind_method(D_METHOD("set_velocity_forced", "velocity"), &NavigationAgent2D::set_velocity_forced);
115
116
ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &NavigationAgent2D::set_velocity);
117
ClassDB::bind_method(D_METHOD("get_velocity"), &NavigationAgent2D::get_velocity);
118
119
ClassDB::bind_method(D_METHOD("distance_to_target"), &NavigationAgent2D::distance_to_target);
120
121
ClassDB::bind_method(D_METHOD("get_current_navigation_result"), &NavigationAgent2D::get_current_navigation_result);
122
123
ClassDB::bind_method(D_METHOD("get_current_navigation_path"), &NavigationAgent2D::get_current_navigation_path);
124
ClassDB::bind_method(D_METHOD("get_current_navigation_path_index"), &NavigationAgent2D::get_current_navigation_path_index);
125
ClassDB::bind_method(D_METHOD("is_target_reached"), &NavigationAgent2D::is_target_reached);
126
ClassDB::bind_method(D_METHOD("is_target_reachable"), &NavigationAgent2D::is_target_reachable);
127
ClassDB::bind_method(D_METHOD("is_navigation_finished"), &NavigationAgent2D::is_navigation_finished);
128
ClassDB::bind_method(D_METHOD("get_final_position"), &NavigationAgent2D::get_final_position);
129
130
ClassDB::bind_method(D_METHOD("_avoidance_done", "new_velocity"), &NavigationAgent2D::_avoidance_done);
131
132
ClassDB::bind_method(D_METHOD("set_avoidance_layers", "layers"), &NavigationAgent2D::set_avoidance_layers);
133
ClassDB::bind_method(D_METHOD("get_avoidance_layers"), &NavigationAgent2D::get_avoidance_layers);
134
ClassDB::bind_method(D_METHOD("set_avoidance_mask", "mask"), &NavigationAgent2D::set_avoidance_mask);
135
ClassDB::bind_method(D_METHOD("get_avoidance_mask"), &NavigationAgent2D::get_avoidance_mask);
136
ClassDB::bind_method(D_METHOD("set_avoidance_layer_value", "layer_number", "value"), &NavigationAgent2D::set_avoidance_layer_value);
137
ClassDB::bind_method(D_METHOD("get_avoidance_layer_value", "layer_number"), &NavigationAgent2D::get_avoidance_layer_value);
138
ClassDB::bind_method(D_METHOD("set_avoidance_mask_value", "mask_number", "value"), &NavigationAgent2D::set_avoidance_mask_value);
139
ClassDB::bind_method(D_METHOD("get_avoidance_mask_value", "mask_number"), &NavigationAgent2D::get_avoidance_mask_value);
140
ClassDB::bind_method(D_METHOD("set_avoidance_priority", "priority"), &NavigationAgent2D::set_avoidance_priority);
141
ClassDB::bind_method(D_METHOD("get_avoidance_priority"), &NavigationAgent2D::get_avoidance_priority);
142
143
ADD_GROUP("Pathfinding", "");
144
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "target_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_target_position", "get_target_position");
145
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_desired_distance", PROPERTY_HINT_RANGE, "0.1,1000,0.01,or_greater,suffix:px"), "set_path_desired_distance", "get_path_desired_distance");
146
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_desired_distance", PROPERTY_HINT_RANGE, "0.1,1000,0.01,or_greater,suffix:px"), "set_target_desired_distance", "get_target_desired_distance");
147
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "10,1000,1,or_greater,suffix:px"), "set_path_max_distance", "get_path_max_distance");
148
ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");
149
ADD_PROPERTY(PropertyInfo(Variant::INT, "pathfinding_algorithm", PROPERTY_HINT_ENUM, "AStar"), "set_pathfinding_algorithm", "get_pathfinding_algorithm");
150
ADD_PROPERTY(PropertyInfo(Variant::INT, "path_postprocessing", PROPERTY_HINT_ENUM, "Corridorfunnel,Edgecentered,None"), "set_path_postprocessing", "get_path_postprocessing");
151
ADD_PROPERTY(PropertyInfo(Variant::INT, "path_metadata_flags", PROPERTY_HINT_FLAGS, "Include Types,Include RIDs,Include Owners"), "set_path_metadata_flags", "get_path_metadata_flags");
152
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "simplify_path"), "set_simplify_path", "get_simplify_path");
153
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "simplify_epsilon", PROPERTY_HINT_RANGE, "0.0,10.0,0.001,or_greater,suffix:px"), "set_simplify_epsilon", "get_simplify_epsilon");
154
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_return_max_length", PROPERTY_HINT_RANGE, "0.0,10240.0,0.001,or_greater,suffix:px"), "set_path_return_max_length", "get_path_return_max_length");
155
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_return_max_radius", PROPERTY_HINT_RANGE, "0.0,10240.0,0.001,or_greater,suffix:px"), "set_path_return_max_radius", "get_path_return_max_radius");
156
ADD_PROPERTY(PropertyInfo(Variant::INT, "path_search_max_polygons", PROPERTY_HINT_RANGE, "0,4096,1,or_greater"), "set_path_search_max_polygons", "get_path_search_max_polygons");
157
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_search_max_distance"), "set_path_search_max_distance", "get_path_search_max_distance");
158
159
ADD_GROUP("Avoidance", "");
160
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled");
161
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_velocity", "get_velocity");
162
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,500,0.01,or_greater,suffix:px"), "set_radius", "get_radius");
163
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "neighbor_distance", PROPERTY_HINT_RANGE, "0.1,100000,0.01,or_greater,suffix:px"), "set_neighbor_distance", "get_neighbor_distance");
164
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_neighbors", PROPERTY_HINT_RANGE, "1,10000,1,or_greater"), "set_max_neighbors", "get_max_neighbors");
165
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_horizon_agents", PROPERTY_HINT_RANGE, "0.0,10,0.01,or_greater,suffix:s"), "set_time_horizon_agents", "get_time_horizon_agents");
166
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_horizon_obstacles", PROPERTY_HINT_RANGE, "0.0,10,0.01,or_greater,suffix:s"), "set_time_horizon_obstacles", "get_time_horizon_obstacles");
167
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_speed", PROPERTY_HINT_RANGE, "0.01,100000,0.01,or_greater,suffix:px/s"), "set_max_speed", "get_max_speed");
168
ADD_PROPERTY(PropertyInfo(Variant::INT, "avoidance_layers", PROPERTY_HINT_LAYERS_AVOIDANCE), "set_avoidance_layers", "get_avoidance_layers");
169
ADD_PROPERTY(PropertyInfo(Variant::INT, "avoidance_mask", PROPERTY_HINT_LAYERS_AVOIDANCE), "set_avoidance_mask", "get_avoidance_mask");
170
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "avoidance_priority", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_avoidance_priority", "get_avoidance_priority");
171
172
ClassDB::bind_method(D_METHOD("set_debug_enabled", "enabled"), &NavigationAgent2D::set_debug_enabled);
173
ClassDB::bind_method(D_METHOD("get_debug_enabled"), &NavigationAgent2D::get_debug_enabled);
174
ClassDB::bind_method(D_METHOD("set_debug_use_custom", "enabled"), &NavigationAgent2D::set_debug_use_custom);
175
ClassDB::bind_method(D_METHOD("get_debug_use_custom"), &NavigationAgent2D::get_debug_use_custom);
176
ClassDB::bind_method(D_METHOD("set_debug_path_custom_color", "color"), &NavigationAgent2D::set_debug_path_custom_color);
177
ClassDB::bind_method(D_METHOD("get_debug_path_custom_color"), &NavigationAgent2D::get_debug_path_custom_color);
178
ClassDB::bind_method(D_METHOD("set_debug_path_custom_point_size", "point_size"), &NavigationAgent2D::set_debug_path_custom_point_size);
179
ClassDB::bind_method(D_METHOD("get_debug_path_custom_point_size"), &NavigationAgent2D::get_debug_path_custom_point_size);
180
ClassDB::bind_method(D_METHOD("set_debug_path_custom_line_width", "line_width"), &NavigationAgent2D::set_debug_path_custom_line_width);
181
ClassDB::bind_method(D_METHOD("get_debug_path_custom_line_width"), &NavigationAgent2D::get_debug_path_custom_line_width);
182
183
ADD_GROUP("Debug", "debug_");
184
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_enabled"), "set_debug_enabled", "get_debug_enabled");
185
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_use_custom"), "set_debug_use_custom", "get_debug_use_custom");
186
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "debug_path_custom_color"), "set_debug_path_custom_color", "get_debug_path_custom_color");
187
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "debug_path_custom_point_size", PROPERTY_HINT_RANGE, "0,50,0.01,or_greater,suffix:px"), "set_debug_path_custom_point_size", "get_debug_path_custom_point_size");
188
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "debug_path_custom_line_width", PROPERTY_HINT_RANGE, "-1,50,0.01,or_greater,suffix:px"), "set_debug_path_custom_line_width", "get_debug_path_custom_line_width");
189
190
ADD_SIGNAL(MethodInfo("path_changed"));
191
ADD_SIGNAL(MethodInfo("target_reached"));
192
ADD_SIGNAL(MethodInfo("waypoint_reached", PropertyInfo(Variant::DICTIONARY, "details")));
193
ADD_SIGNAL(MethodInfo("link_reached", PropertyInfo(Variant::DICTIONARY, "details")));
194
ADD_SIGNAL(MethodInfo("navigation_finished"));
195
ADD_SIGNAL(MethodInfo("velocity_computed", PropertyInfo(Variant::VECTOR2, "safe_velocity")));
196
}
197
198
#ifndef DISABLE_DEPRECATED
199
// Compatibility with Godot 4.0 beta 10 or below.
200
// Functions in block below all renamed or replaced in 4.0 beta 1X avoidance rework.
201
bool NavigationAgent2D::_set(const StringName &p_name, const Variant &p_value) {
202
if (p_name == "time_horizon") {
203
set_time_horizon_agents(p_value);
204
return true;
205
}
206
if (p_name == "target_location") {
207
set_target_position(p_value);
208
return true;
209
}
210
return false;
211
}
212
213
bool NavigationAgent2D::_get(const StringName &p_name, Variant &r_ret) const {
214
if (p_name == "time_horizon") {
215
r_ret = get_time_horizon_agents();
216
return true;
217
}
218
if (p_name == "target_location") {
219
r_ret = get_target_position();
220
return true;
221
}
222
return false;
223
}
224
#endif // DISABLE_DEPRECATED
225
226
void NavigationAgent2D::_notification(int p_what) {
227
switch (p_what) {
228
case NOTIFICATION_POST_ENTER_TREE: {
229
// need to use POST_ENTER_TREE cause with normal ENTER_TREE not all required Nodes are ready.
230
// cannot use READY as ready does not get called if Node is re-added to SceneTree
231
set_agent_parent(get_parent());
232
set_physics_process_internal(true);
233
234
if (agent_parent && avoidance_enabled) {
235
NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position());
236
}
237
238
#ifdef DEBUG_ENABLED
239
if (NavigationServer2D::get_singleton()->get_debug_enabled()) {
240
debug_path_dirty = true;
241
}
242
#endif // DEBUG_ENABLED
243
244
} break;
245
246
case NOTIFICATION_PARENTED: {
247
if (is_inside_tree() && (get_parent() != agent_parent)) {
248
// only react to PARENTED notifications when already inside_tree and parent changed, e.g. users switch nodes around
249
// PARENTED notification fires also when Node is added in scripts to a parent
250
// this would spam transforms fails and world fails while Node is outside SceneTree
251
// when node gets reparented when joining the tree POST_ENTER_TREE takes care of this
252
set_agent_parent(get_parent());
253
set_physics_process_internal(true);
254
}
255
} break;
256
257
case NOTIFICATION_UNPARENTED: {
258
// if agent has no parent no point in processing it until reparented
259
set_agent_parent(nullptr);
260
set_physics_process_internal(false);
261
} break;
262
263
case NOTIFICATION_EXIT_TREE: {
264
set_agent_parent(nullptr);
265
set_physics_process_internal(false);
266
267
#ifdef DEBUG_ENABLED
268
if (debug_path_instance.is_valid()) {
269
RenderingServer::get_singleton()->canvas_item_set_visible(debug_path_instance, false);
270
}
271
#endif // DEBUG_ENABLED
272
} break;
273
274
case NOTIFICATION_SUSPENDED:
275
case NOTIFICATION_PAUSED: {
276
if (agent_parent) {
277
NavigationServer2D::get_singleton()->agent_set_paused(get_rid(), !agent_parent->can_process());
278
}
279
} break;
280
281
case NOTIFICATION_UNSUSPENDED: {
282
if (get_tree()->is_paused()) {
283
break;
284
}
285
[[fallthrough]];
286
}
287
288
case NOTIFICATION_UNPAUSED: {
289
if (agent_parent) {
290
NavigationServer2D::get_singleton()->agent_set_paused(get_rid(), !agent_parent->can_process());
291
}
292
} break;
293
294
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
295
if (agent_parent && avoidance_enabled) {
296
NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position());
297
}
298
if (agent_parent && target_position_submitted) {
299
if (velocity_submitted) {
300
velocity_submitted = false;
301
if (avoidance_enabled) {
302
NavigationServer2D::get_singleton()->agent_set_velocity(agent, velocity);
303
}
304
}
305
if (velocity_forced_submitted) {
306
velocity_forced_submitted = false;
307
if (avoidance_enabled) {
308
NavigationServer2D::get_singleton()->agent_set_velocity_forced(agent, velocity_forced);
309
}
310
}
311
}
312
#ifdef DEBUG_ENABLED
313
if (debug_path_dirty) {
314
_update_debug_path();
315
}
316
#endif // DEBUG_ENABLED
317
} break;
318
}
319
}
320
321
NavigationAgent2D::NavigationAgent2D() {
322
agent = NavigationServer2D::get_singleton()->agent_create();
323
324
NavigationServer2D::get_singleton()->agent_set_neighbor_distance(agent, neighbor_distance);
325
NavigationServer2D::get_singleton()->agent_set_max_neighbors(agent, max_neighbors);
326
NavigationServer2D::get_singleton()->agent_set_time_horizon_agents(agent, time_horizon_agents);
327
NavigationServer2D::get_singleton()->agent_set_time_horizon_obstacles(agent, time_horizon_obstacles);
328
NavigationServer2D::get_singleton()->agent_set_radius(agent, radius);
329
NavigationServer2D::get_singleton()->agent_set_max_speed(agent, max_speed);
330
NavigationServer2D::get_singleton()->agent_set_avoidance_layers(agent, avoidance_layers);
331
NavigationServer2D::get_singleton()->agent_set_avoidance_mask(agent, avoidance_mask);
332
NavigationServer2D::get_singleton()->agent_set_avoidance_priority(agent, avoidance_priority);
333
NavigationServer2D::get_singleton()->agent_set_avoidance_enabled(agent, avoidance_enabled);
334
if (avoidance_enabled) {
335
NavigationServer2D::get_singleton()->agent_set_avoidance_callback(agent, callable_mp(this, &NavigationAgent2D::_avoidance_done));
336
}
337
338
// Preallocate query and result objects to improve performance.
339
navigation_query = Ref<NavigationPathQueryParameters2D>();
340
navigation_query.instantiate();
341
342
navigation_result = Ref<NavigationPathQueryResult2D>();
343
navigation_result.instantiate();
344
345
#ifdef DEBUG_ENABLED
346
NavigationServer2D::get_singleton()->connect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationAgent2D::_navigation_debug_changed));
347
#endif // DEBUG_ENABLED
348
}
349
350
NavigationAgent2D::~NavigationAgent2D() {
351
ERR_FAIL_NULL(NavigationServer2D::get_singleton());
352
NavigationServer2D::get_singleton()->free(agent);
353
agent = RID(); // Pointless
354
355
#ifdef DEBUG_ENABLED
356
NavigationServer2D::get_singleton()->disconnect(SNAME("navigation_debug_changed"), callable_mp(this, &NavigationAgent2D::_navigation_debug_changed));
357
358
ERR_FAIL_NULL(RenderingServer::get_singleton());
359
if (debug_path_instance.is_valid()) {
360
RenderingServer::get_singleton()->free(debug_path_instance);
361
}
362
#endif // DEBUG_ENABLED
363
}
364
365
void NavigationAgent2D::set_avoidance_enabled(bool p_enabled) {
366
if (avoidance_enabled == p_enabled) {
367
return;
368
}
369
370
avoidance_enabled = p_enabled;
371
372
if (avoidance_enabled) {
373
NavigationServer2D::get_singleton()->agent_set_avoidance_enabled(agent, true);
374
NavigationServer2D::get_singleton()->agent_set_avoidance_callback(agent, callable_mp(this, &NavigationAgent2D::_avoidance_done));
375
} else {
376
NavigationServer2D::get_singleton()->agent_set_avoidance_enabled(agent, false);
377
NavigationServer2D::get_singleton()->agent_set_avoidance_callback(agent, Callable());
378
}
379
}
380
381
bool NavigationAgent2D::get_avoidance_enabled() const {
382
return avoidance_enabled;
383
}
384
385
void NavigationAgent2D::set_agent_parent(Node *p_agent_parent) {
386
if (agent_parent == p_agent_parent) {
387
return;
388
}
389
390
// remove agent from any avoidance map before changing parent or there will be leftovers on the RVO map
391
NavigationServer2D::get_singleton()->agent_set_avoidance_callback(agent, Callable());
392
393
if (Object::cast_to<Node2D>(p_agent_parent) != nullptr) {
394
// place agent on navigation map first or else the RVO agent callback creation fails silently later
395
agent_parent = Object::cast_to<Node2D>(p_agent_parent);
396
if (map_override.is_valid()) {
397
NavigationServer2D::get_singleton()->agent_set_map(get_rid(), map_override);
398
} else {
399
NavigationServer2D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_2d()->get_navigation_map());
400
}
401
402
// create new avoidance callback if enabled
403
if (avoidance_enabled) {
404
NavigationServer2D::get_singleton()->agent_set_avoidance_callback(agent, callable_mp(this, &NavigationAgent2D::_avoidance_done));
405
}
406
} else {
407
agent_parent = nullptr;
408
NavigationServer2D::get_singleton()->agent_set_map(get_rid(), RID());
409
}
410
}
411
412
void NavigationAgent2D::set_navigation_layers(uint32_t p_navigation_layers) {
413
if (navigation_layers == p_navigation_layers) {
414
return;
415
}
416
417
navigation_layers = p_navigation_layers;
418
419
if (target_position_submitted) {
420
_request_repath();
421
}
422
}
423
424
uint32_t NavigationAgent2D::get_navigation_layers() const {
425
return navigation_layers;
426
}
427
428
void NavigationAgent2D::set_navigation_layer_value(int p_layer_number, bool p_value) {
429
ERR_FAIL_COND_MSG(p_layer_number < 1, "Navigation layer number must be between 1 and 32 inclusive.");
430
ERR_FAIL_COND_MSG(p_layer_number > 32, "Navigation layer number must be between 1 and 32 inclusive.");
431
uint32_t _navigation_layers = get_navigation_layers();
432
if (p_value) {
433
_navigation_layers |= 1 << (p_layer_number - 1);
434
} else {
435
_navigation_layers &= ~(1 << (p_layer_number - 1));
436
}
437
set_navigation_layers(_navigation_layers);
438
}
439
440
bool NavigationAgent2D::get_navigation_layer_value(int p_layer_number) const {
441
ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Navigation layer number must be between 1 and 32 inclusive.");
442
ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Navigation layer number must be between 1 and 32 inclusive.");
443
return get_navigation_layers() & (1 << (p_layer_number - 1));
444
}
445
446
void NavigationAgent2D::set_pathfinding_algorithm(const NavigationPathQueryParameters2D::PathfindingAlgorithm p_pathfinding_algorithm) {
447
if (pathfinding_algorithm == p_pathfinding_algorithm) {
448
return;
449
}
450
451
pathfinding_algorithm = p_pathfinding_algorithm;
452
453
navigation_query->set_pathfinding_algorithm(pathfinding_algorithm);
454
}
455
456
void NavigationAgent2D::set_path_postprocessing(const NavigationPathQueryParameters2D::PathPostProcessing p_path_postprocessing) {
457
if (path_postprocessing == p_path_postprocessing) {
458
return;
459
}
460
461
path_postprocessing = p_path_postprocessing;
462
463
navigation_query->set_path_postprocessing(path_postprocessing);
464
}
465
466
void NavigationAgent2D::set_simplify_path(bool p_enabled) {
467
simplify_path = p_enabled;
468
navigation_query->set_simplify_path(simplify_path);
469
}
470
471
bool NavigationAgent2D::get_simplify_path() const {
472
return simplify_path;
473
}
474
475
void NavigationAgent2D::set_simplify_epsilon(real_t p_epsilon) {
476
simplify_epsilon = MAX(0.0, p_epsilon);
477
navigation_query->set_simplify_epsilon(simplify_epsilon);
478
}
479
480
real_t NavigationAgent2D::get_simplify_epsilon() const {
481
return simplify_epsilon;
482
}
483
484
void NavigationAgent2D::set_path_return_max_length(float p_length) {
485
path_return_max_length = MAX(0.0, p_length);
486
navigation_query->set_path_return_max_length(path_return_max_length);
487
}
488
489
float NavigationAgent2D::get_path_return_max_length() const {
490
return path_return_max_length;
491
}
492
493
void NavigationAgent2D::set_path_return_max_radius(float p_radius) {
494
path_return_max_radius = MAX(0.0, p_radius);
495
navigation_query->set_path_return_max_radius(path_return_max_radius);
496
}
497
498
float NavigationAgent2D::get_path_return_max_radius() const {
499
return path_return_max_radius;
500
}
501
502
void NavigationAgent2D::set_path_search_max_polygons(int p_max_polygons) {
503
path_search_max_polygons = p_max_polygons;
504
navigation_query->set_path_search_max_polygons(path_search_max_polygons);
505
}
506
507
int NavigationAgent2D::get_path_search_max_polygons() const {
508
return path_search_max_polygons;
509
}
510
511
void NavigationAgent2D::set_path_search_max_distance(float p_distance) {
512
path_search_max_distance = MAX(0.0, p_distance);
513
navigation_query->set_path_search_max_distance(path_search_max_distance);
514
}
515
516
float NavigationAgent2D::get_path_search_max_distance() const {
517
return path_search_max_distance;
518
}
519
520
float NavigationAgent2D::get_path_length() const {
521
return navigation_result->get_path_length();
522
}
523
524
void NavigationAgent2D::set_path_metadata_flags(BitField<NavigationPathQueryParameters2D::PathMetadataFlags> p_path_metadata_flags) {
525
if (path_metadata_flags == p_path_metadata_flags) {
526
return;
527
}
528
529
path_metadata_flags = p_path_metadata_flags;
530
}
531
532
void NavigationAgent2D::set_navigation_map(RID p_navigation_map) {
533
if (map_override == p_navigation_map) {
534
return;
535
}
536
537
map_override = p_navigation_map;
538
539
NavigationServer2D::get_singleton()->agent_set_map(agent, map_override);
540
if (target_position_submitted) {
541
_request_repath();
542
}
543
}
544
545
RID NavigationAgent2D::get_navigation_map() const {
546
if (map_override.is_valid()) {
547
return map_override;
548
} else if (agent_parent != nullptr) {
549
return agent_parent->get_world_2d()->get_navigation_map();
550
}
551
return RID();
552
}
553
554
void NavigationAgent2D::set_path_desired_distance(real_t p_path_desired_distance) {
555
if (Math::is_equal_approx(path_desired_distance, p_path_desired_distance)) {
556
return;
557
}
558
559
path_desired_distance = p_path_desired_distance;
560
}
561
562
void NavigationAgent2D::set_target_desired_distance(real_t p_target_desired_distance) {
563
if (Math::is_equal_approx(target_desired_distance, p_target_desired_distance)) {
564
return;
565
}
566
567
target_desired_distance = p_target_desired_distance;
568
}
569
570
void NavigationAgent2D::set_radius(real_t p_radius) {
571
ERR_FAIL_COND_MSG(p_radius < 0.0, "Radius must be positive.");
572
if (Math::is_equal_approx(radius, p_radius)) {
573
return;
574
}
575
576
radius = p_radius;
577
578
NavigationServer2D::get_singleton()->agent_set_radius(agent, radius);
579
}
580
581
void NavigationAgent2D::set_neighbor_distance(real_t p_distance) {
582
if (Math::is_equal_approx(neighbor_distance, p_distance)) {
583
return;
584
}
585
586
neighbor_distance = p_distance;
587
588
NavigationServer2D::get_singleton()->agent_set_neighbor_distance(agent, neighbor_distance);
589
}
590
591
void NavigationAgent2D::set_max_neighbors(int p_count) {
592
if (max_neighbors == p_count) {
593
return;
594
}
595
596
max_neighbors = p_count;
597
598
NavigationServer2D::get_singleton()->agent_set_max_neighbors(agent, max_neighbors);
599
}
600
601
void NavigationAgent2D::set_time_horizon_agents(real_t p_time_horizon) {
602
ERR_FAIL_COND_MSG(p_time_horizon < 0.0, "Time horizon must be positive.");
603
if (Math::is_equal_approx(time_horizon_agents, p_time_horizon)) {
604
return;
605
}
606
time_horizon_agents = p_time_horizon;
607
NavigationServer2D::get_singleton()->agent_set_time_horizon_agents(agent, time_horizon_agents);
608
}
609
610
void NavigationAgent2D::set_time_horizon_obstacles(real_t p_time_horizon) {
611
ERR_FAIL_COND_MSG(p_time_horizon < 0.0, "Time horizon must be positive.");
612
if (Math::is_equal_approx(time_horizon_obstacles, p_time_horizon)) {
613
return;
614
}
615
time_horizon_obstacles = p_time_horizon;
616
NavigationServer2D::get_singleton()->agent_set_time_horizon_obstacles(agent, time_horizon_obstacles);
617
}
618
619
void NavigationAgent2D::set_max_speed(real_t p_max_speed) {
620
ERR_FAIL_COND_MSG(p_max_speed < 0.0, "Max speed must be positive.");
621
if (Math::is_equal_approx(max_speed, p_max_speed)) {
622
return;
623
}
624
max_speed = p_max_speed;
625
626
NavigationServer2D::get_singleton()->agent_set_max_speed(agent, max_speed);
627
}
628
629
void NavigationAgent2D::set_path_max_distance(real_t p_path_max_distance) {
630
if (Math::is_equal_approx(path_max_distance, p_path_max_distance)) {
631
return;
632
}
633
634
path_max_distance = p_path_max_distance;
635
}
636
637
real_t NavigationAgent2D::get_path_max_distance() {
638
return path_max_distance;
639
}
640
641
void NavigationAgent2D::set_target_position(Vector2 p_position) {
642
// Intentionally not checking for equality of the parameter, as we want to update the path even if the target position is the same in case the world changed.
643
// Revisit later when the navigation server can update the path without requesting a new path.
644
645
target_position = p_position;
646
target_position_submitted = true;
647
648
_request_repath();
649
}
650
651
Vector2 NavigationAgent2D::get_target_position() const {
652
return target_position;
653
}
654
655
Vector2 NavigationAgent2D::get_next_path_position() {
656
_update_navigation();
657
658
const Vector<Vector2> &navigation_path = navigation_result->get_path();
659
if (navigation_path.is_empty()) {
660
ERR_FAIL_NULL_V_MSG(agent_parent, Vector2(), "The agent has no parent.");
661
return agent_parent->get_global_position();
662
} else {
663
return navigation_path[navigation_path_index];
664
}
665
}
666
667
real_t NavigationAgent2D::distance_to_target() const {
668
ERR_FAIL_NULL_V_MSG(agent_parent, 0.0, "The agent has no parent.");
669
return agent_parent->get_global_position().distance_to(target_position);
670
}
671
672
bool NavigationAgent2D::is_target_reached() const {
673
return target_reached;
674
}
675
676
bool NavigationAgent2D::is_target_reachable() {
677
_update_navigation();
678
return _is_target_reachable();
679
}
680
681
bool NavigationAgent2D::_is_target_reachable() const {
682
return target_desired_distance >= _get_final_position().distance_to(target_position);
683
}
684
685
bool NavigationAgent2D::is_navigation_finished() {
686
_update_navigation();
687
return navigation_finished;
688
}
689
690
Vector2 NavigationAgent2D::get_final_position() {
691
_update_navigation();
692
return _get_final_position();
693
}
694
695
Vector2 NavigationAgent2D::_get_final_position() const {
696
const Vector<Vector2> &navigation_path = navigation_result->get_path();
697
if (navigation_path.is_empty()) {
698
return Vector2();
699
}
700
return navigation_path[navigation_path.size() - 1];
701
}
702
703
void NavigationAgent2D::set_velocity_forced(Vector2 p_velocity) {
704
// Intentionally not checking for equality of the parameter.
705
// We need to always submit the velocity to the navigation server, even when it is the same, in order to run avoidance every frame.
706
// Revisit later when the navigation server can update avoidance without users resubmitting the velocity.
707
708
velocity_forced = p_velocity;
709
velocity_forced_submitted = true;
710
}
711
712
void NavigationAgent2D::set_velocity(const Vector2 p_velocity) {
713
velocity = p_velocity;
714
velocity_submitted = true;
715
}
716
717
void NavigationAgent2D::_avoidance_done(Vector2 p_new_velocity) {
718
safe_velocity = p_new_velocity;
719
emit_signal(SNAME("velocity_computed"), safe_velocity);
720
}
721
722
PackedStringArray NavigationAgent2D::get_configuration_warnings() const {
723
PackedStringArray warnings = Node::get_configuration_warnings();
724
725
if (!Object::cast_to<Node2D>(get_parent())) {
726
warnings.push_back(RTR("The NavigationAgent2D can be used only under a Node2D inheriting parent node."));
727
}
728
729
return warnings;
730
}
731
732
void NavigationAgent2D::_update_navigation() {
733
if (agent_parent == nullptr) {
734
return;
735
}
736
if (!agent_parent->is_inside_tree()) {
737
return;
738
}
739
if (!target_position_submitted) {
740
return;
741
}
742
743
Vector2 origin = agent_parent->get_global_position();
744
745
bool reload_path = false;
746
747
if (NavigationServer2D::get_singleton()->agent_is_map_changed(agent)) {
748
reload_path = true;
749
} else if (navigation_result->get_path().is_empty()) {
750
reload_path = true;
751
} else {
752
// Check if too far from the navigation path
753
if (navigation_path_index > 0) {
754
const Vector<Vector2> &navigation_path = navigation_result->get_path();
755
756
const Vector2 segment_a = navigation_path[navigation_path_index - 1];
757
const Vector2 segment_b = navigation_path[navigation_path_index];
758
Vector2 p = Geometry2D::get_closest_point_to_segment(origin, segment_a, segment_b);
759
if (origin.distance_to(p) >= path_max_distance) {
760
// To faraway, reload path
761
reload_path = true;
762
}
763
}
764
}
765
766
if (reload_path) {
767
navigation_query->set_start_position(origin);
768
navigation_query->set_target_position(target_position);
769
navigation_query->set_navigation_layers(navigation_layers);
770
navigation_query->set_metadata_flags(path_metadata_flags);
771
772
if (map_override.is_valid()) {
773
navigation_query->set_map(map_override);
774
} else {
775
navigation_query->set_map(agent_parent->get_world_2d()->get_navigation_map());
776
}
777
778
NavigationServer2D::get_singleton()->query_path(navigation_query, navigation_result);
779
#ifdef DEBUG_ENABLED
780
debug_path_dirty = true;
781
#endif // DEBUG_ENABLED
782
navigation_finished = false;
783
last_waypoint_reached = false;
784
navigation_path_index = 0;
785
emit_signal(SNAME("path_changed"));
786
}
787
788
if (navigation_result->get_path().is_empty()) {
789
return;
790
}
791
792
// Check if the navigation has already finished.
793
if (navigation_finished) {
794
return;
795
}
796
797
// Check if we reached the target.
798
if (_is_within_target_distance(origin)) {
799
// Emit waypoint_reached in case we also moved within distance of a waypoint.
800
_advance_waypoints(origin);
801
_transition_to_target_reached();
802
_transition_to_navigation_finished();
803
} else {
804
// Advance waypoints if possible.
805
_advance_waypoints(origin);
806
// Keep navigation running even after reaching the last waypoint if the target is reachable.
807
if (last_waypoint_reached && !_is_target_reachable()) {
808
_transition_to_navigation_finished();
809
}
810
}
811
}
812
813
void NavigationAgent2D::_advance_waypoints(const Vector2 &p_origin) {
814
if (last_waypoint_reached) {
815
return;
816
}
817
818
// Advance to the farthest possible waypoint.
819
while (_is_within_waypoint_distance(p_origin)) {
820
_trigger_waypoint_reached();
821
822
if (_is_last_waypoint()) {
823
last_waypoint_reached = true;
824
break;
825
}
826
827
_move_to_next_waypoint();
828
}
829
}
830
831
void NavigationAgent2D::_request_repath() {
832
navigation_result->reset();
833
target_reached = false;
834
navigation_finished = false;
835
last_waypoint_reached = false;
836
}
837
838
bool NavigationAgent2D::_is_last_waypoint() const {
839
return navigation_path_index == navigation_result->get_path().size() - 1;
840
}
841
842
void NavigationAgent2D::_move_to_next_waypoint() {
843
navigation_path_index += 1;
844
}
845
846
bool NavigationAgent2D::_is_within_waypoint_distance(const Vector2 &p_origin) const {
847
const Vector<Vector2> &navigation_path = navigation_result->get_path();
848
return p_origin.distance_to(navigation_path[navigation_path_index]) < path_desired_distance;
849
}
850
851
bool NavigationAgent2D::_is_within_target_distance(const Vector2 &p_origin) const {
852
return p_origin.distance_to(target_position) < target_desired_distance;
853
}
854
855
void NavigationAgent2D::_trigger_waypoint_reached() {
856
const Vector<Vector2> &navigation_path = navigation_result->get_path();
857
const Vector<int32_t> &navigation_path_types = navigation_result->get_path_types();
858
const TypedArray<RID> &navigation_path_rids = navigation_result->get_path_rids();
859
const Vector<int64_t> &navigation_path_owners = navigation_result->get_path_owner_ids();
860
861
Dictionary details;
862
863
const Vector2 waypoint = navigation_path[navigation_path_index];
864
details[CoreStringName(position)] = waypoint;
865
866
int waypoint_type = -1;
867
if (path_metadata_flags.has_flag(NavigationPathQueryParameters2D::PathMetadataFlags::PATH_METADATA_INCLUDE_TYPES)) {
868
const NavigationPathQueryResult2D::PathSegmentType type = NavigationPathQueryResult2D::PathSegmentType(navigation_path_types[navigation_path_index]);
869
870
details[SNAME("type")] = type;
871
waypoint_type = type;
872
}
873
874
if (path_metadata_flags.has_flag(NavigationPathQueryParameters2D::PathMetadataFlags::PATH_METADATA_INCLUDE_RIDS)) {
875
details[SNAME("rid")] = navigation_path_rids[navigation_path_index];
876
}
877
878
if (path_metadata_flags.has_flag(NavigationPathQueryParameters2D::PathMetadataFlags::PATH_METADATA_INCLUDE_OWNERS)) {
879
const ObjectID waypoint_owner_id = ObjectID(navigation_path_owners[navigation_path_index]);
880
881
// Get a reference to the owning object.
882
Object *owner = nullptr;
883
if (waypoint_owner_id.is_valid()) {
884
owner = ObjectDB::get_instance(waypoint_owner_id);
885
}
886
887
details[SNAME("owner")] = owner;
888
889
if (waypoint_type == NavigationPathQueryResult2D::PATH_SEGMENT_TYPE_LINK) {
890
const NavigationLink2D *navlink = Object::cast_to<NavigationLink2D>(owner);
891
if (navlink) {
892
Vector2 link_global_start_position = navlink->get_global_start_position();
893
Vector2 link_global_end_position = navlink->get_global_end_position();
894
if (waypoint.distance_to(link_global_start_position) < waypoint.distance_to(link_global_end_position)) {
895
details[SNAME("link_entry_position")] = link_global_start_position;
896
details[SNAME("link_exit_position")] = link_global_end_position;
897
} else {
898
details[SNAME("link_entry_position")] = link_global_end_position;
899
details[SNAME("link_exit_position")] = link_global_start_position;
900
}
901
}
902
}
903
}
904
905
// Emit a signal for the waypoint.
906
emit_signal(SNAME("waypoint_reached"), details);
907
908
// Emit a signal if we've reached a navigation link.
909
if (waypoint_type == NavigationPathQueryResult2D::PATH_SEGMENT_TYPE_LINK) {
910
emit_signal(SNAME("link_reached"), details);
911
}
912
}
913
914
void NavigationAgent2D::_transition_to_navigation_finished() {
915
navigation_finished = true;
916
target_position_submitted = false;
917
918
if (avoidance_enabled) {
919
NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position());
920
NavigationServer2D::get_singleton()->agent_set_velocity(agent, Vector2(0.0, 0.0));
921
NavigationServer2D::get_singleton()->agent_set_velocity_forced(agent, Vector2(0.0, 0.0));
922
}
923
924
emit_signal(SNAME("navigation_finished"));
925
}
926
927
void NavigationAgent2D::_transition_to_target_reached() {
928
target_reached = true;
929
emit_signal(SNAME("target_reached"));
930
}
931
932
void NavigationAgent2D::set_avoidance_layers(uint32_t p_layers) {
933
avoidance_layers = p_layers;
934
NavigationServer2D::get_singleton()->agent_set_avoidance_layers(get_rid(), avoidance_layers);
935
}
936
937
uint32_t NavigationAgent2D::get_avoidance_layers() const {
938
return avoidance_layers;
939
}
940
941
void NavigationAgent2D::set_avoidance_mask(uint32_t p_mask) {
942
avoidance_mask = p_mask;
943
NavigationServer2D::get_singleton()->agent_set_avoidance_mask(get_rid(), p_mask);
944
}
945
946
uint32_t NavigationAgent2D::get_avoidance_mask() const {
947
return avoidance_mask;
948
}
949
950
void NavigationAgent2D::set_avoidance_layer_value(int p_layer_number, bool p_value) {
951
ERR_FAIL_COND_MSG(p_layer_number < 1, "Avoidance layer number must be between 1 and 32 inclusive.");
952
ERR_FAIL_COND_MSG(p_layer_number > 32, "Avoidance layer number must be between 1 and 32 inclusive.");
953
uint32_t avoidance_layers_new = get_avoidance_layers();
954
if (p_value) {
955
avoidance_layers_new |= 1 << (p_layer_number - 1);
956
} else {
957
avoidance_layers_new &= ~(1 << (p_layer_number - 1));
958
}
959
set_avoidance_layers(avoidance_layers_new);
960
}
961
962
bool NavigationAgent2D::get_avoidance_layer_value(int p_layer_number) const {
963
ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Avoidance layer number must be between 1 and 32 inclusive.");
964
ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Avoidance layer number must be between 1 and 32 inclusive.");
965
return get_avoidance_layers() & (1 << (p_layer_number - 1));
966
}
967
968
void NavigationAgent2D::set_avoidance_mask_value(int p_mask_number, bool p_value) {
969
ERR_FAIL_COND_MSG(p_mask_number < 1, "Avoidance mask number must be between 1 and 32 inclusive.");
970
ERR_FAIL_COND_MSG(p_mask_number > 32, "Avoidance mask number must be between 1 and 32 inclusive.");
971
uint32_t mask = get_avoidance_mask();
972
if (p_value) {
973
mask |= 1 << (p_mask_number - 1);
974
} else {
975
mask &= ~(1 << (p_mask_number - 1));
976
}
977
set_avoidance_mask(mask);
978
}
979
980
bool NavigationAgent2D::get_avoidance_mask_value(int p_mask_number) const {
981
ERR_FAIL_COND_V_MSG(p_mask_number < 1, false, "Avoidance mask number must be between 1 and 32 inclusive.");
982
ERR_FAIL_COND_V_MSG(p_mask_number > 32, false, "Avoidance mask number must be between 1 and 32 inclusive.");
983
return get_avoidance_mask() & (1 << (p_mask_number - 1));
984
}
985
986
void NavigationAgent2D::set_avoidance_priority(real_t p_priority) {
987
ERR_FAIL_COND_MSG(p_priority < 0.0, "Avoidance priority must be between 0.0 and 1.0 inclusive.");
988
ERR_FAIL_COND_MSG(p_priority > 1.0, "Avoidance priority must be between 0.0 and 1.0 inclusive.");
989
avoidance_priority = p_priority;
990
NavigationServer2D::get_singleton()->agent_set_avoidance_priority(get_rid(), p_priority);
991
}
992
993
real_t NavigationAgent2D::get_avoidance_priority() const {
994
return avoidance_priority;
995
}
996
997
////////DEBUG////////////////////////////////////////////////////////////
998
999
void NavigationAgent2D::set_debug_enabled(bool p_enabled) {
1000
#ifdef DEBUG_ENABLED
1001
if (debug_enabled == p_enabled) {
1002
return;
1003
}
1004
1005
debug_enabled = p_enabled;
1006
debug_path_dirty = true;
1007
#endif // DEBUG_ENABLED
1008
}
1009
1010
bool NavigationAgent2D::get_debug_enabled() const {
1011
return debug_enabled;
1012
}
1013
1014
void NavigationAgent2D::set_debug_use_custom(bool p_enabled) {
1015
#ifdef DEBUG_ENABLED
1016
if (debug_use_custom == p_enabled) {
1017
return;
1018
}
1019
1020
debug_use_custom = p_enabled;
1021
debug_path_dirty = true;
1022
#endif // DEBUG_ENABLED
1023
}
1024
1025
bool NavigationAgent2D::get_debug_use_custom() const {
1026
return debug_use_custom;
1027
}
1028
1029
void NavigationAgent2D::set_debug_path_custom_color(Color p_color) {
1030
#ifdef DEBUG_ENABLED
1031
if (debug_path_custom_color == p_color) {
1032
return;
1033
}
1034
1035
debug_path_custom_color = p_color;
1036
debug_path_dirty = true;
1037
#endif // DEBUG_ENABLED
1038
}
1039
1040
Color NavigationAgent2D::get_debug_path_custom_color() const {
1041
return debug_path_custom_color;
1042
}
1043
1044
void NavigationAgent2D::set_debug_path_custom_point_size(float p_point_size) {
1045
#ifdef DEBUG_ENABLED
1046
if (Math::is_equal_approx(debug_path_custom_point_size, p_point_size)) {
1047
return;
1048
}
1049
1050
debug_path_custom_point_size = MAX(0.0, p_point_size);
1051
debug_path_dirty = true;
1052
#endif // DEBUG_ENABLED
1053
}
1054
1055
float NavigationAgent2D::get_debug_path_custom_point_size() const {
1056
return debug_path_custom_point_size;
1057
}
1058
1059
void NavigationAgent2D::set_debug_path_custom_line_width(float p_line_width) {
1060
#ifdef DEBUG_ENABLED
1061
if (Math::is_equal_approx(debug_path_custom_line_width, p_line_width)) {
1062
return;
1063
}
1064
1065
debug_path_custom_line_width = p_line_width;
1066
debug_path_dirty = true;
1067
#endif // DEBUG_ENABLED
1068
}
1069
1070
float NavigationAgent2D::get_debug_path_custom_line_width() const {
1071
return debug_path_custom_line_width;
1072
}
1073
1074
#ifdef DEBUG_ENABLED
1075
void NavigationAgent2D::_navigation_debug_changed() {
1076
debug_path_dirty = true;
1077
}
1078
1079
void NavigationAgent2D::_update_debug_path() {
1080
if (!debug_path_dirty) {
1081
return;
1082
}
1083
debug_path_dirty = false;
1084
1085
if (!debug_path_instance.is_valid()) {
1086
debug_path_instance = RenderingServer::get_singleton()->canvas_item_create();
1087
}
1088
1089
RenderingServer::get_singleton()->canvas_item_clear(debug_path_instance);
1090
1091
if (!(debug_enabled && NavigationServer2D::get_singleton()->get_debug_navigation_enable_agent_paths())) {
1092
return;
1093
}
1094
1095
if (!(agent_parent && agent_parent->is_inside_tree())) {
1096
return;
1097
}
1098
1099
RenderingServer::get_singleton()->canvas_item_set_parent(debug_path_instance, agent_parent->get_canvas());
1100
RenderingServer::get_singleton()->canvas_item_set_z_index(debug_path_instance, RS::CANVAS_ITEM_Z_MAX - 1);
1101
RenderingServer::get_singleton()->canvas_item_set_visible(debug_path_instance, agent_parent->is_visible_in_tree());
1102
1103
const Vector<Vector2> &navigation_path = navigation_result->get_path();
1104
1105
if (navigation_path.size() <= 1) {
1106
return;
1107
}
1108
1109
Color debug_path_color = NavigationServer2D::get_singleton()->get_debug_navigation_agent_path_color();
1110
if (debug_use_custom) {
1111
debug_path_color = debug_path_custom_color;
1112
}
1113
1114
Vector<Color> debug_path_colors;
1115
debug_path_colors.resize(navigation_path.size());
1116
debug_path_colors.fill(debug_path_color);
1117
1118
RenderingServer::get_singleton()->canvas_item_add_polyline(debug_path_instance, navigation_path, debug_path_colors, debug_path_custom_line_width, false);
1119
1120
if (debug_path_custom_point_size <= 0.0) {
1121
return;
1122
}
1123
1124
float point_size = NavigationServer2D::get_singleton()->get_debug_navigation_agent_path_point_size();
1125
float half_point_size = point_size * 0.5;
1126
1127
if (debug_use_custom) {
1128
point_size = debug_path_custom_point_size;
1129
half_point_size = debug_path_custom_point_size * 0.5;
1130
}
1131
1132
for (int i = 0; i < navigation_path.size(); i++) {
1133
const Vector2 &vert = navigation_path[i];
1134
Rect2 path_point_rect = Rect2(vert.x - half_point_size, vert.y - half_point_size, point_size, point_size);
1135
RenderingServer::get_singleton()->canvas_item_add_rect(debug_path_instance, path_point_rect, debug_path_color);
1136
}
1137
}
1138
#endif // DEBUG_ENABLED
1139
1140