Merge pull request #54104 from Scony/improve-navigation-obstacles
Improve NavigationObstacle3D usability
This commit is contained in:
commit
87ddc5bbbf
|
@ -8,4 +8,12 @@
|
||||||
</description>
|
</description>
|
||||||
<tutorials>
|
<tutorials>
|
||||||
</tutorials>
|
</tutorials>
|
||||||
|
<members>
|
||||||
|
<member name="estimate_radius" type="bool" setter="set_estimate_radius" getter="is_radius_estimated" default="true">
|
||||||
|
Enables radius estimation algorithm which uses parent's collision shapes to determine the obstacle radius.
|
||||||
|
</member>
|
||||||
|
<member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
|
||||||
|
The radius of the agent. Used only if [member estimate_radius] is set to false.
|
||||||
|
</member>
|
||||||
|
</members>
|
||||||
</class>
|
</class>
|
||||||
|
|
|
@ -8,4 +8,12 @@
|
||||||
</description>
|
</description>
|
||||||
<tutorials>
|
<tutorials>
|
||||||
</tutorials>
|
</tutorials>
|
||||||
|
<members>
|
||||||
|
<member name="estimate_radius" type="bool" setter="set_estimate_radius" getter="is_radius_estimated" default="true">
|
||||||
|
Enables radius estimation algorithm which uses parent's collision shapes to determine the obstacle radius.
|
||||||
|
</member>
|
||||||
|
<member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
|
||||||
|
The radius of the agent. Used only if [member estimate_radius] is set to false.
|
||||||
|
</member>
|
||||||
|
</members>
|
||||||
</class>
|
</class>
|
||||||
|
|
|
@ -34,19 +34,41 @@
|
||||||
#include "servers/navigation_server_2d.h"
|
#include "servers/navigation_server_2d.h"
|
||||||
|
|
||||||
void NavigationObstacle2D::_bind_methods() {
|
void NavigationObstacle2D::_bind_methods() {
|
||||||
|
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("set_radius", "radius"), &NavigationObstacle2D::set_radius);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_radius"), &NavigationObstacle2D::get_radius);
|
||||||
|
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "estimate_radius"), "set_estimate_radius", "is_radius_estimated");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,500,0.01"), "set_radius", "get_radius");
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavigationObstacle2D::_validate_property(PropertyInfo &p_property) const {
|
||||||
|
if (p_property.name == "radius") {
|
||||||
|
if (estimate_radius) {
|
||||||
|
p_property.usage = PROPERTY_USAGE_NOEDITOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavigationObstacle2D::_notification(int p_what) {
|
void NavigationObstacle2D::_notification(int p_what) {
|
||||||
switch (p_what) {
|
switch (p_what) {
|
||||||
case NOTIFICATION_READY: {
|
case NOTIFICATION_READY: {
|
||||||
|
initialize_agent();
|
||||||
|
parent_node2d = Object::cast_to<Node2D>(get_parent());
|
||||||
|
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_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());
|
parent_node2d = Object::cast_to<Node2D>(get_parent());
|
||||||
update_agent_shape();
|
reevaluate_agent_radius();
|
||||||
} break;
|
} break;
|
||||||
case NOTIFICATION_UNPARENTED: {
|
case NOTIFICATION_UNPARENTED: {
|
||||||
parent_node2d = nullptr;
|
parent_node2d = nullptr;
|
||||||
|
@ -78,7 +100,22 @@ TypedArray<String> NavigationObstacle2D::get_configuration_warnings() const {
|
||||||
return warnings;
|
return warnings;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavigationObstacle2D::update_agent_shape() {
|
void NavigationObstacle2D::initialize_agent() {
|
||||||
|
NavigationServer2D::get_singleton()->agent_set_neighbor_dist(agent, 0.0);
|
||||||
|
NavigationServer2D::get_singleton()->agent_set_max_neighbors(agent, 0);
|
||||||
|
NavigationServer2D::get_singleton()->agent_set_time_horizon(agent, 0.0);
|
||||||
|
NavigationServer2D::get_singleton()->agent_set_max_speed(agent, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavigationObstacle2D::reevaluate_agent_radius() {
|
||||||
|
if (!estimate_radius) {
|
||||||
|
NavigationServer2D::get_singleton()->agent_set_radius(agent, radius);
|
||||||
|
} else if (parent_node2d) {
|
||||||
|
NavigationServer2D::get_singleton()->agent_set_radius(agent, estimate_agent_radius());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
real_t NavigationObstacle2D::estimate_agent_radius() const {
|
||||||
if (parent_node2d) {
|
if (parent_node2d) {
|
||||||
// Estimate the radius of this physics body
|
// Estimate the radius of this physics body
|
||||||
real_t radius = 0.0;
|
real_t radius = 0.0;
|
||||||
|
@ -101,15 +138,21 @@ void NavigationObstacle2D::update_agent_shape() {
|
||||||
Vector2 s = parent_node2d->get_global_scale();
|
Vector2 s = parent_node2d->get_global_scale();
|
||||||
radius *= MAX(s.x, s.y);
|
radius *= MAX(s.x, s.y);
|
||||||
|
|
||||||
if (radius == 0.0) {
|
if (radius > 0.0) {
|
||||||
radius = 1.0; // Never a 0 radius
|
return radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the Agent as an object
|
|
||||||
NavigationServer2D::get_singleton()->agent_set_neighbor_dist(agent, 0.0);
|
|
||||||
NavigationServer2D::get_singleton()->agent_set_max_neighbors(agent, 0);
|
|
||||||
NavigationServer2D::get_singleton()->agent_set_time_horizon(agent, 0.0);
|
|
||||||
NavigationServer2D::get_singleton()->agent_set_radius(agent, radius);
|
|
||||||
NavigationServer2D::get_singleton()->agent_set_max_speed(agent, 0.0);
|
|
||||||
}
|
}
|
||||||
|
return 1.0; // Never a 0 radius
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavigationObstacle2D::set_estimate_radius(bool p_estimate_radius) {
|
||||||
|
estimate_radius = p_estimate_radius;
|
||||||
|
notify_property_list_changed();
|
||||||
|
reevaluate_agent_radius();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavigationObstacle2D::set_radius(real_t p_radius) {
|
||||||
|
ERR_FAIL_COND_MSG(p_radius <= 0.0, "Radius must be greater than 0.");
|
||||||
|
radius = p_radius;
|
||||||
|
reevaluate_agent_radius();
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,8 +40,12 @@ class NavigationObstacle2D : public Node {
|
||||||
Node2D *parent_node2d = nullptr;
|
Node2D *parent_node2d = nullptr;
|
||||||
RID agent;
|
RID agent;
|
||||||
|
|
||||||
|
bool estimate_radius = true;
|
||||||
|
real_t radius = 1.0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
void _validate_property(PropertyInfo &p_property) const override;
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -52,10 +56,21 @@ public:
|
||||||
return agent;
|
return agent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_estimate_radius(bool p_estimate_radius);
|
||||||
|
bool is_radius_estimated() const {
|
||||||
|
return estimate_radius;
|
||||||
|
}
|
||||||
|
void set_radius(real_t p_radius);
|
||||||
|
real_t get_radius() const {
|
||||||
|
return radius;
|
||||||
|
}
|
||||||
|
|
||||||
TypedArray<String> get_configuration_warnings() const override;
|
TypedArray<String> get_configuration_warnings() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void update_agent_shape();
|
void initialize_agent();
|
||||||
|
void reevaluate_agent_radius();
|
||||||
|
real_t estimate_agent_radius() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -35,19 +35,41 @@
|
||||||
#include "servers/navigation_server_3d.h"
|
#include "servers/navigation_server_3d.h"
|
||||||
|
|
||||||
void NavigationObstacle3D::_bind_methods() {
|
void NavigationObstacle3D::_bind_methods() {
|
||||||
|
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("set_radius", "radius"), &NavigationObstacle3D::set_radius);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_radius"), &NavigationObstacle3D::get_radius);
|
||||||
|
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "estimate_radius"), "set_estimate_radius", "is_radius_estimated");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.01,100,0.01"), "set_radius", "get_radius");
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavigationObstacle3D::_validate_property(PropertyInfo &p_property) const {
|
||||||
|
if (p_property.name == "radius") {
|
||||||
|
if (estimate_radius) {
|
||||||
|
p_property.usage = PROPERTY_USAGE_NOEDITOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavigationObstacle3D::_notification(int p_what) {
|
void NavigationObstacle3D::_notification(int p_what) {
|
||||||
switch (p_what) {
|
switch (p_what) {
|
||||||
case NOTIFICATION_READY: {
|
case NOTIFICATION_READY: {
|
||||||
|
initialize_agent();
|
||||||
|
parent_node3d = Object::cast_to<Node3D>(get_parent());
|
||||||
|
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_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());
|
parent_node3d = Object::cast_to<Node3D>(get_parent());
|
||||||
update_agent_shape();
|
reevaluate_agent_radius();
|
||||||
} break;
|
} break;
|
||||||
case NOTIFICATION_UNPARENTED: {
|
case NOTIFICATION_UNPARENTED: {
|
||||||
parent_node3d = nullptr;
|
parent_node3d = nullptr;
|
||||||
|
@ -86,7 +108,22 @@ TypedArray<String> NavigationObstacle3D::get_configuration_warnings() const {
|
||||||
return warnings;
|
return warnings;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavigationObstacle3D::update_agent_shape() {
|
void NavigationObstacle3D::initialize_agent() {
|
||||||
|
NavigationServer3D::get_singleton()->agent_set_neighbor_dist(agent, 0.0);
|
||||||
|
NavigationServer3D::get_singleton()->agent_set_max_neighbors(agent, 0);
|
||||||
|
NavigationServer3D::get_singleton()->agent_set_time_horizon(agent, 0.0);
|
||||||
|
NavigationServer3D::get_singleton()->agent_set_max_speed(agent, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavigationObstacle3D::reevaluate_agent_radius() {
|
||||||
|
if (!estimate_radius) {
|
||||||
|
NavigationServer3D::get_singleton()->agent_set_radius(agent, radius);
|
||||||
|
} else if (parent_node3d) {
|
||||||
|
NavigationServer3D::get_singleton()->agent_set_radius(agent, estimate_agent_radius());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
real_t NavigationObstacle3D::estimate_agent_radius() const {
|
||||||
if (parent_node3d) {
|
if (parent_node3d) {
|
||||||
// Estimate the radius of this physics body
|
// Estimate the radius of this physics body
|
||||||
real_t radius = 0.0;
|
real_t radius = 0.0;
|
||||||
|
@ -110,15 +147,21 @@ void NavigationObstacle3D::update_agent_shape() {
|
||||||
Vector3 s = parent_node3d->get_global_transform().basis.get_scale();
|
Vector3 s = parent_node3d->get_global_transform().basis.get_scale();
|
||||||
radius *= MAX(s.x, MAX(s.y, s.z));
|
radius *= MAX(s.x, MAX(s.y, s.z));
|
||||||
|
|
||||||
if (radius == 0.0) {
|
if (radius > 0.0) {
|
||||||
radius = 1.0; // Never a 0 radius
|
return radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the Agent as an object
|
|
||||||
NavigationServer3D::get_singleton()->agent_set_neighbor_dist(agent, 0.0);
|
|
||||||
NavigationServer3D::get_singleton()->agent_set_max_neighbors(agent, 0);
|
|
||||||
NavigationServer3D::get_singleton()->agent_set_time_horizon(agent, 0.0);
|
|
||||||
NavigationServer3D::get_singleton()->agent_set_radius(agent, radius);
|
|
||||||
NavigationServer3D::get_singleton()->agent_set_max_speed(agent, 0.0);
|
|
||||||
}
|
}
|
||||||
|
return 1.0; // Never a 0 radius
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavigationObstacle3D::set_estimate_radius(bool p_estimate_radius) {
|
||||||
|
estimate_radius = p_estimate_radius;
|
||||||
|
notify_property_list_changed();
|
||||||
|
reevaluate_agent_radius();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NavigationObstacle3D::set_radius(real_t p_radius) {
|
||||||
|
ERR_FAIL_COND_MSG(p_radius <= 0.0, "Radius must be greater than 0.");
|
||||||
|
radius = p_radius;
|
||||||
|
reevaluate_agent_radius();
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,8 +39,12 @@ class NavigationObstacle3D : public Node {
|
||||||
Node3D *parent_node3d = nullptr;
|
Node3D *parent_node3d = nullptr;
|
||||||
RID agent;
|
RID agent;
|
||||||
|
|
||||||
|
bool estimate_radius = true;
|
||||||
|
real_t radius = 1.0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
void _validate_property(PropertyInfo &p_property) const override;
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -51,10 +55,21 @@ public:
|
||||||
return agent;
|
return agent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_estimate_radius(bool p_estimate_radius);
|
||||||
|
bool is_radius_estimated() const {
|
||||||
|
return estimate_radius;
|
||||||
|
}
|
||||||
|
void set_radius(real_t p_radius);
|
||||||
|
real_t get_radius() const {
|
||||||
|
return radius;
|
||||||
|
}
|
||||||
|
|
||||||
TypedArray<String> get_configuration_warnings() const override;
|
TypedArray<String> get_configuration_warnings() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void update_agent_shape();
|
void initialize_agent();
|
||||||
|
void reevaluate_agent_radius();
|
||||||
|
real_t estimate_agent_radius() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue