From 610712a269c44b5e2649f08d508416a8a7cd9491 Mon Sep 17 00:00:00 2001 From: Chaosus Date: Mon, 21 Jul 2025 21:34:13 +0300 Subject: [PATCH] Add a way to filter neighbor points to AStar2D/3D --- core/math/a_star.cpp | 42 +++++++++++++++++++++++++++++++++++++++++ core/math/a_star.h | 9 +++++++++ doc/classes/AStar2D.xml | 14 ++++++++++++++ doc/classes/AStar3D.xml | 14 ++++++++++++++ 4 files changed, 79 insertions(+) diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index 1161a4732d..be581e825e 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -349,6 +349,13 @@ bool AStar3D::_solve(Point *begin_point, Point *end_point, bool p_allow_partial_ continue; } + if (neighbor_filter_enabled) { + bool filtered; + if (GDVIRTUAL_CALL(_filter_neighbor, p->id, e->id, filtered) && filtered) { + continue; + } + } + real_t tentative_g_score = p->g_score + _compute_cost(p->id, e->id) * e->weight_scale; bool new_point = false; @@ -524,6 +531,14 @@ Vector AStar3D::get_id_path(int64_t p_from_id, int64_t p_to_id, bool p_ return path; } +bool AStar3D::is_neighbor_filter_enabled() const { + return neighbor_filter_enabled; +} + +void AStar3D::set_neighbor_filter_enabled(bool p_enabled) { + neighbor_filter_enabled = p_enabled; +} + void AStar3D::set_point_disabled(int64_t p_id, bool p_disabled) { Point **p_entry = points.getptr(p_id); ERR_FAIL_COND_MSG(!p_entry, vformat("Can't set if point is disabled. Point with id: %d doesn't exist.", p_id)); @@ -555,6 +570,9 @@ void AStar3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_point_disabled", "id", "disabled"), &AStar3D::set_point_disabled, DEFVAL(true)); ClassDB::bind_method(D_METHOD("is_point_disabled", "id"), &AStar3D::is_point_disabled); + ClassDB::bind_method(D_METHOD("set_neighbor_filter_enabled", "enabled"), &AStar3D::set_neighbor_filter_enabled); + ClassDB::bind_method(D_METHOD("is_neighbor_filter_enabled"), &AStar3D::is_neighbor_filter_enabled); + ClassDB::bind_method(D_METHOD("connect_points", "id", "to_id", "bidirectional"), &AStar3D::connect_points, DEFVAL(true)); ClassDB::bind_method(D_METHOD("disconnect_points", "id", "to_id", "bidirectional"), &AStar3D::disconnect_points, DEFVAL(true)); ClassDB::bind_method(D_METHOD("are_points_connected", "id", "to_id", "bidirectional"), &AStar3D::are_points_connected, DEFVAL(true)); @@ -570,8 +588,11 @@ void AStar3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id", "allow_partial_path"), &AStar3D::get_point_path, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id", "allow_partial_path"), &AStar3D::get_id_path, DEFVAL(false)); + GDVIRTUAL_BIND(_filter_neighbor, "from_id", "neighbor_id") GDVIRTUAL_BIND(_estimate_cost, "from_id", "end_id") GDVIRTUAL_BIND(_compute_cost, "from_id", "to_id") + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "neighbor_filter_enabled"), "set_neighbor_filter_enabled", "is_neighbor_filter_enabled"); } AStar3D::~AStar3D() { @@ -621,6 +642,14 @@ PackedInt64Array AStar2D::get_point_ids() { return astar.get_point_ids(); } +bool AStar2D::is_neighbor_filter_enabled() const { + return astar.neighbor_filter_enabled; +} + +void AStar2D::set_neighbor_filter_enabled(bool p_enabled) { + astar.neighbor_filter_enabled = p_enabled; +} + void AStar2D::set_point_disabled(int64_t p_id, bool p_disabled) { astar.set_point_disabled(p_id, p_disabled); } @@ -854,6 +883,13 @@ bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point, boo continue; } + if (astar.neighbor_filter_enabled) { + bool filtered; + if (GDVIRTUAL_CALL(_filter_neighbor, p->id, e->id, filtered) && filtered) { + continue; + } + } + real_t tentative_g_score = p->g_score + _compute_cost(p->id, e->id) * e->weight_scale; bool new_point = false; @@ -895,6 +931,9 @@ void AStar2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_point_connections", "id"), &AStar2D::get_point_connections); ClassDB::bind_method(D_METHOD("get_point_ids"), &AStar2D::get_point_ids); + ClassDB::bind_method(D_METHOD("set_neighbor_filter_enabled", "enabled"), &AStar2D::set_neighbor_filter_enabled); + ClassDB::bind_method(D_METHOD("is_neighbor_filter_enabled"), &AStar2D::is_neighbor_filter_enabled); + ClassDB::bind_method(D_METHOD("set_point_disabled", "id", "disabled"), &AStar2D::set_point_disabled, DEFVAL(true)); ClassDB::bind_method(D_METHOD("is_point_disabled", "id"), &AStar2D::is_point_disabled); @@ -913,6 +952,9 @@ void AStar2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id", "allow_partial_path"), &AStar2D::get_point_path, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id", "allow_partial_path"), &AStar2D::get_id_path, DEFVAL(false)); + GDVIRTUAL_BIND(_filter_neighbor, "from_id", "neighbor_id") GDVIRTUAL_BIND(_estimate_cost, "from_id", "end_id") GDVIRTUAL_BIND(_compute_cost, "from_id", "to_id") + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "neighbor_filter_enabled"), "set_neighbor_filter_enabled", "is_neighbor_filter_enabled"); } diff --git a/core/math/a_star.h b/core/math/a_star.h index 87980021ef..523c4db098 100644 --- a/core/math/a_star.h +++ b/core/math/a_star.h @@ -113,6 +113,7 @@ class AStar3D : public RefCounted { AHashMap points; HashSet segments; Point *last_closest_point = nullptr; + bool neighbor_filter_enabled = false; bool _solve(Point *begin_point, Point *end_point, bool p_allow_partial_path); @@ -122,6 +123,7 @@ protected: virtual real_t _estimate_cost(int64_t p_from_id, int64_t p_end_id); virtual real_t _compute_cost(int64_t p_from_id, int64_t p_to_id); + GDVIRTUAL2RC(bool, _filter_neighbor, int64_t, int64_t) GDVIRTUAL2RC(real_t, _estimate_cost, int64_t, int64_t) GDVIRTUAL2RC(real_t, _compute_cost, int64_t, int64_t) @@ -144,6 +146,9 @@ public: Vector get_point_connections(int64_t p_id); PackedInt64Array get_point_ids(); + bool is_neighbor_filter_enabled() const; + void set_neighbor_filter_enabled(bool p_enabled); + void set_point_disabled(int64_t p_id, bool p_disabled = true); bool is_point_disabled(int64_t p_id) const; @@ -178,6 +183,7 @@ protected: virtual real_t _estimate_cost(int64_t p_from_id, int64_t p_end_id); virtual real_t _compute_cost(int64_t p_from_id, int64_t p_to_id); + GDVIRTUAL2RC(bool, _filter_neighbor, int64_t, int64_t) GDVIRTUAL2RC(real_t, _estimate_cost, int64_t, int64_t) GDVIRTUAL2RC(real_t, _compute_cost, int64_t, int64_t) @@ -200,6 +206,9 @@ public: Vector get_point_connections(int64_t p_id); PackedInt64Array get_point_ids(); + bool is_neighbor_filter_enabled() const; + void set_neighbor_filter_enabled(bool p_enabled); + void set_point_disabled(int64_t p_id, bool p_disabled = true); bool is_point_disabled(int64_t p_id) const; diff --git a/doc/classes/AStar2D.xml b/doc/classes/AStar2D.xml index 8fb9f06bba..1a27ef0dca 100644 --- a/doc/classes/AStar2D.xml +++ b/doc/classes/AStar2D.xml @@ -29,6 +29,15 @@ Note that this function is hidden in the default [AStar2D] class. + + + + + + Called when neighboring enters processing and if [member neighbor_filter_enabled] is [code]true[/code]. If [code]true[/code] is returned the point will not be processed. + Note that this function is hidden in the default [AStar2D] class. + + @@ -307,4 +316,9 @@ + + + If [code]true[/code] enables the filtering of neighbors via [method _filter_neighbor]. + + diff --git a/doc/classes/AStar3D.xml b/doc/classes/AStar3D.xml index 2deecca5c6..cc346b8a88 100644 --- a/doc/classes/AStar3D.xml +++ b/doc/classes/AStar3D.xml @@ -70,6 +70,15 @@ Note that this function is hidden in the default [AStar3D] class. + + + + + + Called when neighboring point enters processing and if [member neighbor_filter_enabled] is [code]true[/code]. If [code]true[/code] is returned the point will not be processed. + Note that this function is hidden in the default [AStar3D] class. + + @@ -346,4 +355,9 @@ + + + If [code]true[/code] enables the filtering of neighbors via [method _filter_neighbor]. + +