diff --git a/doc/classes/NavigationAgent.xml b/doc/classes/NavigationAgent.xml index ae65dfd6f96..906e79322fd 100644 --- a/doc/classes/NavigationAgent.xml +++ b/doc/classes/NavigationAgent.xml @@ -40,6 +40,12 @@ Returns the [Navigation] node that the agent is using for its navigation system. + + + + Returns the [RID] of the navigation map for this NavigationAgent node. This function returns always the map set on the NavigationAgent node and not the map of the abstract agent on the NavigationServer. If the agent map is changed directly with the NavigationServer API the NavigationAgent node will not be aware of the map change. Use [method set_navigation_map] to change the navigation map for the NavigationAgent and also update the agent on the NavigationServer. + + @@ -83,6 +89,13 @@ Sets the [Navigation] node used by the agent. Useful when you don't want to make the agent a child of a [Navigation] node. + + + + + Sets the [RID] of the navigation map this NavigationAgent node should use and also updates the [code]agent[/code] on the NavigationServer. + + diff --git a/doc/classes/NavigationAgent2D.xml b/doc/classes/NavigationAgent2D.xml index 1fcdacd35c5..0d09ba388ca 100644 --- a/doc/classes/NavigationAgent2D.xml +++ b/doc/classes/NavigationAgent2D.xml @@ -40,6 +40,12 @@ Returns the [Navigation2D] node that the agent is using for its navigation system. + + + + Returns the [RID] of the navigation map for this NavigationAgent node. This function returns always the map set on the NavigationAgent node and not the map of the abstract agent on the NavigationServer. If the agent map is changed directly with the NavigationServer API the NavigationAgent node will not be aware of the map change. Use [method set_navigation_map] to change the navigation map for the NavigationAgent and also update the agent on the NavigationServer. + + @@ -83,6 +89,13 @@ Sets the [Navigation2D] node used by the agent. Useful when you don't want to make the agent a child of a [Navigation2D] node. + + + + + Sets the [RID] of the navigation map this NavigationAgent node should use and also updates the [code]agent[/code] on the NavigationServer. + + diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp index b35b3967434..9e1a058dd9d 100644 --- a/scene/2d/navigation_agent_2d.cpp +++ b/scene/2d/navigation_agent_2d.cpp @@ -67,6 +67,9 @@ void NavigationAgent2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_navigation_layers", "navigation_layers"), &NavigationAgent2D::set_navigation_layers); ClassDB::bind_method(D_METHOD("get_navigation_layers"), &NavigationAgent2D::get_navigation_layers); + ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationAgent2D::set_navigation_map); + ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationAgent2D::get_navigation_map); + ClassDB::bind_method(D_METHOD("set_target_location", "location"), &NavigationAgent2D::set_target_location); ClassDB::bind_method(D_METHOD("get_target_location"), &NavigationAgent2D::get_target_location); ClassDB::bind_method(D_METHOD("get_next_location"), &NavigationAgent2D::get_next_location); @@ -156,12 +159,9 @@ void NavigationAgent2D::_notification(int p_what) { } } break; case NOTIFICATION_EXIT_TREE: { - agent_parent = nullptr; + set_agent_parent(nullptr); set_navigation(nullptr); set_physics_process_internal(false); - // Want to call ready again when the node enters the tree again. We're not using enter_tree notification because - // the navigation map may not be ready at that time. This fixes issues with taking the agent out of the scene tree. - request_ready(); } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { if (agent_parent) { @@ -218,11 +218,13 @@ void NavigationAgent2D::set_agent_parent(Node *p_agent_parent) { if (Object::cast_to(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(p_agent_parent); - if (navigation == nullptr) { + if (map_override.is_valid()) { + Navigation2DServer::get_singleton()->agent_set_map(get_rid(), map_override); + } else if (navigation != nullptr) { + Navigation2DServer::get_singleton()->agent_set_map(get_rid(), navigation->get_rid()); + } else { // no navigation node found in parent nodes, use default navigation map from world resource Navigation2DServer::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world_2d()->get_navigation_map()); - } else { - Navigation2DServer::get_singleton()->agent_set_map(get_rid(), navigation->get_rid()); } // create new avoidance callback if enabled set_avoidance_enabled(avoidance_enabled); @@ -263,6 +265,23 @@ uint32_t NavigationAgent2D::get_navigation_layers() const { return navigation_layers; } +void NavigationAgent2D::set_navigation_map(RID p_navigation_map) { + map_override = p_navigation_map; + Navigation2DServer::get_singleton()->agent_set_map(agent, map_override); + _request_repath(); +} + +RID NavigationAgent2D::get_navigation_map() const { + if (map_override.is_valid()) { + return map_override; + } else if (navigation != nullptr) { + return navigation->get_rid(); + } else if (agent_parent != nullptr) { + return agent_parent->get_world_2d()->get_navigation_map(); + } + return RID(); +} + void NavigationAgent2D::set_target_desired_distance(real_t p_dd) { target_desired_distance = p_dd; } @@ -377,7 +396,7 @@ void NavigationAgent2D::update_navigation() { if (agent_parent == nullptr) { return; } - if (navigation == nullptr) { + if (!agent_parent->is_inside_tree()) { return; } if (update_frame_id == Engine::get_singleton()->get_physics_frames()) { @@ -409,7 +428,13 @@ void NavigationAgent2D::update_navigation() { } if (reload_path) { - navigation_path = Navigation2DServer::get_singleton()->map_get_path(navigation->get_rid(), o, target_location, true, navigation_layers); + if (map_override.is_valid()) { + navigation_path = Navigation2DServer::get_singleton()->map_get_path(map_override, o, target_location, true, navigation_layers); + } else if (navigation != nullptr) { + navigation_path = Navigation2DServer::get_singleton()->map_get_path(navigation->get_rid(), o, target_location, true, navigation_layers); + } else { + navigation_path = Navigation2DServer::get_singleton()->map_get_path(agent_parent->get_world_2d()->get_navigation_map(), o, target_location, true, navigation_layers); + } navigation_finished = false; nav_path_index = 0; emit_signal("path_changed"); diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h index a6a7885777c..396354c67c7 100644 --- a/scene/2d/navigation_agent_2d.h +++ b/scene/2d/navigation_agent_2d.h @@ -45,6 +45,7 @@ class NavigationAgent2D : public Node { RID agent; RID map_before_pause; + RID map_override; bool avoidance_enabled = false; uint32_t navigation_layers = 1; @@ -98,6 +99,9 @@ public: void set_navigation_layers(uint32_t p_navigation_layers); uint32_t get_navigation_layers() const; + void set_navigation_map(RID p_navigation_map); + RID get_navigation_map() const; + void set_target_desired_distance(real_t p_dd); real_t get_target_desired_distance() const { return target_desired_distance; diff --git a/scene/3d/navigation_agent.cpp b/scene/3d/navigation_agent.cpp index e1354ab010c..e2419a8e851 100644 --- a/scene/3d/navigation_agent.cpp +++ b/scene/3d/navigation_agent.cpp @@ -73,6 +73,9 @@ void NavigationAgent::_bind_methods() { ClassDB::bind_method(D_METHOD("set_navigation_layers", "navigation_layers"), &NavigationAgent::set_navigation_layers); ClassDB::bind_method(D_METHOD("get_navigation_layers"), &NavigationAgent::get_navigation_layers); + ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationAgent::set_navigation_map); + ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationAgent::get_navigation_map); + ClassDB::bind_method(D_METHOD("set_target_location", "location"), &NavigationAgent::set_target_location); ClassDB::bind_method(D_METHOD("get_target_location"), &NavigationAgent::get_target_location); ClassDB::bind_method(D_METHOD("get_next_location"), &NavigationAgent::get_next_location); @@ -149,9 +152,6 @@ void NavigationAgent::_notification(int p_what) { set_agent_parent(nullptr); set_navigation(nullptr); set_physics_process_internal(false); - // Want to call ready again when the node enters the tree again. We're not using enter_tree notification because - // the navigation map may not be ready at that time. This fixes issues with taking the agent out of the scene tree. - request_ready(); } break; case NOTIFICATION_PAUSED: { @@ -240,11 +240,13 @@ void NavigationAgent::set_agent_parent(Node *p_agent_parent) { if (Object::cast_to(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(p_agent_parent); - if (navigation == nullptr) { + if (map_override.is_valid()) { + NavigationServer::get_singleton()->agent_set_map(get_rid(), map_override); + } else if (navigation != nullptr) { + NavigationServer::get_singleton()->agent_set_map(get_rid(), navigation->get_rid()); + } else { // no navigation node found in parent nodes, use default navigation map from world resource NavigationServer::get_singleton()->agent_set_map(get_rid(), agent_parent->get_world()->get_navigation_map()); - } else { - NavigationServer::get_singleton()->agent_set_map(get_rid(), navigation->get_rid()); } // create new avoidance callback if enabled set_avoidance_enabled(avoidance_enabled); @@ -266,6 +268,21 @@ uint32_t NavigationAgent::get_navigation_layers() const { return navigation_layers; } +void NavigationAgent::set_navigation_map(RID p_navigation_map) { + map_override = p_navigation_map; + NavigationServer::get_singleton()->agent_set_map(agent, map_override); + _request_repath(); +} + +RID NavigationAgent::get_navigation_map() const { + if (map_override.is_valid()) { + return map_override; + } else if (agent_parent != nullptr) { + return agent_parent->get_world()->get_navigation_map(); + } + return RID(); +} + void NavigationAgent::set_target_desired_distance(real_t p_dd) { target_desired_distance = p_dd; } @@ -422,10 +439,12 @@ void NavigationAgent::update_navigation() { } if (reload_path) { - if (navigation == nullptr) { - navigation_path = NavigationServer::get_singleton()->map_get_path(agent_parent->get_world()->get_navigation_map(), o, target_location, true, navigation_layers); - } else { + if (map_override.is_valid()) { + navigation_path = NavigationServer::get_singleton()->map_get_path(map_override, o, target_location, true, navigation_layers); + } else if (navigation != nullptr) { navigation_path = NavigationServer::get_singleton()->map_get_path(navigation->get_rid(), o, target_location, true, navigation_layers); + } else { + navigation_path = NavigationServer::get_singleton()->map_get_path(agent_parent->get_world()->get_navigation_map(), o, target_location, true, navigation_layers); } navigation_finished = false; nav_path_index = 0; diff --git a/scene/3d/navigation_agent.h b/scene/3d/navigation_agent.h index 0820b8872f0..17933199826 100644 --- a/scene/3d/navigation_agent.h +++ b/scene/3d/navigation_agent.h @@ -45,6 +45,7 @@ class NavigationAgent : public Node { RID agent; RID map_before_pause; + RID map_override; bool avoidance_enabled = false; uint32_t navigation_layers = 1; @@ -100,6 +101,9 @@ public: void set_navigation_layers(uint32_t p_navigation_layers); uint32_t get_navigation_layers() const; + void set_navigation_map(RID p_navigation_map); + RID get_navigation_map() const; + void set_target_desired_distance(real_t p_dd); real_t get_target_desired_distance() const { return target_desired_distance;