diff --git a/doc/classes/NavigationObstacle2D.xml b/doc/classes/NavigationObstacle2D.xml index e365d1aec55..2d94e0a0259 100644 --- a/doc/classes/NavigationObstacle2D.xml +++ b/doc/classes/NavigationObstacle2D.xml @@ -13,12 +13,6 @@ $DOCS_URL/tutorials/navigation/navigation_using_navigationobstacles.html - - - - Returns the [RID] of this agent on the [NavigationServer2D]. This [RID] is used for the moving avoidance "obstacle" component (using a fake avoidance agent) which size is defined by [member radius] and velocity set by using [member velocity]. - - @@ -32,10 +26,10 @@ 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 obstacle on the NavigationServer. If the obstacle 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 obstacle on the NavigationServer. - + - Returns the [RID] of this obstacle on the [NavigationServer2D]. This [RID] is used for the static avoidance obstacle component which shape is defined by [member vertices]. + Returns the [RID] of this obstacle on the [NavigationServer2D]. @@ -55,6 +49,9 @@ + + If [code]true[/code] the obstacle affects avoidance using agents. + A bitfield determining the avoidance layers for this obstacle. Agent's with a matching bit on the their avoidance mask will avoid this obstacle. diff --git a/doc/classes/NavigationObstacle3D.xml b/doc/classes/NavigationObstacle3D.xml index eb76d86fc01..2a921d3b8c1 100644 --- a/doc/classes/NavigationObstacle3D.xml +++ b/doc/classes/NavigationObstacle3D.xml @@ -13,12 +13,6 @@ $DOCS_URL/tutorials/navigation/navigation_using_navigationobstacles.html - - - - Returns the [RID] of this agent on the [NavigationServer3D]. This [RID] is used for the moving avoidance "obstacle" component (using a fake avoidance agent) which size is defined by [member radius] and velocity set by using [member velocity]. - - @@ -32,10 +26,10 @@ 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 obstacle on the NavigationServer. If the obstacle 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 obstacle on the NavigationServer. - + - Returns the [RID] of this obstacle on the [NavigationServer3D]. This [RID] is used for the static avoidance obstacle component which shape is defined by [member vertices]. + Returns the [RID] of this obstacle on the [NavigationServer3D]. @@ -55,6 +49,9 @@ + + If [code]true[/code] the obstacle affects avoidance using agents. + A bitfield determining the avoidance layers for this obstacle. Agent's with a matching bit on the their avoidance mask will avoid this obstacle. diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml index a487bb68c22..fb23d221274 100644 --- a/doc/classes/NavigationServer2D.xml +++ b/doc/classes/NavigationServer2D.xml @@ -464,6 +464,13 @@ Creates a new navigation obstacle. + + + + + Returns [code]true[/code] if the provided [param obstacle] has avoidance enabled. + + @@ -471,11 +478,20 @@ Returns the navigation map [RID] the requested [param obstacle] is currently assigned to. + + + + + + If [param enabled] the provided [param obstacle] affects avoidance using agents. + + + Set the obstacles's [code]avoidance_layers[/code] bitmask. @@ -494,6 +510,22 @@ Sets the position of the obstacle in world space. + + + + + + Sets the radius of the dynamic obstacle. + + + + + + + + Sets [param velocity] of the dynamic [param obstacle]. Allows other agents to better predict the movement of the dynamic obstacle. Only works in combination with the radius of the obstacle. + + diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml index f5221ad17d1..6f406aa629e 100644 --- a/doc/classes/NavigationServer3D.xml +++ b/doc/classes/NavigationServer3D.xml @@ -529,6 +529,13 @@ Creates a new obstacle. + + + + + Returns [code]true[/code] if the provided [param obstacle] has avoidance enabled. + + @@ -536,6 +543,21 @@ Returns the navigation map [RID] the requested [param obstacle] is currently assigned to. + + + + + Returns [code]true[/code] if the provided [param obstacle] uses avoidance in 3D space Vector3(x,y,z) instead of horizontal 2D Vector2(x,y) / Vector3(x,0.0,z). + + + + + + + + If [param enabled] the provided [param obstacle] affects avoidance using agents. + + @@ -568,6 +590,30 @@ Updates the [param position] in world space for the [param obstacle]. + + + + + + Sets the radius of the dynamic obstacle. + + + + + + + + Sets if the [param obstacle] uses the 2D avoidance or the 3D avoidance while avoidance is enabled. + + + + + + + + Sets [param velocity] of the dynamic [param obstacle]. Allows other agents to better predict the movement of the dynamic obstacle. Only works in combination with the radius of the obstacle. + + diff --git a/misc/extension_api_validation/4.0-stable.expected b/misc/extension_api_validation/4.0-stable.expected index 2bf64561d30..b96397adb51 100644 --- a/misc/extension_api_validation/4.0-stable.expected +++ b/misc/extension_api_validation/4.0-stable.expected @@ -85,11 +85,9 @@ Validate extension JSON: API was removed: classes/NavigationAgent3D/methods/set_ Validate extension JSON: API was removed: classes/NavigationAgent3D/properties/agent_height_offset Validate extension JSON: API was removed: classes/NavigationAgent3D/properties/ignore_y Validate extension JSON: API was removed: classes/NavigationAgent3D/properties/time_horizon -Validate extension JSON: API was removed: classes/NavigationObstacle2D/methods/get_rid Validate extension JSON: API was removed: classes/NavigationObstacle2D/methods/is_radius_estimated Validate extension JSON: API was removed: classes/NavigationObstacle2D/methods/set_estimate_radius Validate extension JSON: API was removed: classes/NavigationObstacle2D/properties/estimate_radius -Validate extension JSON: API was removed: classes/NavigationObstacle3D/methods/get_rid Validate extension JSON: API was removed: classes/NavigationObstacle3D/methods/is_radius_estimated Validate extension JSON: API was removed: classes/NavigationObstacle3D/methods/set_estimate_radius Validate extension JSON: API was removed: classes/NavigationObstacle3D/properties/estimate_radius diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp index b0b52a67325..c72b61014b7 100644 --- a/modules/navigation/godot_navigation_server.cpp +++ b/modules/navigation/godot_navigation_server.cpp @@ -802,9 +802,44 @@ RID GodotNavigationServer::obstacle_create() { RID rid = obstacle_owner.make_rid(); NavObstacle *obstacle = obstacle_owner.get_or_null(rid); obstacle->set_self(rid); + + RID agent_rid = agent_owner.make_rid(); + NavAgent *agent = agent_owner.get_or_null(agent_rid); + agent->set_self(agent_rid); + + obstacle->set_agent(agent); + return rid; } +COMMAND_2(obstacle_set_avoidance_enabled, RID, p_obstacle, bool, p_enabled) { + NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle); + ERR_FAIL_COND(obstacle == nullptr); + + obstacle->set_avoidance_enabled(p_enabled); +} + +bool GodotNavigationServer::obstacle_get_avoidance_enabled(RID p_obstacle) const { + NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle); + ERR_FAIL_COND_V(obstacle == nullptr, false); + + return obstacle->is_avoidance_enabled(); +} + +COMMAND_2(obstacle_set_use_3d_avoidance, RID, p_obstacle, bool, p_enabled) { + NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle); + ERR_FAIL_COND(obstacle == nullptr); + + obstacle->set_use_3d_avoidance(p_enabled); +} + +bool GodotNavigationServer::obstacle_get_use_3d_avoidance(RID p_obstacle) const { + NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle); + ERR_FAIL_COND_V(obstacle == nullptr, false); + + return obstacle->get_use_3d_avoidance(); +} + COMMAND_2(obstacle_set_map, RID, p_obstacle, RID, p_map) { NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle); ERR_FAIL_COND(obstacle == nullptr); @@ -837,12 +872,27 @@ RID GodotNavigationServer::obstacle_get_map(RID p_obstacle) const { return RID(); } +COMMAND_2(obstacle_set_radius, RID, p_obstacle, real_t, p_radius) { + ERR_FAIL_COND_MSG(p_radius < 0.0, "Radius must be positive."); + NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle); + ERR_FAIL_COND(obstacle == nullptr); + + obstacle->set_radius(p_radius); +} + COMMAND_2(obstacle_set_height, RID, p_obstacle, real_t, p_height) { NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle); ERR_FAIL_COND(obstacle == nullptr); obstacle->set_height(p_height); } +COMMAND_2(obstacle_set_velocity, RID, p_obstacle, Vector3, p_velocity) { + NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle); + ERR_FAIL_COND(obstacle == nullptr); + + obstacle->set_velocity(p_velocity); +} + COMMAND_2(obstacle_set_position, RID, p_obstacle, Vector3, p_position) { NavObstacle *obstacle = obstacle_owner.get_or_null(p_obstacle); ERR_FAIL_COND(obstacle == nullptr); @@ -917,29 +967,42 @@ COMMAND_1(free, RID, p_object) { link_owner.free(p_object); } else if (agent_owner.owns(p_object)) { - NavAgent *agent = agent_owner.get_or_null(p_object); + internal_free_agent(p_object); - // Removes this agent from the map if assigned + } else if (obstacle_owner.owns(p_object)) { + internal_free_obstacle(p_object); + + } else { + ERR_PRINT("Attempted to free a NavigationServer RID that did not exist (or was already freed)."); + } +} + +void GodotNavigationServer::internal_free_agent(RID p_object) { + NavAgent *agent = agent_owner.get_or_null(p_object); + if (agent) { if (agent->get_map() != nullptr) { agent->get_map()->remove_agent(agent); agent->set_map(nullptr); } - agent_owner.free(p_object); + } +} - } else if (obstacle_owner.owns(p_object)) { - NavObstacle *obstacle = obstacle_owner.get_or_null(p_object); - - // Removes this agent from the map if assigned +void GodotNavigationServer::internal_free_obstacle(RID p_object) { + NavObstacle *obstacle = obstacle_owner.get_or_null(p_object); + if (obstacle) { if (obstacle->get_map() != nullptr) { obstacle->get_map()->remove_obstacle(obstacle); obstacle->set_map(nullptr); } - + if (obstacle->get_agent()) { + if (obstacle->get_agent()->get_self() != RID()) { + RID _agent_rid = obstacle->get_agent()->get_self(); + obstacle->set_agent(nullptr); + internal_free_agent(_agent_rid); + } + } obstacle_owner.free(p_object); - - } else { - ERR_PRINT("Attempted to free a NavigationServer RID that did not exist (or was already freed)."); } } diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h index 5d68844a9b1..8c9b1eb1b19 100644 --- a/modules/navigation/godot_navigation_server.h +++ b/modules/navigation/godot_navigation_server.h @@ -198,8 +198,14 @@ public: COMMAND_2(agent_set_avoidance_priority, RID, p_agent, real_t, p_priority); virtual RID obstacle_create() override; + COMMAND_2(obstacle_set_avoidance_enabled, RID, p_obstacle, bool, p_enabled); + virtual bool obstacle_get_avoidance_enabled(RID p_obstacle) const override; + COMMAND_2(obstacle_set_use_3d_avoidance, RID, p_obstacle, bool, p_enabled); + virtual bool obstacle_get_use_3d_avoidance(RID p_obstacle) const override; COMMAND_2(obstacle_set_map, RID, p_obstacle, RID, p_map); virtual RID obstacle_get_map(RID p_obstacle) const override; + COMMAND_2(obstacle_set_radius, RID, p_obstacle, real_t, p_radius); + COMMAND_2(obstacle_set_velocity, RID, p_obstacle, Vector3, p_velocity); COMMAND_2(obstacle_set_position, RID, p_obstacle, Vector3, p_position); COMMAND_2(obstacle_set_height, RID, p_obstacle, real_t, p_height); virtual void obstacle_set_vertices(RID p_obstacle, const Vector &p_vertices) override; @@ -215,6 +221,10 @@ public: virtual NavigationUtilities::PathQueryResult _query_path(const NavigationUtilities::PathQueryParameters &p_parameters) const override; int get_process_info(ProcessInfo p_info) const override; + +private: + void internal_free_agent(RID p_object); + void internal_free_obstacle(RID p_object); }; #undef COMMAND_1 diff --git a/modules/navigation/nav_obstacle.cpp b/modules/navigation/nav_obstacle.cpp index 5d0bc59cbb2..4241ddcd795 100644 --- a/modules/navigation/nav_obstacle.cpp +++ b/modules/navigation/nav_obstacle.cpp @@ -30,38 +30,121 @@ #include "nav_obstacle.h" +#include "nav_agent.h" #include "nav_map.h" NavObstacle::NavObstacle() {} NavObstacle::~NavObstacle() {} +void NavObstacle::set_agent(NavAgent *p_agent) { + if (agent == p_agent) { + return; + } + + agent = p_agent; + + internal_update_agent(); +} + +void NavObstacle::set_avoidance_enabled(bool p_enabled) { + if (avoidance_enabled == p_enabled) { + return; + } + + avoidance_enabled = p_enabled; + obstacle_dirty = true; + + internal_update_agent(); +} + +void NavObstacle::set_use_3d_avoidance(bool p_enabled) { + if (use_3d_avoidance == p_enabled) { + return; + } + + use_3d_avoidance = p_enabled; + obstacle_dirty = true; + + if (agent) { + agent->set_use_3d_avoidance(use_3d_avoidance); + } +} + void NavObstacle::set_map(NavMap *p_map) { - if (map != p_map) { - map = p_map; - obstacle_dirty = true; + if (map == p_map) { + return; + } + + if (map) { + map->remove_obstacle(this); + if (agent) { + agent->set_map(nullptr); + } + } + + map = p_map; + obstacle_dirty = true; + + if (map) { + map->add_obstacle(this); + internal_update_agent(); } } void NavObstacle::set_position(const Vector3 p_position) { - if (position != p_position) { - position = p_position; - obstacle_dirty = true; + if (position == p_position) { + return; + } + + position = p_position; + obstacle_dirty = true; + + if (agent) { + agent->set_position(position); + } +} + +void NavObstacle::set_radius(real_t p_radius) { + if (radius == p_radius) { + return; + } + + radius = p_radius; + + if (agent) { + agent->set_radius(radius); } } void NavObstacle::set_height(const real_t p_height) { - if (height != p_height) { - height = p_height; - obstacle_dirty = true; + if (height == p_height) { + return; + } + + height = p_height; + obstacle_dirty = true; + + if (agent) { + agent->set_height(height); + } +} + +void NavObstacle::set_velocity(const Vector3 p_velocity) { + velocity = p_velocity; + + if (agent) { + agent->set_velocity(velocity); } } void NavObstacle::set_vertices(const Vector &p_vertices) { - if (vertices != p_vertices) { - vertices = p_vertices; - obstacle_dirty = true; + if (vertices == p_vertices) { + return; } + + vertices = p_vertices; + obstacle_dirty = true; } bool NavObstacle::is_map_changed() { @@ -75,8 +158,16 @@ bool NavObstacle::is_map_changed() { } void NavObstacle::set_avoidance_layers(uint32_t p_layers) { + if (avoidance_layers == p_layers) { + return; + } + avoidance_layers = p_layers; obstacle_dirty = true; + + if (agent) { + agent->set_avoidance_layers(avoidance_layers); + } } bool NavObstacle::check_dirty() { @@ -84,3 +175,22 @@ bool NavObstacle::check_dirty() { obstacle_dirty = false; return was_dirty; } + +void NavObstacle::internal_update_agent() { + if (agent) { + agent->set_neighbor_distance(0.0); + agent->set_max_neighbors(0.0); + agent->set_time_horizon_agents(0.0); + agent->set_time_horizon_obstacles(0.0); + agent->set_avoidance_mask(0.0); + agent->set_neighbor_distance(0.0); + agent->set_avoidance_priority(1.0); + agent->set_map(map); + agent->set_radius(radius); + agent->set_height(height); + agent->set_position(position); + agent->set_avoidance_layers(avoidance_layers); + agent->set_avoidance_enabled(avoidance_enabled); + agent->set_use_3d_avoidance(use_3d_avoidance); + } +} diff --git a/modules/navigation/nav_obstacle.h b/modules/navigation/nav_obstacle.h index f59eba5200d..93910898e9e 100644 --- a/modules/navigation/nav_obstacle.h +++ b/modules/navigation/nav_obstacle.h @@ -33,18 +33,23 @@ #include "core/object/class_db.h" #include "core/templates/local_vector.h" -#include "nav_agent.h" #include "nav_rid.h" +class NavAgent; class NavMap; class NavObstacle : public NavRid { + NavAgent *agent = nullptr; NavMap *map = nullptr; + Vector3 velocity; Vector3 position; Vector vertices; + real_t radius = 0.0; real_t height = 0.0; + bool avoidance_enabled = false; + bool use_3d_avoidance = false; uint32_t avoidance_layers = 1; bool obstacle_dirty = true; @@ -55,15 +60,30 @@ public: NavObstacle(); ~NavObstacle(); + void set_avoidance_enabled(bool p_enabled); + bool is_avoidance_enabled() { return avoidance_enabled; } + + void set_use_3d_avoidance(bool p_enabled); + bool get_use_3d_avoidance() { return use_3d_avoidance; } + void set_map(NavMap *p_map); NavMap *get_map() { return map; } + void set_agent(NavAgent *p_agent); + NavAgent *get_agent() { return agent; } + void set_position(const Vector3 p_position); const Vector3 &get_position() const { return position; } + void set_radius(real_t p_radius); + real_t get_radius() const { return radius; } + void set_height(const real_t p_height); real_t get_height() const { return height; } + void set_velocity(const Vector3 p_velocity); + const Vector3 &get_velocity() const { return velocity; } + void set_vertices(const Vector &p_vertices); const Vector &get_vertices() const { return vertices; } @@ -73,6 +93,9 @@ public: uint32_t get_avoidance_layers() const { return avoidance_layers; }; bool check_dirty(); + +private: + void internal_update_agent(); }; #endif // NAV_OBSTACLE_H diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp index d368a4d4369..3ee1260c0dc 100644 --- a/scene/2d/navigation_obstacle_2d.cpp +++ b/scene/2d/navigation_obstacle_2d.cpp @@ -36,8 +36,10 @@ #include "servers/navigation_server_3d.h" void NavigationObstacle2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_obstacle_rid"), &NavigationObstacle2D::get_obstacle_rid); - ClassDB::bind_method(D_METHOD("get_agent_rid"), &NavigationObstacle2D::get_agent_rid); + ClassDB::bind_method(D_METHOD("get_rid"), &NavigationObstacle2D::get_rid); + + ClassDB::bind_method(D_METHOD("set_avoidance_enabled", "enabled"), &NavigationObstacle2D::set_avoidance_enabled); + ClassDB::bind_method(D_METHOD("get_avoidance_enabled"), &NavigationObstacle2D::get_avoidance_enabled); 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); @@ -56,7 +58,8 @@ void NavigationObstacle2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_avoidance_layer_value", "layer_number", "value"), &NavigationObstacle2D::set_avoidance_layer_value); ClassDB::bind_method(D_METHOD("get_avoidance_layer_value", "layer_number"), &NavigationObstacle2D::get_avoidance_layer_value); - ADD_GROUP("Avoidance", "avoidance_"); + ADD_GROUP("Avoidance", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_velocity", "get_velocity"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.0,500,0.01,suffix:px"), "set_radius", "get_radius"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "vertices"), "set_vertices", "get_vertices"); @@ -75,7 +78,7 @@ void NavigationObstacle2D::_notification(int p_what) { } previous_transform = get_global_transform(); // need to trigger map controlled agent assignment somehow for the fake_agent since obstacles use no callback like regular agents - NavigationServer2D::get_singleton()->agent_set_avoidance_enabled(fake_agent, radius > 0); + NavigationServer2D::get_singleton()->obstacle_set_avoidance_enabled(obstacle, avoidance_enabled); _update_position(get_global_transform().get_origin()); set_physics_process_internal(true); } break; @@ -113,7 +116,7 @@ void NavigationObstacle2D::_notification(int p_what) { velocity_submitted = false; // only update if there is a noticeable change, else the rvo agent preferred velocity stays the same if (!previous_velocity.is_equal_approx(velocity)) { - NavigationServer2D::get_singleton()->agent_set_velocity(fake_agent, velocity); + NavigationServer2D::get_singleton()->obstacle_set_velocity(obstacle, velocity); } previous_velocity = velocity; } @@ -142,21 +145,11 @@ void NavigationObstacle2D::_notification(int p_what) { NavigationObstacle2D::NavigationObstacle2D() { obstacle = NavigationServer2D::get_singleton()->obstacle_create(); - fake_agent = NavigationServer2D::get_singleton()->agent_create(); - - // change properties of the fake agent so it can act as fake obstacle with a radius - NavigationServer2D::get_singleton()->agent_set_neighbor_distance(fake_agent, 0.0); - NavigationServer2D::get_singleton()->agent_set_max_neighbors(fake_agent, 0); - NavigationServer2D::get_singleton()->agent_set_time_horizon_agents(fake_agent, 0.0); - NavigationServer2D::get_singleton()->agent_set_time_horizon_obstacles(fake_agent, 0.0); - NavigationServer2D::get_singleton()->agent_set_max_speed(fake_agent, 0.0); - NavigationServer2D::get_singleton()->agent_set_avoidance_mask(fake_agent, 0); - NavigationServer2D::get_singleton()->agent_set_avoidance_priority(fake_agent, 1.0); - NavigationServer2D::get_singleton()->agent_set_avoidance_enabled(fake_agent, radius > 0); set_radius(radius); set_vertices(vertices); set_avoidance_layers(avoidance_layers); + set_avoidance_enabled(avoidance_enabled); } NavigationObstacle2D::~NavigationObstacle2D() { @@ -164,9 +157,6 @@ NavigationObstacle2D::~NavigationObstacle2D() { NavigationServer2D::get_singleton()->free(obstacle); obstacle = RID(); - - NavigationServer2D::get_singleton()->free(fake_agent); - fake_agent = RID(); } void NavigationObstacle2D::set_vertices(const Vector &p_vertices) { @@ -202,17 +192,18 @@ void NavigationObstacle2D::set_radius(real_t p_radius) { radius = p_radius; - NavigationServer2D::get_singleton()->agent_set_avoidance_enabled(fake_agent, radius > 0.0); - NavigationServer2D::get_singleton()->agent_set_radius(fake_agent, radius); + NavigationServer2D::get_singleton()->obstacle_set_radius(obstacle, radius); if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint())) { queue_redraw(); } } void NavigationObstacle2D::set_avoidance_layers(uint32_t p_layers) { + if (avoidance_layers == p_layers) { + return; + } avoidance_layers = p_layers; NavigationServer2D::get_singleton()->obstacle_set_avoidance_layers(obstacle, avoidance_layers); - NavigationServer2D::get_singleton()->agent_set_avoidance_layers(fake_agent, avoidance_layers); } uint32_t NavigationObstacle2D::get_avoidance_layers() const { @@ -237,24 +228,31 @@ bool NavigationObstacle2D::get_avoidance_layer_value(int p_layer_number) const { return get_avoidance_layers() & (1 << (p_layer_number - 1)); } +void NavigationObstacle2D::set_avoidance_enabled(bool p_enabled) { + if (avoidance_enabled == p_enabled) { + return; + } + + avoidance_enabled = p_enabled; + NavigationServer2D::get_singleton()->obstacle_set_avoidance_enabled(obstacle, avoidance_enabled); +} + +bool NavigationObstacle2D::get_avoidance_enabled() const { + return avoidance_enabled; +} + void NavigationObstacle2D::set_velocity(const Vector2 p_velocity) { velocity = p_velocity; velocity_submitted = true; } void NavigationObstacle2D::_update_map(RID p_map) { - NavigationServer2D::get_singleton()->obstacle_set_map(obstacle, p_map); - NavigationServer2D::get_singleton()->agent_set_map(fake_agent, p_map); map_current = p_map; + NavigationServer2D::get_singleton()->obstacle_set_map(obstacle, p_map); } void NavigationObstacle2D::_update_position(const Vector2 p_position) { - if (vertices.size() > 0) { - NavigationServer2D::get_singleton()->obstacle_set_position(obstacle, p_position); - } - if (radius > 0.0) { - NavigationServer2D::get_singleton()->agent_set_position(fake_agent, p_position); - } + NavigationServer2D::get_singleton()->obstacle_set_position(obstacle, p_position); } #ifdef DEBUG_ENABLED diff --git a/scene/2d/navigation_obstacle_2d.h b/scene/2d/navigation_obstacle_2d.h index d3b0926247f..8e8f6c11462 100644 --- a/scene/2d/navigation_obstacle_2d.h +++ b/scene/2d/navigation_obstacle_2d.h @@ -45,7 +45,7 @@ class NavigationObstacle2D : public Node2D { Vector vertices; - RID fake_agent; + bool avoidance_enabled = true; uint32_t avoidance_layers = 1; Transform2D previous_transform; @@ -68,8 +68,10 @@ public: NavigationObstacle2D(); virtual ~NavigationObstacle2D(); - RID get_obstacle_rid() const { return obstacle; } - RID get_agent_rid() const { return fake_agent; } + RID get_rid() const { return obstacle; } + + void set_avoidance_enabled(bool p_enabled); + bool get_avoidance_enabled() const; void set_navigation_map(RID p_navigation_map); RID get_navigation_map() const; diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp index b44ebf837ac..2c29991ab97 100644 --- a/scene/3d/navigation_obstacle_3d.cpp +++ b/scene/3d/navigation_obstacle_3d.cpp @@ -36,8 +36,10 @@ #include "servers/navigation_server_3d.h" void NavigationObstacle3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_obstacle_rid"), &NavigationObstacle3D::get_obstacle_rid); - ClassDB::bind_method(D_METHOD("get_agent_rid"), &NavigationObstacle3D::get_agent_rid); + ClassDB::bind_method(D_METHOD("get_rid"), &NavigationObstacle3D::get_rid); + + ClassDB::bind_method(D_METHOD("set_avoidance_enabled", "enabled"), &NavigationObstacle3D::set_avoidance_enabled); + ClassDB::bind_method(D_METHOD("get_avoidance_enabled"), &NavigationObstacle3D::get_avoidance_enabled); 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); @@ -63,7 +65,8 @@ void NavigationObstacle3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_use_3d_avoidance", "enabled"), &NavigationObstacle3D::set_use_3d_avoidance); ClassDB::bind_method(D_METHOD("get_use_3d_avoidance"), &NavigationObstacle3D::get_use_3d_avoidance); - ADD_GROUP("Avoidance", "avoidance_"); + ADD_GROUP("Avoidance", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "velocity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_velocity", "get_velocity"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.0,100,0.01,suffix:m"), "set_radius", "get_radius"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.0,100,0.01,suffix:m"), "set_height", "get_height"); @@ -84,7 +87,7 @@ void NavigationObstacle3D::_notification(int p_what) { } previous_transform = get_global_transform(); // need to trigger map controlled agent assignment somehow for the fake_agent since obstacles use no callback like regular agents - NavigationServer3D::get_singleton()->agent_set_avoidance_enabled(fake_agent, radius > 0); + NavigationServer3D::get_singleton()->obstacle_set_avoidance_enabled(obstacle, avoidance_enabled); _update_position(get_global_transform().origin); set_physics_process_internal(true); #ifdef DEBUG_ENABLED @@ -137,7 +140,7 @@ void NavigationObstacle3D::_notification(int p_what) { velocity_submitted = false; // only update if there is a noticeable change, else the rvo agent preferred velocity stays the same if (!previous_velocity.is_equal_approx(velocity)) { - NavigationServer3D::get_singleton()->agent_set_velocity(fake_agent, velocity); + NavigationServer3D::get_singleton()->obstacle_set_velocity(obstacle, velocity); } previous_velocity = velocity; } @@ -156,22 +159,12 @@ void NavigationObstacle3D::_notification(int p_what) { NavigationObstacle3D::NavigationObstacle3D() { obstacle = NavigationServer3D::get_singleton()->obstacle_create(); - fake_agent = NavigationServer3D::get_singleton()->agent_create(); - - // change properties of the fake agent so it can act as fake obstacle with a radius - NavigationServer3D::get_singleton()->agent_set_neighbor_distance(fake_agent, 0.0); - NavigationServer3D::get_singleton()->agent_set_max_neighbors(fake_agent, 0); - NavigationServer3D::get_singleton()->agent_set_time_horizon_agents(fake_agent, 0.0); - NavigationServer3D::get_singleton()->agent_set_time_horizon_obstacles(fake_agent, 0.0); - NavigationServer3D::get_singleton()->agent_set_max_speed(fake_agent, 0.0); - NavigationServer3D::get_singleton()->agent_set_avoidance_mask(fake_agent, 1); - NavigationServer3D::get_singleton()->agent_set_avoidance_priority(fake_agent, 1.0); - NavigationServer3D::get_singleton()->agent_set_avoidance_enabled(fake_agent, radius > 0); set_radius(radius); set_height(height); set_vertices(vertices); set_avoidance_layers(avoidance_layers); + set_avoidance_enabled(avoidance_enabled); set_use_3d_avoidance(use_3d_avoidance); #ifdef DEBUG_ENABLED @@ -188,9 +181,6 @@ NavigationObstacle3D::~NavigationObstacle3D() { NavigationServer3D::get_singleton()->free(obstacle); obstacle = RID(); - NavigationServer3D::get_singleton()->free(fake_agent); - fake_agent = RID(); - #ifdef DEBUG_ENABLED NavigationServer3D::get_singleton()->disconnect("avoidance_debug_changed", callable_mp(this, &NavigationObstacle3D::_update_fake_agent_radius_debug)); NavigationServer3D::get_singleton()->disconnect("avoidance_debug_changed", callable_mp(this, &NavigationObstacle3D::_update_static_obstacle_debug)); @@ -242,8 +232,7 @@ void NavigationObstacle3D::set_radius(real_t p_radius) { } radius = p_radius; - NavigationServer3D::get_singleton()->agent_set_avoidance_enabled(fake_agent, radius > 0.0); - NavigationServer3D::get_singleton()->agent_set_radius(fake_agent, radius); + NavigationServer3D::get_singleton()->obstacle_set_radius(obstacle, radius); #ifdef DEBUG_ENABLED _update_fake_agent_radius_debug(); @@ -258,7 +247,7 @@ void NavigationObstacle3D::set_height(real_t p_height) { height = p_height; NavigationServer3D::get_singleton()->obstacle_set_height(obstacle, height); - NavigationServer3D::get_singleton()->agent_set_height(fake_agent, height); + #ifdef DEBUG_ENABLED _update_static_obstacle_debug(); #endif // DEBUG_ENABLED @@ -267,7 +256,6 @@ void NavigationObstacle3D::set_height(real_t p_height) { void NavigationObstacle3D::set_avoidance_layers(uint32_t p_layers) { avoidance_layers = p_layers; NavigationServer3D::get_singleton()->obstacle_set_avoidance_layers(obstacle, avoidance_layers); - NavigationServer3D::get_singleton()->agent_set_avoidance_layers(fake_agent, avoidance_layers); } uint32_t NavigationObstacle3D::get_avoidance_layers() const { @@ -292,6 +280,19 @@ bool NavigationObstacle3D::get_avoidance_layer_value(int p_layer_number) const { return get_avoidance_layers() & (1 << (p_layer_number - 1)); } +void NavigationObstacle3D::set_avoidance_enabled(bool p_enabled) { + if (avoidance_enabled == p_enabled) { + return; + } + + avoidance_enabled = p_enabled; + NavigationServer3D::get_singleton()->obstacle_set_avoidance_enabled(obstacle, avoidance_enabled); +} + +bool NavigationObstacle3D::get_avoidance_enabled() const { + return avoidance_enabled; +} + void NavigationObstacle3D::set_use_3d_avoidance(bool p_use_3d_avoidance) { use_3d_avoidance = p_use_3d_avoidance; _update_use_3d_avoidance(use_3d_avoidance); @@ -304,27 +305,16 @@ void NavigationObstacle3D::set_velocity(const Vector3 p_velocity) { } void NavigationObstacle3D::_update_map(RID p_map) { - // avoidance obstacles are 2D only, no point keeping them on the map while 3D is used - if (use_3d_avoidance) { - NavigationServer3D::get_singleton()->obstacle_set_map(obstacle, RID()); - } else { - NavigationServer3D::get_singleton()->obstacle_set_map(obstacle, p_map); - } - NavigationServer3D::get_singleton()->agent_set_map(fake_agent, p_map); + NavigationServer3D::get_singleton()->obstacle_set_map(obstacle, p_map); map_current = p_map; } void NavigationObstacle3D::_update_position(const Vector3 p_position) { - if (vertices.size() > 0) { - NavigationServer3D::get_singleton()->obstacle_set_position(obstacle, p_position); - } - if (radius > 0.0) { - NavigationServer3D::get_singleton()->agent_set_position(fake_agent, p_position); - } + NavigationServer3D::get_singleton()->obstacle_set_position(obstacle, p_position); } void NavigationObstacle3D::_update_use_3d_avoidance(bool p_use_3d_avoidance) { - NavigationServer3D::get_singleton()->agent_set_use_3d_avoidance(fake_agent, use_3d_avoidance); + NavigationServer3D::get_singleton()->obstacle_set_use_3d_avoidance(obstacle, use_3d_avoidance); _update_map(map_current); } diff --git a/scene/3d/navigation_obstacle_3d.h b/scene/3d/navigation_obstacle_3d.h index 603d22cf5ea..51a84c9a54a 100644 --- a/scene/3d/navigation_obstacle_3d.h +++ b/scene/3d/navigation_obstacle_3d.h @@ -46,7 +46,7 @@ class NavigationObstacle3D : public Node3D { Vector vertices; - RID fake_agent; + bool avoidance_enabled = true; uint32_t avoidance_layers = 1; bool use_3d_avoidance = false; @@ -77,8 +77,10 @@ public: NavigationObstacle3D(); virtual ~NavigationObstacle3D(); - RID get_obstacle_rid() const { return obstacle; } - RID get_agent_rid() const { return fake_agent; } + RID get_rid() const { return obstacle; } + + void set_avoidance_enabled(bool p_enabled); + bool get_avoidance_enabled() const; void set_navigation_map(RID p_navigation_map); RID get_navigation_map() const; diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp index c2dddb0627a..4b3bb421d15 100644 --- a/servers/navigation_server_2d.cpp +++ b/servers/navigation_server_2d.cpp @@ -449,8 +449,12 @@ void NavigationServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("agent_set_avoidance_priority", "agent", "priority"), &NavigationServer2D::agent_set_avoidance_priority); ClassDB::bind_method(D_METHOD("obstacle_create"), &NavigationServer2D::obstacle_create); + ClassDB::bind_method(D_METHOD("obstacle_set_avoidance_enabled", "obstacle", "enabled"), &NavigationServer2D::obstacle_set_avoidance_enabled); + ClassDB::bind_method(D_METHOD("obstacle_get_avoidance_enabled", "obstacle"), &NavigationServer2D::obstacle_get_avoidance_enabled); ClassDB::bind_method(D_METHOD("obstacle_set_map", "obstacle", "map"), &NavigationServer2D::obstacle_set_map); ClassDB::bind_method(D_METHOD("obstacle_get_map", "obstacle"), &NavigationServer2D::obstacle_get_map); + ClassDB::bind_method(D_METHOD("obstacle_set_radius", "obstacle", "radius"), &NavigationServer2D::obstacle_set_radius); + ClassDB::bind_method(D_METHOD("obstacle_set_velocity", "obstacle", "velocity"), &NavigationServer2D::obstacle_set_velocity); ClassDB::bind_method(D_METHOD("obstacle_set_position", "obstacle", "position"), &NavigationServer2D::obstacle_set_position); ClassDB::bind_method(D_METHOD("obstacle_set_vertices", "obstacle", "vertices"), &NavigationServer2D::obstacle_set_vertices); ClassDB::bind_method(D_METHOD("obstacle_set_avoidance_layers", "obstacle", "layers"), &NavigationServer2D::obstacle_set_avoidance_layers); @@ -602,8 +606,12 @@ RID NavigationServer2D::obstacle_create() { RID obstacle = NavigationServer3D::get_singleton()->obstacle_create(); return obstacle; } +void FORWARD_2(obstacle_set_avoidance_enabled, RID, p_obstacle, bool, p_enabled, rid_to_rid, bool_to_bool); +bool FORWARD_1_C(obstacle_get_avoidance_enabled, RID, p_obstacle, rid_to_rid); void FORWARD_2(obstacle_set_map, RID, p_obstacle, RID, p_map, rid_to_rid, rid_to_rid); RID FORWARD_1_C(obstacle_get_map, RID, p_obstacle, rid_to_rid); +void FORWARD_2(obstacle_set_radius, RID, p_obstacle, real_t, p_radius, rid_to_rid, real_to_real); +void FORWARD_2(obstacle_set_velocity, RID, p_obstacle, Vector2, p_velocity, rid_to_rid, v2_to_v3); void FORWARD_2(obstacle_set_position, RID, p_obstacle, Vector2, p_position, rid_to_rid, v2_to_v3); void FORWARD_2(obstacle_set_avoidance_layers, RID, p_obstacle, uint32_t, p_layers, rid_to_rid, uint32_to_uint32); diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h index 88246019b9f..36c964e2ea9 100644 --- a/servers/navigation_server_2d.h +++ b/servers/navigation_server_2d.h @@ -240,8 +240,12 @@ public: /// Creates the obstacle. virtual RID obstacle_create(); + virtual void obstacle_set_avoidance_enabled(RID p_obstacle, bool p_enabled); + virtual bool obstacle_get_avoidance_enabled(RID p_obstacle) const; virtual void obstacle_set_map(RID p_obstacle, RID p_map); virtual RID obstacle_get_map(RID p_obstacle) const; + virtual void obstacle_set_radius(RID p_obstacle, real_t p_radius); + virtual void obstacle_set_velocity(RID p_obstacle, Vector2 p_velocity); virtual void obstacle_set_position(RID p_obstacle, Vector2 p_position); virtual void obstacle_set_vertices(RID p_obstacle, const Vector &p_vertices); virtual void obstacle_set_avoidance_layers(RID p_obstacle, uint32_t p_layers); diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp index 7888a28b7b4..f9f8797b76f 100644 --- a/servers/navigation_server_3d.cpp +++ b/servers/navigation_server_3d.cpp @@ -128,9 +128,15 @@ void NavigationServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("agent_set_avoidance_priority", "agent", "priority"), &NavigationServer3D::agent_set_avoidance_priority); ClassDB::bind_method(D_METHOD("obstacle_create"), &NavigationServer3D::obstacle_create); + ClassDB::bind_method(D_METHOD("obstacle_set_avoidance_enabled", "obstacle", "enabled"), &NavigationServer3D::obstacle_set_avoidance_enabled); + ClassDB::bind_method(D_METHOD("obstacle_get_avoidance_enabled", "obstacle"), &NavigationServer3D::obstacle_get_avoidance_enabled); + ClassDB::bind_method(D_METHOD("obstacle_set_use_3d_avoidance", "obstacle", "enabled"), &NavigationServer3D::obstacle_set_use_3d_avoidance); + ClassDB::bind_method(D_METHOD("obstacle_get_use_3d_avoidance", "obstacle"), &NavigationServer3D::obstacle_get_use_3d_avoidance); ClassDB::bind_method(D_METHOD("obstacle_set_map", "obstacle", "map"), &NavigationServer3D::obstacle_set_map); ClassDB::bind_method(D_METHOD("obstacle_get_map", "obstacle"), &NavigationServer3D::obstacle_get_map); + ClassDB::bind_method(D_METHOD("obstacle_set_radius", "obstacle", "radius"), &NavigationServer3D::obstacle_set_radius); ClassDB::bind_method(D_METHOD("obstacle_set_height", "obstacle", "height"), &NavigationServer3D::obstacle_set_height); + ClassDB::bind_method(D_METHOD("obstacle_set_velocity", "obstacle", "velocity"), &NavigationServer3D::obstacle_set_velocity); ClassDB::bind_method(D_METHOD("obstacle_set_position", "obstacle", "position"), &NavigationServer3D::obstacle_set_position); ClassDB::bind_method(D_METHOD("obstacle_set_vertices", "obstacle", "vertices"), &NavigationServer3D::obstacle_set_vertices); ClassDB::bind_method(D_METHOD("obstacle_set_avoidance_layers", "obstacle", "layers"), &NavigationServer3D::obstacle_set_avoidance_layers); diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h index 73698581e90..23c38532e8c 100644 --- a/servers/navigation_server_3d.h +++ b/servers/navigation_server_3d.h @@ -260,7 +260,13 @@ public: virtual RID obstacle_create() = 0; virtual void obstacle_set_map(RID p_obstacle, RID p_map) = 0; virtual RID obstacle_get_map(RID p_obstacle) const = 0; + virtual void obstacle_set_avoidance_enabled(RID p_obstacle, bool p_enabled) = 0; + virtual bool obstacle_get_avoidance_enabled(RID p_obstacle) const = 0; + virtual void obstacle_set_use_3d_avoidance(RID p_obstacle, bool p_enabled) = 0; + virtual bool obstacle_get_use_3d_avoidance(RID p_obstacle) const = 0; + virtual void obstacle_set_radius(RID p_obstacle, real_t p_radius) = 0; virtual void obstacle_set_height(RID p_obstacle, real_t p_height) = 0; + virtual void obstacle_set_velocity(RID p_obstacle, Vector3 p_velocity) = 0; virtual void obstacle_set_position(RID p_obstacle, Vector3 p_position) = 0; virtual void obstacle_set_vertices(RID p_obstacle, const Vector &p_vertices) = 0; virtual void obstacle_set_avoidance_layers(RID p_obstacle, uint32_t p_layers) = 0; diff --git a/servers/navigation_server_3d_dummy.h b/servers/navigation_server_3d_dummy.h index 98dc38990ef..23fd8291db4 100644 --- a/servers/navigation_server_3d_dummy.h +++ b/servers/navigation_server_3d_dummy.h @@ -123,7 +123,13 @@ public: RID obstacle_create() override { return RID(); } void obstacle_set_map(RID p_obstacle, RID p_map) override {} RID obstacle_get_map(RID p_obstacle) const override { return RID(); } + void obstacle_set_avoidance_enabled(RID p_obstacle, bool p_enabled) override {} + bool obstacle_get_avoidance_enabled(RID p_obstacle) const override { return false; } + void obstacle_set_use_3d_avoidance(RID p_obstacle, bool p_enabled) override {} + bool obstacle_get_use_3d_avoidance(RID p_obstacle) const override { return false; } + void obstacle_set_radius(RID p_obstacle, real_t p_radius) override {} void obstacle_set_height(RID p_obstacle, real_t p_height) override {} + void obstacle_set_velocity(RID p_obstacle, Vector3 p_velocity) override {} void obstacle_set_position(RID p_obstacle, Vector3 p_position) override {} void obstacle_set_vertices(RID p_obstacle, const Vector &p_vertices) override {} void obstacle_set_avoidance_layers(RID p_obstacle, uint32_t p_layers) override {}