Fix NavigationObstacle 2D/3D (re)parent issues

Fixes (re)parent issues with NavigationObstacle 2D and 3D (same as NavigationAgents).
Also adds the option from NavigationAgents to override the default navigation map.
This commit is contained in:
smix8 2022-08-14 16:23:27 +02:00
parent e9e9e92e48
commit 5162d9ac8b
6 changed files with 122 additions and 22 deletions

View File

@ -10,12 +10,25 @@
<tutorials> <tutorials>
</tutorials> </tutorials>
<methods> <methods>
<method name="get_navigation_map" qualifiers="const">
<return type="RID" />
<description>
Returns the [RID] of the navigation map for this NavigationObstacle node. This function returns always the map set on the NavigationObstacle node and not the map of the abstract agent on the NavigationServer. If the agent map is changed directly with the NavigationServer API the NavigationObstacle node will not be aware of the map change. Use [method set_navigation_map] to change the navigation map for the NavigationObstacle and also update the agent on the NavigationServer.
</description>
</method>
<method name="get_rid" qualifiers="const"> <method name="get_rid" qualifiers="const">
<return type="RID" /> <return type="RID" />
<description> <description>
Returns the [RID] of this obstacle on the [NavigationServer2D]. Returns the [RID] of this obstacle on the [NavigationServer2D].
</description> </description>
</method> </method>
<method name="set_navigation_map">
<return type="void" />
<param index="0" name="navigation_map" type="RID" />
<description>
Sets the [RID] of the navigation map this NavigationObstacle node should use and also updates the [code]agent[/code] on the NavigationServer.
</description>
</method>
</methods> </methods>
<members> <members>
<member name="estimate_radius" type="bool" setter="set_estimate_radius" getter="is_radius_estimated" default="true"> <member name="estimate_radius" type="bool" setter="set_estimate_radius" getter="is_radius_estimated" default="true">

View File

@ -10,12 +10,25 @@
<tutorials> <tutorials>
</tutorials> </tutorials>
<methods> <methods>
<method name="get_navigation_map" qualifiers="const">
<return type="RID" />
<description>
Returns the [RID] of the navigation map for this NavigationObstacle node. This function returns always the map set on the NavigationObstacle node and not the map of the abstract agent on the NavigationServer. If the agent map is changed directly with the NavigationServer API the NavigationObstacle node will not be aware of the map change. Use [method set_navigation_map] to change the navigation map for the NavigationObstacle and also update the agent on the NavigationServer.
</description>
</method>
<method name="get_rid" qualifiers="const"> <method name="get_rid" qualifiers="const">
<return type="RID" /> <return type="RID" />
<description> <description>
Returns the [RID] of this obstacle on the [NavigationServer3D]. Returns the [RID] of this obstacle on the [NavigationServer3D].
</description> </description>
</method> </method>
<method name="set_navigation_map">
<return type="void" />
<param index="0" name="navigation_map" type="RID" />
<description>
Sets the [RID] of the navigation map this NavigationObstacle node should use and also updates the [code]agent[/code] on the NavigationServer.
</description>
</method>
</methods> </methods>
<members> <members>
<member name="estimate_radius" type="bool" setter="set_estimate_radius" getter="is_radius_estimated" default="true"> <member name="estimate_radius" type="bool" setter="set_estimate_radius" getter="is_radius_estimated" default="true">

View File

@ -38,6 +38,9 @@
void NavigationObstacle2D::_bind_methods() { void NavigationObstacle2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_rid"), &NavigationObstacle2D::get_rid); ClassDB::bind_method(D_METHOD("get_rid"), &NavigationObstacle2D::get_rid);
ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationObstacle2D::set_navigation_map);
ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationObstacle2D::get_navigation_map);
ClassDB::bind_method(D_METHOD("set_estimate_radius", "estimate_radius"), &NavigationObstacle2D::set_estimate_radius); ClassDB::bind_method(D_METHOD("set_estimate_radius", "estimate_radius"), &NavigationObstacle2D::set_estimate_radius);
ClassDB::bind_method(D_METHOD("is_radius_estimated"), &NavigationObstacle2D::is_radius_estimated); ClassDB::bind_method(D_METHOD("is_radius_estimated"), &NavigationObstacle2D::is_radius_estimated);
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &NavigationObstacle2D::set_radius); ClassDB::bind_method(D_METHOD("set_radius", "radius"), &NavigationObstacle2D::set_radius);
@ -57,28 +60,26 @@ void NavigationObstacle2D::_validate_property(PropertyInfo &p_property) const {
void NavigationObstacle2D::_notification(int p_what) { void NavigationObstacle2D::_notification(int p_what) {
switch (p_what) { switch (p_what) {
case NOTIFICATION_ENTER_TREE: { case NOTIFICATION_POST_ENTER_TREE: {
parent_node2d = Object::cast_to<Node2D>(get_parent()); set_agent_parent(get_parent());
reevaluate_agent_radius();
if (parent_node2d != 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(), parent_node2d->get_world_2d()->get_navigation_map());
}
set_physics_process_internal(true); set_physics_process_internal(true);
} break; } break;
case NOTIFICATION_EXIT_TREE: { case NOTIFICATION_EXIT_TREE: {
parent_node2d = nullptr; set_agent_parent(nullptr);
set_physics_process_internal(false); set_physics_process_internal(false);
} break; } break;
case NOTIFICATION_PARENTED: { case NOTIFICATION_PARENTED: {
parent_node2d = Object::cast_to<Node2D>(get_parent()); if (is_inside_tree() && (get_parent() != parent_node2d)) {
reevaluate_agent_radius(); set_agent_parent(get_parent());
set_physics_process_internal(true);
}
} break; } break;
case NOTIFICATION_UNPARENTED: { case NOTIFICATION_UNPARENTED: {
parent_node2d = nullptr; set_agent_parent(nullptr);
set_physics_process_internal(false);
} break; } break;
case NOTIFICATION_PAUSED: { case NOTIFICATION_PAUSED: {
@ -182,6 +183,35 @@ real_t NavigationObstacle2D::estimate_agent_radius() const {
return 1.0; // Never a 0 radius return 1.0; // Never a 0 radius
} }
void NavigationObstacle2D::set_agent_parent(Node *p_agent_parent) {
if (Object::cast_to<Node2D>(p_agent_parent) != nullptr) {
parent_node2d = Object::cast_to<Node2D>(p_agent_parent);
if (map_override.is_valid()) {
NavigationServer2D::get_singleton()->agent_set_map(get_rid(), map_override);
} else {
NavigationServer2D::get_singleton()->agent_set_map(get_rid(), parent_node2d->get_world_2d()->get_navigation_map());
}
reevaluate_agent_radius();
} else {
parent_node2d = nullptr;
NavigationServer2D::get_singleton()->agent_set_map(get_rid(), RID());
}
}
void NavigationObstacle2D::set_navigation_map(RID p_navigation_map) {
map_override = p_navigation_map;
NavigationServer2D::get_singleton()->agent_set_map(agent, map_override);
}
RID NavigationObstacle2D::get_navigation_map() const {
if (map_override.is_valid()) {
return map_override;
} else if (parent_node2d != nullptr) {
return parent_node2d->get_world_2d()->get_navigation_map();
}
return RID();
}
void NavigationObstacle2D::set_estimate_radius(bool p_estimate_radius) { void NavigationObstacle2D::set_estimate_radius(bool p_estimate_radius) {
estimate_radius = p_estimate_radius; estimate_radius = p_estimate_radius;
notify_property_list_changed(); notify_property_list_changed();

View File

@ -38,8 +38,10 @@ class NavigationObstacle2D : public Node {
GDCLASS(NavigationObstacle2D, Node); GDCLASS(NavigationObstacle2D, Node);
Node2D *parent_node2d = nullptr; Node2D *parent_node2d = nullptr;
RID agent; RID agent;
RID map_before_pause; RID map_before_pause;
RID map_override;
bool estimate_radius = true; bool estimate_radius = true;
real_t radius = 1.0; real_t radius = 1.0;
@ -57,6 +59,11 @@ public:
return agent; return agent;
} }
void set_agent_parent(Node *p_agent_parent);
void set_navigation_map(RID p_navigation_map);
RID get_navigation_map() const;
void set_estimate_radius(bool p_estimate_radius); void set_estimate_radius(bool p_estimate_radius);
bool is_radius_estimated() const { bool is_radius_estimated() const {
return estimate_radius; return estimate_radius;

View File

@ -37,6 +37,9 @@
void NavigationObstacle3D::_bind_methods() { void NavigationObstacle3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_rid"), &NavigationObstacle3D::get_rid); ClassDB::bind_method(D_METHOD("get_rid"), &NavigationObstacle3D::get_rid);
ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationObstacle3D::set_navigation_map);
ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationObstacle3D::get_navigation_map);
ClassDB::bind_method(D_METHOD("set_estimate_radius", "estimate_radius"), &NavigationObstacle3D::set_estimate_radius); ClassDB::bind_method(D_METHOD("set_estimate_radius", "estimate_radius"), &NavigationObstacle3D::set_estimate_radius);
ClassDB::bind_method(D_METHOD("is_radius_estimated"), &NavigationObstacle3D::is_radius_estimated); ClassDB::bind_method(D_METHOD("is_radius_estimated"), &NavigationObstacle3D::is_radius_estimated);
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &NavigationObstacle3D::set_radius); ClassDB::bind_method(D_METHOD("set_radius", "radius"), &NavigationObstacle3D::set_radius);
@ -56,28 +59,26 @@ void NavigationObstacle3D::_validate_property(PropertyInfo &p_property) const {
void NavigationObstacle3D::_notification(int p_what) { void NavigationObstacle3D::_notification(int p_what) {
switch (p_what) { switch (p_what) {
case NOTIFICATION_ENTER_TREE: { case NOTIFICATION_POST_ENTER_TREE: {
parent_node3d = Object::cast_to<Node3D>(get_parent()); set_agent_parent(get_parent());
reevaluate_agent_radius();
if (parent_node3d != 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(), parent_node3d->get_world_3d()->get_navigation_map());
}
set_physics_process_internal(true); set_physics_process_internal(true);
} break; } break;
case NOTIFICATION_EXIT_TREE: { case NOTIFICATION_EXIT_TREE: {
parent_node3d = nullptr; set_agent_parent(nullptr);
set_physics_process_internal(false); set_physics_process_internal(false);
} break; } break;
case NOTIFICATION_PARENTED: { case NOTIFICATION_PARENTED: {
parent_node3d = Object::cast_to<Node3D>(get_parent()); if (is_inside_tree() && (get_parent() != parent_node3d)) {
reevaluate_agent_radius(); set_agent_parent(get_parent());
set_physics_process_internal(true);
}
} break; } break;
case NOTIFICATION_UNPARENTED: { case NOTIFICATION_UNPARENTED: {
parent_node3d = nullptr; set_agent_parent(nullptr);
set_physics_process_internal(false);
} break; } break;
case NOTIFICATION_PAUSED: { case NOTIFICATION_PAUSED: {
@ -189,6 +190,35 @@ real_t NavigationObstacle3D::estimate_agent_radius() const {
return 1.0; // Never a 0 radius return 1.0; // Never a 0 radius
} }
void NavigationObstacle3D::set_agent_parent(Node *p_agent_parent) {
if (Object::cast_to<Node3D>(p_agent_parent) != nullptr) {
parent_node3d = Object::cast_to<Node3D>(p_agent_parent);
if (map_override.is_valid()) {
NavigationServer3D::get_singleton()->agent_set_map(get_rid(), map_override);
} else {
NavigationServer3D::get_singleton()->agent_set_map(get_rid(), parent_node3d->get_world_3d()->get_navigation_map());
}
reevaluate_agent_radius();
} else {
parent_node3d = nullptr;
NavigationServer3D::get_singleton()->agent_set_map(get_rid(), RID());
}
}
void NavigationObstacle3D::set_navigation_map(RID p_navigation_map) {
map_override = p_navigation_map;
NavigationServer3D::get_singleton()->agent_set_map(agent, map_override);
}
RID NavigationObstacle3D::get_navigation_map() const {
if (map_override.is_valid()) {
return map_override;
} else if (parent_node3d != nullptr) {
return parent_node3d->get_world_3d()->get_navigation_map();
}
return RID();
}
void NavigationObstacle3D::set_estimate_radius(bool p_estimate_radius) { void NavigationObstacle3D::set_estimate_radius(bool p_estimate_radius) {
estimate_radius = p_estimate_radius; estimate_radius = p_estimate_radius;
notify_property_list_changed(); notify_property_list_changed();

View File

@ -37,8 +37,10 @@ class NavigationObstacle3D : public Node {
GDCLASS(NavigationObstacle3D, Node); GDCLASS(NavigationObstacle3D, Node);
Node3D *parent_node3d = nullptr; Node3D *parent_node3d = nullptr;
RID agent; RID agent;
RID map_before_pause; RID map_before_pause;
RID map_override;
bool estimate_radius = true; bool estimate_radius = true;
real_t radius = 1.0; real_t radius = 1.0;
@ -56,6 +58,11 @@ public:
return agent; return agent;
} }
void set_agent_parent(Node *p_agent_parent);
void set_navigation_map(RID p_navigation_map);
RID get_navigation_map() const;
void set_estimate_radius(bool p_estimate_radius); void set_estimate_radius(bool p_estimate_radius);
bool is_radius_estimated() const { bool is_radius_estimated() const {
return estimate_radius; return estimate_radius;