Ported: [3.5] Add NavigationAgent2D/3D set_navigation_map() function

Add NavigationAgent2D/3D set_navigation_map() function. Also fixes some bugs from leftover code before the backport update.
- smix8
c6f9627c74
This commit is contained in:
Relintai 2022-07-29 10:34:10 +02:00
parent b7d07a4487
commit 2e0589f63a
6 changed files with 99 additions and 18 deletions

View File

@ -40,6 +40,12 @@
Returns the [Navigation] node that the agent is using for its navigation system.
</description>
</method>
<method name="get_navigation_map" qualifiers="const">
<return type="RID" />
<description>
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.
</description>
</method>
<method name="get_next_location">
<return type="Vector3" />
<description>
@ -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.
</description>
</method>
<method name="set_navigation_map">
<return type="void" />
<argument index="0" name="navigation_map" type="RID" />
<description>
Sets the [RID] of the navigation map this NavigationAgent node should use and also updates the [code]agent[/code] on the NavigationServer.
</description>
</method>
<method name="set_target_location">
<return type="void" />
<argument index="0" name="location" type="Vector3" />

View File

@ -40,6 +40,12 @@
Returns the [Navigation2D] node that the agent is using for its navigation system.
</description>
</method>
<method name="get_navigation_map" qualifiers="const">
<return type="RID" />
<description>
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.
</description>
</method>
<method name="get_next_location">
<return type="Vector2" />
<description>
@ -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.
</description>
</method>
<method name="set_navigation_map">
<return type="void" />
<argument index="0" name="navigation_map" type="RID" />
<description>
Sets the [RID] of the navigation map this NavigationAgent node should use and also updates the [code]agent[/code] on the NavigationServer.
</description>
</method>
<method name="set_target_location">
<return type="void" />
<argument index="0" name="location" type="Vector2" />

View File

@ -69,6 +69,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);
@ -157,12 +160,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) {
@ -227,11 +227,13 @@ void NavigationAgent2D::set_agent_parent(Node *p_agent_parent) {
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);
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);
@ -272,6 +274,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;
}
@ -386,7 +405,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()) {
@ -418,7 +437,14 @@ void NavigationAgent2D::update_navigation() {
}
if (reload_path) {
navigation_path = Navigation2DServer::get_singleton()->map_get_path(navigation->get_rid(), o, target_location, true);
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");

View File

@ -43,6 +43,7 @@ class NavigationAgent2D : public Node {
RID agent;
RID map_before_pause;
RID map_override;
bool avoidance_enabled;
uint32_t navigation_layers;
@ -96,6 +97,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;

View File

@ -57,6 +57,9 @@ void NavigationAgent::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_navigation", "navigation"), &NavigationAgent::set_navigation_node);
ClassDB::bind_method(D_METHOD("get_navigation"), &NavigationAgent::get_navigation_node);
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_neighbor_dist", "neighbor_dist"), &NavigationAgent::set_neighbor_dist);
ClassDB::bind_method(D_METHOD("get_neighbor_dist"), &NavigationAgent::get_neighbor_dist);
@ -150,9 +153,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: {
if (agent_parent && !agent_parent->can_process()) {
@ -254,12 +254,15 @@ void NavigationAgent::set_agent_parent(Node *p_agent_parent) {
if (Object::cast_to<Spatial>(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<Spatial>(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);
} else {
@ -280,6 +283,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;
}
@ -440,11 +458,14 @@ 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;
emit_signal("path_changed");

View File

@ -44,6 +44,7 @@ class NavigationAgent : public Node {
RID agent;
RID map_before_pause;
RID map_override;
bool avoidance_enabled;
uint32_t navigation_layers;
@ -99,6 +100,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;