summaryrefslogtreecommitdiff
path: root/scene/3d/navigation_agent_3d.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/3d/navigation_agent_3d.cpp')
-rw-r--r--scene/3d/navigation_agent_3d.cpp84
1 files changed, 67 insertions, 17 deletions
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index fb80fe6348..947d6012d5 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -35,6 +35,9 @@
void NavigationAgent3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_rid"), &NavigationAgent3D::get_rid);
+ ClassDB::bind_method(D_METHOD("set_avoidance_enabled", "enabled"), &NavigationAgent3D::set_avoidance_enabled);
+ ClassDB::bind_method(D_METHOD("get_avoidance_enabled"), &NavigationAgent3D::get_avoidance_enabled);
+
ClassDB::bind_method(D_METHOD("set_target_desired_distance", "desired_distance"), &NavigationAgent3D::set_target_desired_distance);
ClassDB::bind_method(D_METHOD("get_target_desired_distance"), &NavigationAgent3D::get_target_desired_distance);
@@ -79,15 +82,16 @@ void NavigationAgent3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_avoidance_done", "new_velocity"), &NavigationAgent3D::_avoidance_done);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01"), "set_target_desired_distance", "get_target_desired_distance");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.1,100,0.01"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_height_offset", PROPERTY_HINT_RANGE, "-100.0,100,0.01"), "set_agent_height_offset", "get_agent_height_offset");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "neighbor_dist", PROPERTY_HINT_RANGE, "0.1,10000,0.01"), "set_neighbor_dist", "get_neighbor_dist");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:m"), "set_target_desired_distance", "get_target_desired_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:m"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_height_offset", PROPERTY_HINT_RANGE, "-100.0,100,0.01,suffix:m"), "set_agent_height_offset", "get_agent_height_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "neighbor_dist", PROPERTY_HINT_RANGE, "0.1,10000,0.01,suffix:m"), "set_neighbor_dist", "get_neighbor_dist");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_neighbors", PROPERTY_HINT_RANGE, "1,10000,1"), "set_max_neighbors", "get_max_neighbors");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_horizon", PROPERTY_HINT_RANGE, "0.01,100,0.01"), "set_time_horizon", "get_time_horizon");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_speed", PROPERTY_HINT_RANGE, "0.1,10000,0.01"), "set_max_speed", "get_max_speed");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "0.01,100,0.1"), "set_path_max_distance", "get_path_max_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_horizon", PROPERTY_HINT_RANGE, "0.01,100,0.01,suffix:s"), "set_time_horizon", "get_time_horizon");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_speed", PROPERTY_HINT_RANGE, "0.1,10000,0.01,suffix:m/s"), "set_max_speed", "get_max_speed");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "0.01,100,0.1,suffix:m"), "set_path_max_distance", "get_path_max_distance");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_y"), "set_ignore_y", "get_ignore_y");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "navigable_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigable_layers", "get_navigable_layers");
ADD_SIGNAL(MethodInfo("path_changed"));
@@ -98,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());
- NavigationServer3D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
- }
+ 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;
@@ -135,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;
@@ -157,6 +179,34 @@ NavigationAgent3D::~NavigationAgent3D() {
agent = RID(); // Pointless
}
+void NavigationAgent3D::set_avoidance_enabled(bool p_enabled) {
+ avoidance_enabled = p_enabled;
+ if (avoidance_enabled) {
+ NavigationServer3D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done");
+ } else {
+ NavigationServer3D::get_singleton()->agent_set_callback(agent, nullptr, "_avoidance_done");
+ }
+}
+
+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;
@@ -283,7 +333,7 @@ TypedArray<String> NavigationAgent3D::get_configuration_warnings() const {
TypedArray<String> warnings = Node::get_configuration_warnings();
if (!Object::cast_to<Node3D>(get_parent())) {
- warnings.push_back(RTR("The NavigationAgent3D can be used only under a spatial node."));
+ warnings.push_back(RTR("The NavigationAgent3D can be used only under a Node3D inheriting parent node."));
}
return warnings;