summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/NavigationServer2D.xml4
-rw-r--r--doc/classes/NavigationServer3D.xml4
-rw-r--r--scene/2d/navigation_agent_2d.cpp49
-rw-r--r--scene/2d/navigation_agent_2d.h2
-rw-r--r--scene/3d/navigation_agent_3d.cpp51
-rw-r--r--scene/3d/navigation_agent_3d.h2
6 files changed, 93 insertions, 19 deletions
diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml
index 928834101f..1994a7a4c4 100644
--- a/doc/classes/NavigationServer2D.xml
+++ b/doc/classes/NavigationServer2D.xml
@@ -5,7 +5,9 @@
</brief_description>
<description>
NavigationServer2D is the server responsible for all 2D navigation. It handles several objects, namely maps, regions and agents.
- Maps are made up of regions, which are made of navigation polygons. Together, they define the navigable areas in the 2D world. For two regions to be connected to each other, they must share a similar edge. An edge is considered connected to another if both of its two vertices are at a distance less than [code]edge_connection_margin[/code] to the respective other edge's vertex.
+ Maps are made up of regions, which are made of navigation polygons. Together, they define the navigable areas in the 2D world.
+ [b]Note:[/b] Most NavigationServer changes take effect after the next physics frame and not immediately. This includes all changes made to maps, regions or agents by navigation related Nodes in the SceneTree or made through scripts.
+ For two regions to be connected to each other, they must share a similar edge. An edge is considered connected to another if both of its two vertices are at a distance less than [code]edge_connection_margin[/code] to the respective other edge's vertex.
You may assign navigation layers to regions with [method NavigationServer2D.region_set_layers], which then can be checked upon when requesting a path with [method NavigationServer2D.map_get_path]. This allows allowing or forbidding some areas to 2D objects.
To use the collision avoidance system, you may use agents. You can set an agent's target velocity, then the servers will emit a callback with a modified velocity.
[b]Note:[/b] The collision avoidance system ignores regions. Using the modified velocity as-is might lead to pushing and agent outside of a navigable area. This is a limitation of the collision avoidance system, any more complex situation may require the use of the physics engine.
diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml
index 8c83fe5485..2a729e7108 100644
--- a/doc/classes/NavigationServer3D.xml
+++ b/doc/classes/NavigationServer3D.xml
@@ -5,7 +5,9 @@
</brief_description>
<description>
NavigationServer3D is the server responsible for all 3D navigation. It handles several objects, namely maps, regions and agents.
- Maps are made up of regions, which are made of navigation meshes. Together, they define the navigable areas in the 3D world. For two regions to be connected to each other, they must share a similar edge. An edge is considered connected to another if both of its two vertices are at a distance less than [code]edge_connection_margin[/code] to the respective other edge's vertex.
+ Maps are made up of regions, which are made of navigation meshes. Together, they define the navigable areas in the 3D world.
+ [b]Note:[/b] Most NavigationServer changes take effect after the next physics frame and not immediately. This includes all changes made to maps, regions or agents by navigation related Nodes in the SceneTree or made through scripts.
+ For two regions to be connected to each other, they must share a similar edge. An edge is considered connected to another if both of its two vertices are at a distance less than [code]edge_connection_margin[/code] to the respective other edge's vertex.
You may assign navigation layers to regions with [method NavigationServer3D.region_set_layers], which then can be checked upon when requesting a path with [method NavigationServer3D.map_get_path]. This allows allowing or forbidding some areas to 3D objects.
To use the collision avoidance system, you may use agents. You can set an agent's target velocity, then the servers will emit a callback with a modified velocity.
[b]Note:[/b] The collision avoidance system ignores regions. Using the modified velocity as-is might lead to pushing and agent outside of a navigable area. This is a limitation of the collision avoidance system, any more complex situation may require the use of the physics engine.
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index 00082b321e..80d60dca17 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -96,16 +96,30 @@ void NavigationAgent2D::_bind_methods() {
void NavigationAgent2D::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_READY: {
- agent_parent = Object::cast_to<Node2D>(get_parent());
- if (agent_parent != nullptr) {
- // place agent on navigation map first or else the RVO agent callback creation fails silently later
- NavigationServer2D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_2d()->get_navigation_map());
- set_avoidance_enabled(avoidance_enabled);
- }
+ case NOTIFICATION_POST_ENTER_TREE: {
+ // need to use POST_ENTER_TREE cause with normal ENTER_TREE not all required Nodes are ready.
+ // cannot use READY as ready does not get called if Node is readded to SceneTree
+ set_agent_parent(get_parent());
set_physics_process_internal(true);
} break;
+ case NOTIFICATION_PARENTED: {
+ if (is_inside_tree() && (get_parent() != agent_parent)) {
+ // only react to PARENTED notifications when already inside_tree and parent changed, e.g. users switch nodes around
+ // PARENTED notification fires also when Node is added in scripts to a parent
+ // this would spam transforms fails and world fails while Node is outside SceneTree
+ // when node gets reparented when joining the tree POST_ENTER_TREE takes care of this
+ set_agent_parent(get_parent());
+ set_physics_process_internal(true);
+ }
+ } break;
+
+ case NOTIFICATION_UNPARENTED: {
+ // if agent has no parent no point in processing it until reparented
+ set_agent_parent(nullptr);
+ set_physics_process_internal(false);
+ } break;
+
case NOTIFICATION_PAUSED: {
if (agent_parent && !agent_parent->can_process()) {
map_before_pause = NavigationServer2D::get_singleton()->agent_get_map(get_rid());
@@ -133,7 +147,11 @@ void NavigationAgent2D::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (agent_parent) {
- NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position());
+ if (avoidance_enabled) {
+ // agent_position on NavigationServer is avoidance only and has nothing to do with pathfinding
+ // no point in flooding NavigationServer queue with agent position updates that get send to the void if avoidance is not used
+ NavigationServer2D::get_singleton()->agent_set_position(agent, agent_parent->get_global_position());
+ }
_check_distance_to_target();
}
} break;
@@ -167,6 +185,21 @@ bool NavigationAgent2D::get_avoidance_enabled() const {
return avoidance_enabled;
}
+void NavigationAgent2D::set_agent_parent(Node *p_agent_parent) {
+ // remove agent from any avoidance map before changing parent or there will be leftovers on the RVO map
+ NavigationServer2D::get_singleton()->agent_set_callback(agent, nullptr, "_avoidance_done");
+ if (Object::cast_to<Node2D>(p_agent_parent) != nullptr) {
+ // place agent on navigation map first or else the RVO agent callback creation fails silently later
+ agent_parent = Object::cast_to<Node2D>(p_agent_parent);
+ NavigationServer2D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_2d()->get_navigation_map());
+ // create new avoidance callback if enabled
+ set_avoidance_enabled(avoidance_enabled);
+ } else {
+ agent_parent = nullptr;
+ NavigationServer2D::get_singleton()->agent_set_map(get_rid(), RID());
+ }
+}
+
void NavigationAgent2D::set_navigable_layers(uint32_t p_layers) {
bool layers_changed = navigable_layers != p_layers;
navigable_layers = p_layers;
diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h
index 5ab4cdba5d..c9983119d0 100644
--- a/scene/2d/navigation_agent_2d.h
+++ b/scene/2d/navigation_agent_2d.h
@@ -82,6 +82,8 @@ public:
void set_avoidance_enabled(bool p_enabled);
bool get_avoidance_enabled() const;
+ void set_agent_parent(Node *p_agent_parent);
+
void set_navigable_layers(uint32_t p_layers);
uint32_t get_navigable_layers() const;
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index 88f676d031..947d6012d5 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -102,18 +102,32 @@ void NavigationAgent3D::_bind_methods() {
void NavigationAgent3D::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_READY: {
- agent_parent = Object::cast_to<Node3D>(get_parent());
- if (agent_parent != nullptr) {
- // place agent on navigation map first or else the RVO agent callback creation fails silently later
- NavigationServer3D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_3d()->get_navigation_map());
- set_avoidance_enabled(avoidance_enabled);
- }
+ case NOTIFICATION_POST_ENTER_TREE: {
+ // need to use POST_ENTER_TREE cause with normal ENTER_TREE not all required Nodes are ready.
+ // cannot use READY as ready does not get called if Node is readded to SceneTree
+ set_agent_parent(get_parent());
set_physics_process_internal(true);
} break;
+ case NOTIFICATION_PARENTED: {
+ if (is_inside_tree() && (get_parent() != agent_parent)) {
+ // only react to PARENTED notifications when already inside_tree and parent changed, e.g. users switch nodes around
+ // PARENTED notification fires also when Node is added in scripts to a parent
+ // this would spam transforms fails and world fails while Node is outside SceneTree
+ // when node gets reparented when joining the tree POST_ENTER_TREE takes care of this
+ set_agent_parent(get_parent());
+ set_physics_process_internal(true);
+ }
+ } break;
+
+ case NOTIFICATION_UNPARENTED: {
+ // if agent has no parent no point in processing it until reparented
+ set_agent_parent(nullptr);
+ set_physics_process_internal(false);
+ } break;
+
case NOTIFICATION_EXIT_TREE: {
- agent_parent = nullptr;
+ set_agent_parent(nullptr);
set_physics_process_internal(false);
} break;
@@ -139,7 +153,11 @@ void NavigationAgent3D::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (agent_parent) {
- NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().origin);
+ if (avoidance_enabled) {
+ // agent_position on NavigationServer is avoidance only and has nothing to do with pathfinding
+ // no point in flooding NavigationServer queue with agent position updates that get send to the void if avoidance is not used
+ NavigationServer3D::get_singleton()->agent_set_position(agent, agent_parent->get_global_transform().origin);
+ }
_check_distance_to_target();
}
} break;
@@ -174,6 +192,21 @@ bool NavigationAgent3D::get_avoidance_enabled() const {
return avoidance_enabled;
}
+void NavigationAgent3D::set_agent_parent(Node *p_agent_parent) {
+ // remove agent from any avoidance map before changing parent or there will be leftovers on the RVO map
+ NavigationServer3D::get_singleton()->agent_set_callback(agent, nullptr, "_avoidance_done");
+ if (Object::cast_to<Node3D>(p_agent_parent) != nullptr) {
+ // place agent on navigation map first or else the RVO agent callback creation fails silently later
+ agent_parent = Object::cast_to<Node3D>(p_agent_parent);
+ NavigationServer3D::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_3d()->get_navigation_map());
+ // create new avoidance callback if enabled
+ set_avoidance_enabled(avoidance_enabled);
+ } else {
+ agent_parent = nullptr;
+ NavigationServer3D::get_singleton()->agent_set_map(get_rid(), RID());
+ }
+}
+
void NavigationAgent3D::set_navigable_layers(uint32_t p_layers) {
bool layers_changed = navigable_layers != p_layers;
navigable_layers = p_layers;
diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h
index 28bcffd5b4..633bf091d1 100644
--- a/scene/3d/navigation_agent_3d.h
+++ b/scene/3d/navigation_agent_3d.h
@@ -84,6 +84,8 @@ public:
void set_avoidance_enabled(bool p_enabled);
bool get_avoidance_enabled() const;
+ void set_agent_parent(Node *p_agent_parent);
+
void set_navigable_layers(uint32_t p_layers);
uint32_t get_navigable_layers() const;