Backported from godot4: Update navigation obstacle API

Updates navigation obstacle API.
- smix8
c1fc331b88
This commit is contained in:
Relintai 2023-09-04 19:55:32 +02:00
parent aeb4d3fbe2
commit b37e0e6a4e
20 changed files with 435 additions and 119 deletions

View File

@ -495,6 +495,13 @@
Creates a new navigation obstacle.
</description>
</method>
<method name="obstacle_get_avoidance_enabled" qualifiers="const">
<return type="bool" />
<param index="0" name="obstacle" type="RID" />
<description>
Returns [code]true[/code] if the provided [param obstacle] has avoidance enabled.
</description>
</method>
<method name="obstacle_get_map" qualifiers="const">
<return type="RID" />
<argument index="0" name="obstacle" type="RID" />
@ -509,11 +516,20 @@
Returns [code]true[/code] if the specified [param obstacle] is paused.
</description>
</method>
<method name="obstacle_set_avoidance_enabled">
<return type="void" />
<param index="0" name="obstacle" type="RID" />
<param index="1" name="enabled" type="bool" />
<description>
If [param enabled] the provided [param obstacle] affects avoidance using agents.
</description>
</method>
<method name="obstacle_set_avoidance_layers">
<return type="void" />
<argument index="0" name="obstacle" type="RID" />
<argument index="1" name="layers" type="int" />
<description>
Set the obstacles's [code]avoidance_layers[/code] bitmask.
</description>
</method>
<method name="obstacle_set_map">
@ -540,6 +556,22 @@
Sets the position of the obstacle in world space.
</description>
</method>
<method name="obstacle_set_radius">
<return type="void" />
<param index="0" name="obstacle" type="RID" />
<param index="1" name="radius" type="float" />
<description>
Sets the radius of the dynamic obstacle.
</description>
</method>
<method name="obstacle_set_velocity">
<return type="void" />
<param index="0" name="obstacle" type="RID" />
<param index="1" name="velocity" type="Vector2" />
<description>
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.
</description>
</method>
<method name="obstacle_set_vertices">
<return type="void" />
<argument index="0" name="obstacle" type="RID" />

View File

@ -12,12 +12,6 @@
<tutorials>
</tutorials>
<methods>
<method name="get_agent_rid" qualifiers="const">
<return type="RID" />
<description>
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].
</description>
</method>
<method name="get_avoidance_layer_value" qualifiers="const">
<return type="bool" />
<argument index="0" name="layer_number" type="int" />
@ -37,10 +31,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.
</description>
</method>
<method name="get_obstacle_rid" qualifiers="const">
<method name="get_rid" qualifiers="const">
<return type="RID" />
<description>
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].
</description>
</method>
<method name="set_avoidance_layer_value">
@ -67,6 +61,9 @@
</method>
</methods>
<members>
<member name="avoidance_enabled" type="bool" setter="set_avoidance_enabled" getter="get_avoidance_enabled" default="true">
If [code]true[/code] the obstacle affects avoidance using agents.
</member>
<member name="avoidance_layers" type="int" setter="set_avoidance_layers" getter="get_avoidance_layers" default="1">
A bitfield determining the avoidance layers for this obstacle. Agent's with a matching bit on the their avoidance mask will avoid this obstacle.
</member>

View File

@ -12,12 +12,6 @@
<tutorials>
</tutorials>
<methods>
<method name="get_agent_rid" qualifiers="const">
<return type="RID" />
<description>
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].
</description>
</method>
<method name="get_avoidance_layer_value" qualifiers="const">
<return type="bool" />
<argument index="0" name="layer_number" type="int" />
@ -37,10 +31,10 @@
Returns the [RID] of the navigation map for this NavigationObstacle2D 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 NavigationObstacle2D and also update the obstacle on the [NavigationServer2D].
</description>
</method>
<method name="get_obstacle_rid" qualifiers="const">
<method name="get_rid" qualifiers="const">
<return type="RID" />
<description>
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].
</description>
</method>
<method name="set_avoidance_layer_value">
@ -67,6 +61,9 @@
</method>
</methods>
<members>
<member name="avoidance_enabled" type="bool" setter="set_avoidance_enabled" getter="get_avoidance_enabled" default="true">
If [code]true[/code] the obstacle affects avoidance using agents.
</member>
<member name="avoidance_layers" type="int" setter="set_avoidance_layers" getter="get_avoidance_layers" default="1">
A bitfield determining the avoidance layers for this obstacle. Agent's with a matching bit on the their avoidance mask will avoid this obstacle.
</member>

View File

@ -559,6 +559,13 @@
Creates a new obstacle.
</description>
</method>
<method name="obstacle_get_avoidance_enabled" qualifiers="const">
<return type="bool" />
<param index="0" name="obstacle" type="RID" />
<description>
Returns [code]true[/code] if the provided [param obstacle] has avoidance enabled.
</description>
</method>
<method name="obstacle_get_map" qualifiers="const">
<return type="RID" />
<argument index="0" name="obstacle" type="RID" />
@ -573,6 +580,21 @@
Returns [code]true[/code] if the specified [param obstacle] is paused.
</description>
</method>
<method name="obstacle_get_use_3d_avoidance" qualifiers="const">
<return type="bool" />
<param index="0" name="obstacle" type="RID" />
<description>
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).
</description>
</method>
<method name="obstacle_set_avoidance_enabled">
<return type="void" />
<param index="0" name="obstacle" type="RID" />
<param index="1" name="enabled" type="bool" />
<description>
If [param enabled] the provided [param obstacle] affects avoidance using agents.
</description>
</method>
<method name="obstacle_set_avoidance_layers">
<return type="void" />
<argument index="0" name="obstacle" type="RID" />
@ -613,6 +635,30 @@
Updates the [param position] in world space for the [param obstacle].
</description>
</method>
<method name="obstacle_set_radius">
<return type="void" />
<param index="0" name="obstacle" type="RID" />
<param index="1" name="radius" type="float" />
<description>
Sets the radius of the dynamic obstacle.
</description>
</method>
<method name="obstacle_set_use_3d_avoidance">
<return type="void" />
<param index="0" name="obstacle" type="RID" />
<param index="1" name="enabled" type="bool" />
<description>
Sets if the [param obstacle] uses the 2D avoidance or the 3D avoidance while avoidance is enabled.
</description>
</method>
<method name="obstacle_set_velocity">
<return type="void" />
<param index="0" name="obstacle" type="RID" />
<param index="1" name="velocity" type="Vector3" />
<description>
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.
</description>
</method>
<method name="obstacle_set_vertices">
<return type="void" />
<argument index="0" name="obstacle" type="RID" />

View File

@ -30,11 +30,16 @@
#include "nav_obstacle.h"
#include "nav_agent.h"
#include "nav_map.h"
NavObstacle::NavObstacle() {
agent = nullptr;
map = nullptr;
radius = 0.0;
height = 0.0;
avoidance_enabled = false;
use_3d_avoidance = false;
avoidance_layers = 1;
obstacle_dirty = true;
map_update_id = 0;
@ -43,24 +48,104 @@ 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);
}
}
@ -80,8 +165,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() {
@ -90,6 +183,26 @@ bool NavObstacle::check_dirty() {
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_paused(paused);
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);
}
}
void NavObstacle::set_paused(bool p_paused) {
if (paused == p_paused) {
return;
@ -104,7 +217,7 @@ void NavObstacle::set_paused(bool p_paused) {
map->add_obstacle(this);
}
}
//internal_update_agent();
internal_update_agent();
}
bool NavObstacle::get_paused() const {

View File

@ -34,18 +34,23 @@
#include "core/containers/local_vector.h"
#include "core/object/class_db.h"
#include "nav_agent.h"
#include "nav_rid.h"
class NavAgent;
class NavMap;
class NavObstacle : public NavRid {
NavAgent *agent;
NavMap *map;
Vector3 velocity;
Vector3 position;
Vector<Vector3> vertices;
real_t radius;
real_t height;
bool avoidance_enabled;
bool use_3d_avoidance;
uint32_t avoidance_layers;
bool obstacle_dirty;
@ -57,15 +62,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<Vector3> &p_vertices);
const Vector<Vector3> &get_vertices() const { return vertices; }
@ -78,6 +98,9 @@ public:
bool get_paused() const;
bool check_dirty();
private:
void internal_update_agent();
};
#endif // NAV_OBSTACLE_H

View File

@ -357,8 +357,12 @@ RID PandemoniumNavigation2DServer::obstacle_create() {
RID obstacle = NavigationServer::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_paused, RID, p_obstacle, bool, p_paused, rid_to_rid, bool_to_bool);
bool FORWARD_1_C(obstacle_get_paused, RID, p_obstacle, rid_to_rid);
void FORWARD_2(obstacle_set_position, RID, p_obstacle, Vector2, p_position, rid_to_rid, v2_to_v3);

View File

@ -240,12 +240,14 @@ 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_paused(RID p_obstacle, bool p_paused);
virtual bool obstacle_get_paused(RID p_obstacle) const;
virtual void obstacle_set_position(RID p_obstacle, Vector2 p_position);
virtual void obstacle_set_vertices(RID p_obstacle, const Vector<Vector2> &p_vertices);
virtual void obstacle_set_avoidance_layers(RID p_obstacle, uint32_t p_layers);

View File

@ -864,12 +864,48 @@ COMMAND_2(agent_set_avoidance_priority, RID, p_agent, real_t, p_priority) {
RID PandemoniumNavigationServer::obstacle_create() {
PandemoniumNavigationServer *mut_this = const_cast<PandemoniumNavigationServer *>(this);
MutexLock lock(mut_this->operations_mutex);
NavObstacle *obstacle = memnew(NavObstacle());
RID rid = obstacle_owner.make_rid(obstacle);
obstacle->set_self(rid);
NavAgent *agent = memnew(NavAgent());
RID agent_rid = agent_owner.make_rid(agent);
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.getornull(p_obstacle);
ERR_FAIL_COND(obstacle == nullptr);
obstacle->set_avoidance_enabled(p_enabled);
}
bool PandemoniumNavigationServer::obstacle_get_avoidance_enabled(RID p_obstacle) const {
NavObstacle *obstacle = obstacle_owner.getornull(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.getornull(p_obstacle);
ERR_FAIL_COND(obstacle == nullptr);
obstacle->set_use_3d_avoidance(p_enabled);
}
bool PandemoniumNavigationServer::obstacle_get_use_3d_avoidance(RID p_obstacle) const {
NavObstacle *obstacle = obstacle_owner.getornull(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.getornull(p_obstacle);
ERR_FAIL_COND(obstacle == nullptr);
@ -916,12 +952,27 @@ bool PandemoniumNavigationServer::obstacle_get_paused(RID p_obstacle) const {
return obstacle->get_paused();
}
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.getornull(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.getornull(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.getornull(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.getornull(p_obstacle);
ERR_FAIL_COND(obstacle == nullptr);
@ -1007,9 +1058,17 @@ COMMAND_1(free, RID, p_object) {
link_owner.free(p_object);
} else if (agent_owner.owns(p_object)) {
NavAgent *agent = agent_owner.getornull(p_object);
internal_free_agent(p_object);
} 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).");
}
}
// Removes this agent from the map if assigned
void PandemoniumNavigationServer::internal_free_agent(RID p_object) {
NavAgent *agent = agent_owner.getornull(p_object);
if (agent) {
if (agent->get_map() != nullptr) {
agent->get_map()->remove_agent(agent);
agent->set_map(nullptr);
@ -1017,19 +1076,26 @@ COMMAND_1(free, RID, p_object) {
agent_owner.free(p_object);
memdelete(agent);
}
}
} else if (obstacle_owner.owns(p_object)) {
NavObstacle *obstacle = obstacle_owner.getornull(p_object);
// Removes this agent from the map if assigned
void PandemoniumNavigationServer::internal_free_obstacle(RID p_object) {
NavObstacle *obstacle = obstacle_owner.getornull(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).");
memdelete(obstacle);
}
}

View File

@ -205,8 +205,14 @@ public:
COMMAND_2(agent_set_avoidance_priority, RID, p_agent, real_t, p_priority);
virtual RID obstacle_create();
COMMAND_2(obstacle_set_avoidance_enabled, RID, p_obstacle, bool, p_enabled);
virtual bool obstacle_get_avoidance_enabled(RID p_obstacle) const;
COMMAND_2(obstacle_set_use_3d_avoidance, RID, p_obstacle, bool, p_enabled);
virtual bool obstacle_get_use_3d_avoidance(RID p_obstacle) const;
COMMAND_2(obstacle_set_map, RID, p_obstacle, RID, p_map);
virtual RID obstacle_get_map(RID p_obstacle) const;
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_paused, RID, p_obstacle, bool, p_paused);
virtual bool obstacle_get_paused(RID p_obstacle) const;
COMMAND_2(obstacle_set_position, RID, p_obstacle, Vector3, p_position);
@ -224,6 +230,10 @@ public:
virtual int get_process_info(ProcessInfo p_info) const;
virtual NavigationUtilities::PathQueryResult _query_path(const NavigationUtilities::PathQueryParameters &p_parameters) const;
private:
void internal_free_agent(RID p_object);
void internal_free_obstacle(RID p_object);
};
#undef COMMAND_1

View File

@ -101,8 +101,12 @@ public:
virtual RID obstacle_create() { return RID(); }
virtual void obstacle_set_map(RID p_obstacle, RID p_map) {}
virtual RID obstacle_get_map(RID p_obstacle) const { return RID(); }
virtual void obstacle_set_avoidance_enabled(RID p_obstacle, bool p_enabled) {}
virtual bool obstacle_get_avoidance_enabled(RID p_obstacle) const { return false; }
virtual void obstacle_set_radius(RID p_obstacle, real_t p_radius) {}
virtual void obstacle_set_paused(RID p_obstacle, bool p_paused) {}
virtual bool obstacle_get_paused(RID p_obstacle) const { return false; }
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<Vector2> &p_vertices) {}
virtual void obstacle_set_avoidance_layers(RID p_obstacle, uint32_t p_layers) {}

View File

@ -105,9 +105,15 @@ public:
virtual RID obstacle_create() { return RID(); }
virtual void obstacle_set_map(RID p_obstacle, RID p_map) {}
virtual RID obstacle_get_map(RID p_obstacle) const { return RID(); }
virtual void obstacle_set_avoidance_enabled(RID p_obstacle, bool p_enabled) {}
virtual bool obstacle_get_avoidance_enabled(RID p_obstacle) const { return false; }
virtual void obstacle_set_use_3d_avoidance(RID p_obstacle, bool p_enabled) {}
virtual bool obstacle_get_use_3d_avoidance(RID p_obstacle) const { return false; }
virtual void obstacle_set_radius(RID p_obstacle, real_t p_radius) {}
virtual void obstacle_set_paused(RID p_obstacle, bool p_paused) {}
virtual bool obstacle_get_paused(RID p_obstacle) const { return false; }
virtual void obstacle_set_height(RID p_obstacle, real_t p_height) {}
virtual void obstacle_set_velocity(RID p_obstacle, Vector3 p_velocity) {}
virtual void obstacle_set_position(RID p_obstacle, Vector3 p_position) {}
virtual void obstacle_set_vertices(RID p_obstacle, const Vector<Vector3> &p_vertices) {}
virtual void obstacle_set_avoidance_layers(RID p_obstacle, uint32_t p_layers) {}

View File

@ -39,8 +39,10 @@
#include "servers/navigation_2d_server.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", "navigation"), &NavigationObstacle2D::set_navigation_node);
ClassDB::bind_method(D_METHOD("get_navigation"), &NavigationObstacle2D::get_navigation_node);
@ -62,7 +64,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_NOEDITOR), "set_velocity", "get_velocity");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.0,500,0.01,suffix:px"), "set_radius", "get_radius");
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "vertices"), "set_vertices", "get_vertices");
@ -92,7 +95,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
Navigation2DServer::get_singleton()->agent_set_avoidance_enabled(fake_agent, radius > 0);
Navigation2DServer::get_singleton()->obstacle_set_avoidance_enabled(obstacle, avoidance_enabled);
_update_position(get_global_transform().get_origin());
set_physics_process_internal(true);
@ -132,7 +135,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)) {
Navigation2DServer::get_singleton()->agent_set_velocity(fake_agent, velocity);
Navigation2DServer::get_singleton()->obstacle_set_velocity(obstacle, velocity);
}
previous_velocity = velocity;
}
@ -163,30 +166,24 @@ NavigationObstacle2D::NavigationObstacle2D() {
navigation = NULL;
obstacle = Navigation2DServer::get_singleton()->obstacle_create();
fake_agent = Navigation2DServer::get_singleton()->agent_create();
// change properties of the fake agent so it can act as fake obstacle with a radius
Navigation2DServer::get_singleton()->agent_set_neighbor_distance(fake_agent, 0.0);
Navigation2DServer::get_singleton()->agent_set_max_neighbors(fake_agent, 0);
Navigation2DServer::get_singleton()->agent_set_time_horizon_agents(fake_agent, 0.0);
Navigation2DServer::get_singleton()->agent_set_time_horizon_obstacles(fake_agent, 0.0);
Navigation2DServer::get_singleton()->agent_set_max_speed(fake_agent, 0.0);
Navigation2DServer::get_singleton()->agent_set_avoidance_mask(fake_agent, 0);
Navigation2DServer::get_singleton()->agent_set_avoidance_priority(fake_agent, 1.0);
Navigation2DServer::get_singleton()->agent_set_avoidance_enabled(fake_agent, radius > 0);
radius = 0.0;
avoidance_enabled = true;
avoidance_layers = 1;
velocity_submitted = false;
set_radius(radius);
set_vertices(vertices);
set_avoidance_layers(avoidance_layers);
set_avoidance_enabled(avoidance_enabled);
}
NavigationObstacle2D::~NavigationObstacle2D() {
ERR_FAIL_NULL(Navigation2DServer::get_singleton());
Navigation2DServer::get_singleton()->free(obstacle);
obstacle = RID();
Navigation2DServer::get_singleton()->free(fake_agent);
fake_agent = RID();
}
void NavigationObstacle2D::set_navigation(Navigation2D *p_nav) {
@ -247,17 +244,19 @@ void NavigationObstacle2D::set_radius(real_t p_radius) {
radius = p_radius;
Navigation2DServer::get_singleton()->agent_set_avoidance_enabled(fake_agent, radius > 0.0);
Navigation2DServer::get_singleton()->agent_set_radius(fake_agent, radius);
Navigation2DServer::get_singleton()->obstacle_set_radius(obstacle, radius);
if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint())) {
update();
}
}
void NavigationObstacle2D::set_avoidance_layers(uint32_t p_layers) {
if (avoidance_layers == p_layers) {
return;
}
avoidance_layers = p_layers;
Navigation2DServer::get_singleton()->obstacle_set_avoidance_layers(obstacle, avoidance_layers);
Navigation2DServer::get_singleton()->agent_set_avoidance_layers(fake_agent, avoidance_layers);
}
uint32_t NavigationObstacle2D::get_avoidance_layers() const {
@ -282,25 +281,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;
Navigation2DServer::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;
Navigation2DServer::get_singleton()->agent_set_velocity(fake_agent, velocity);
}
void NavigationObstacle2D::_update_map(RID p_map) {
Navigation2DServer::get_singleton()->obstacle_set_map(obstacle, p_map);
Navigation2DServer::get_singleton()->agent_set_map(fake_agent, p_map);
map_current = p_map;
Navigation2DServer::get_singleton()->obstacle_set_map(obstacle, p_map);
}
void NavigationObstacle2D::_update_position(const Vector2 p_position) {
if (vertices.size() > 0) {
Navigation2DServer::get_singleton()->obstacle_set_position(obstacle, p_position);
}
if (radius > 0.0) {
Navigation2DServer::get_singleton()->agent_set_position(fake_agent, p_position);
}
Navigation2DServer::get_singleton()->obstacle_set_position(obstacle, p_position);
}
#ifdef DEBUG_ENABLED

View File

@ -45,18 +45,18 @@ class NavigationObstacle2D : public Node2D {
RID map_override;
RID map_current;
real_t radius = 0.0;
real_t radius;
Vector<Vector2> vertices;
RID fake_agent;
uint32_t avoidance_layers = 1;
bool avoidance_enabled;
uint32_t avoidance_layers;
Transform2D previous_transform;
Vector2 velocity;
Vector2 previous_velocity;
bool velocity_submitted = false;
bool velocity_submitted;
#ifdef DEBUG_ENABLED
private:
@ -80,8 +80,10 @@ public:
void set_navigation_node(Node *p_nav);
Node *get_navigation_node() const;
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;

View File

@ -43,8 +43,10 @@
#include "servers/rendering_server.h"
void NavigationObstacle::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_obstacle_rid"), &NavigationObstacle::get_obstacle_rid);
ClassDB::bind_method(D_METHOD("get_agent_rid"), &NavigationObstacle::get_agent_rid);
ClassDB::bind_method(D_METHOD("get_rid"), &NavigationObstacle::get_rid);
ClassDB::bind_method(D_METHOD("set_avoidance_enabled", "enabled"), &NavigationObstacle::set_avoidance_enabled);
ClassDB::bind_method(D_METHOD("get_avoidance_enabled"), &NavigationObstacle::get_avoidance_enabled);
ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationObstacle::set_navigation_map);
ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationObstacle::get_navigation_map);
@ -78,7 +80,8 @@ void NavigationObstacle::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_static_obstacle_debug"), &NavigationObstacle::_update_static_obstacle_debug);
#endif // DEBUG_ENABLED
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_NOEDITOR), "set_velocity", "get_velocity");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.0,100,0.01,suffix:m"), "set_radius", "get_radius");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.0,100,0.01,suffix:m"), "set_height", "get_height");
@ -110,7 +113,7 @@ void NavigationObstacle::_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
NavigationServer::get_singleton()->agent_set_avoidance_enabled(fake_agent, radius > 0);
NavigationServer::get_singleton()->obstacle_set_avoidance_enabled(obstacle, avoidance_enabled);
_update_position(get_global_transform().origin);
set_physics_process_internal(true);
@ -166,7 +169,7 @@ void NavigationObstacle::_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)) {
NavigationServer::get_singleton()->agent_set_velocity(fake_agent, velocity);
NavigationServer::get_singleton()->obstacle_set_velocity(obstacle, velocity);
}
previous_velocity = velocity;
}
@ -195,24 +198,15 @@ NavigationObstacle::NavigationObstacle() {
use_3d_avoidance = false;
velocity_submitted = false;
avoidance_enabled = true;
obstacle = NavigationServer::get_singleton()->obstacle_create();
fake_agent = NavigationServer::get_singleton()->agent_create();
// change properties of the fake agent so it can act as fake obstacle with a radius
NavigationServer::get_singleton()->agent_set_neighbor_distance(fake_agent, 0.0);
NavigationServer::get_singleton()->agent_set_max_neighbors(fake_agent, 0);
NavigationServer::get_singleton()->agent_set_time_horizon_agents(fake_agent, 0.0);
NavigationServer::get_singleton()->agent_set_time_horizon_obstacles(fake_agent, 0.0);
NavigationServer::get_singleton()->agent_set_max_speed(fake_agent, 0.0);
NavigationServer::get_singleton()->agent_set_avoidance_mask(fake_agent, 1);
NavigationServer::get_singleton()->agent_set_avoidance_priority(fake_agent, 1.0);
NavigationServer::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
@ -229,9 +223,6 @@ NavigationObstacle::~NavigationObstacle() {
NavigationServer::get_singleton()->free(obstacle);
obstacle = RID();
NavigationServer::get_singleton()->free(fake_agent);
fake_agent = RID();
#ifdef DEBUG_ENABLED
NavigationServer::get_singleton()->disconnect("avoidance_debug_changed", this, "_update_fake_agent_radius_debug");
NavigationServer::get_singleton()->disconnect("avoidance_debug_changed", this, "_update_static_obstacle_debug");
@ -258,7 +249,8 @@ void NavigationObstacle::set_navigation(Navigation *p_nav) {
}
navigation = p_nav;
NavigationServer::get_singleton()->agent_set_map(fake_agent, get_navigation_map());
NavigationServer::get_singleton()->obstacle_set_map(obstacle, get_navigation_map());
}
void NavigationObstacle::set_navigation_node(Node *p_nav) {
@ -305,8 +297,7 @@ void NavigationObstacle::set_radius(real_t p_radius) {
}
radius = p_radius;
NavigationServer::get_singleton()->agent_set_avoidance_enabled(fake_agent, radius > 0.0);
NavigationServer::get_singleton()->agent_set_radius(fake_agent, radius);
NavigationServer::get_singleton()->obstacle_set_radius(obstacle, radius);
#ifdef DEBUG_ENABLED
_update_fake_agent_radius_debug();
@ -321,7 +312,7 @@ void NavigationObstacle::set_height(real_t p_height) {
height = p_height;
NavigationServer::get_singleton()->obstacle_set_height(obstacle, height);
NavigationServer::get_singleton()->agent_set_height(fake_agent, height);
#ifdef DEBUG_ENABLED
_update_static_obstacle_debug();
#endif // DEBUG_ENABLED
@ -330,7 +321,6 @@ void NavigationObstacle::set_height(real_t p_height) {
void NavigationObstacle::set_avoidance_layers(uint32_t p_layers) {
avoidance_layers = p_layers;
NavigationServer::get_singleton()->obstacle_set_avoidance_layers(obstacle, avoidance_layers);
NavigationServer::get_singleton()->agent_set_avoidance_layers(fake_agent, avoidance_layers);
}
uint32_t NavigationObstacle::get_avoidance_layers() const {
@ -355,6 +345,19 @@ bool NavigationObstacle::get_avoidance_layer_value(int p_layer_number) const {
return get_avoidance_layers() & (1 << (p_layer_number - 1));
}
void NavigationObstacle::set_avoidance_enabled(bool p_enabled) {
if (avoidance_enabled == p_enabled) {
return;
}
avoidance_enabled = p_enabled;
NavigationServer::get_singleton()->obstacle_set_avoidance_enabled(obstacle, avoidance_enabled);
}
bool NavigationObstacle::get_avoidance_enabled() const {
return avoidance_enabled;
}
void NavigationObstacle::set_use_3d_avoidance(bool p_use_3d_avoidance) {
use_3d_avoidance = p_use_3d_avoidance;
_update_use_3d_avoidance(use_3d_avoidance);
@ -367,28 +370,16 @@ void NavigationObstacle::set_velocity(const Vector3 p_velocity) {
}
void NavigationObstacle::_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) {
NavigationServer::get_singleton()->obstacle_set_map(obstacle, RID());
} else {
NavigationServer::get_singleton()->obstacle_set_map(obstacle, p_map);
}
NavigationServer::get_singleton()->agent_set_map(fake_agent, p_map);
NavigationServer::get_singleton()->obstacle_set_map(obstacle, p_map);
map_current = p_map;
}
void NavigationObstacle::_update_position(const Vector3 p_position) {
if (vertices.size() > 0) {
NavigationServer::get_singleton()->obstacle_set_position(obstacle, p_position);
}
if (radius > 0.0) {
NavigationServer::get_singleton()->agent_set_position(fake_agent, p_position);
}
NavigationServer::get_singleton()->obstacle_set_position(obstacle, p_position);
}
void NavigationObstacle::_update_use_3d_avoidance(bool p_use_3d_avoidance) {
NavigationServer::get_singleton()->agent_set_use_3d_avoidance(fake_agent, use_3d_avoidance);
NavigationServer::get_singleton()->obstacle_set_use_3d_avoidance(obstacle, use_3d_avoidance);
_update_map(map_current);
}

View File

@ -51,7 +51,7 @@ class NavigationObstacle : public Spatial {
Vector<Vector3> vertices;
RID fake_agent;
bool avoidance_enabled;
uint32_t avoidance_layers;
bool use_3d_avoidance;
@ -90,8 +90,10 @@ public:
void set_navigation_node(Node *p_nav);
Node *get_navigation_node() const;
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;

View File

@ -124,8 +124,12 @@ void Navigation2DServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("agent_set_avoidance_priority", "agent", "priority"), &Navigation2DServer::agent_set_avoidance_priority);
ClassDB::bind_method(D_METHOD("obstacle_create"), &Navigation2DServer::obstacle_create);
ClassDB::bind_method(D_METHOD("obstacle_set_avoidance_enabled", "obstacle", "enabled"), &Navigation2DServer::obstacle_set_avoidance_enabled);
ClassDB::bind_method(D_METHOD("obstacle_get_avoidance_enabled", "obstacle"), &Navigation2DServer::obstacle_get_avoidance_enabled);
ClassDB::bind_method(D_METHOD("obstacle_set_map", "obstacle", "map"), &Navigation2DServer::obstacle_set_map);
ClassDB::bind_method(D_METHOD("obstacle_get_map", "obstacle"), &Navigation2DServer::obstacle_get_map);
ClassDB::bind_method(D_METHOD("obstacle_set_radius", "obstacle", "radius"), &Navigation2DServer::obstacle_set_radius);
ClassDB::bind_method(D_METHOD("obstacle_set_velocity", "obstacle", "velocity"), &Navigation2DServer::obstacle_set_velocity);
ClassDB::bind_method(D_METHOD("obstacle_set_paused", "obstacle", "paused"), &Navigation2DServer::obstacle_set_paused);
ClassDB::bind_method(D_METHOD("obstacle_get_paused", "obstacle"), &Navigation2DServer::obstacle_get_paused);
ClassDB::bind_method(D_METHOD("obstacle_set_position", "obstacle", "position"), &Navigation2DServer::obstacle_set_position);

View File

@ -249,10 +249,12 @@ 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_radius(RID p_obstacle, real_t p_radius) = 0;
virtual void obstacle_set_paused(RID p_obstacle, bool p_paused) = 0;
virtual bool obstacle_get_paused(RID p_obstacle) const = 0;
virtual void obstacle_set_velocity(RID p_obstacle, Vector2 p_velocity) = 0;
virtual void obstacle_set_position(RID p_obstacle, Vector2 p_position) = 0;
virtual void obstacle_set_vertices(RID p_obstacle, const Vector<Vector2> &p_vertices) = 0;
virtual void obstacle_set_avoidance_layers(RID p_obstacle, uint32_t p_layers) = 0;

View File

@ -151,11 +151,17 @@ void NavigationServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("agent_set_avoidance_priority", "agent", "priority"), &NavigationServer::agent_set_avoidance_priority);
ClassDB::bind_method(D_METHOD("obstacle_create"), &NavigationServer::obstacle_create);
ClassDB::bind_method(D_METHOD("obstacle_set_avoidance_enabled", "obstacle", "enabled"), &NavigationServer::obstacle_set_avoidance_enabled);
ClassDB::bind_method(D_METHOD("obstacle_get_avoidance_enabled", "obstacle"), &NavigationServer::obstacle_get_avoidance_enabled);
ClassDB::bind_method(D_METHOD("obstacle_set_use_3d_avoidance", "obstacle", "enabled"), &NavigationServer::obstacle_set_use_3d_avoidance);
ClassDB::bind_method(D_METHOD("obstacle_get_use_3d_avoidance", "obstacle"), &NavigationServer::obstacle_get_use_3d_avoidance);
ClassDB::bind_method(D_METHOD("obstacle_set_map", "obstacle", "map"), &NavigationServer::obstacle_set_map);
ClassDB::bind_method(D_METHOD("obstacle_get_map", "obstacle"), &NavigationServer::obstacle_get_map);
ClassDB::bind_method(D_METHOD("obstacle_set_radius", "obstacle", "radius"), &NavigationServer::obstacle_set_radius);
ClassDB::bind_method(D_METHOD("obstacle_set_paused", "obstacle", "paused"), &NavigationServer::obstacle_set_paused);
ClassDB::bind_method(D_METHOD("obstacle_get_paused", "obstacle"), &NavigationServer::obstacle_get_paused);
ClassDB::bind_method(D_METHOD("obstacle_set_height", "obstacle", "height"), &NavigationServer::obstacle_set_height);
ClassDB::bind_method(D_METHOD("obstacle_set_velocity", "obstacle", "velocity"), &NavigationServer::obstacle_set_velocity);
ClassDB::bind_method(D_METHOD("obstacle_set_position", "obstacle", "position"), &NavigationServer::obstacle_set_position);
ClassDB::bind_method(D_METHOD("obstacle_set_vertices", "obstacle", "vertices"), &NavigationServer::obstacle_set_vertices);
ClassDB::bind_method(D_METHOD("obstacle_set_avoidance_layers", "obstacle", "layers"), &NavigationServer::obstacle_set_avoidance_layers);

View File

@ -268,11 +268,15 @@ 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_paused(RID p_obstacle, bool p_paused) = 0;
virtual bool obstacle_get_paused(RID p_obstacle) const = 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<Vector3> &p_vertices) = 0;
virtual void obstacle_set_avoidance_layers(RID p_obstacle, uint32_t p_layers) = 0;