소스 검색

Add a way to filter neighbor points to AStar2D/3D

Chaosus 1 개월 전
부모
커밋
610712a269
4개의 변경된 파일79개의 추가작업 그리고 0개의 파일을 삭제
  1. 42 0
      core/math/a_star.cpp
  2. 9 0
      core/math/a_star.h
  3. 14 0
      doc/classes/AStar2D.xml
  4. 14 0
      doc/classes/AStar3D.xml

+ 42 - 0
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<int64_t> 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");
 }

+ 9 - 0
core/math/a_star.h

@@ -113,6 +113,7 @@ class AStar3D : public RefCounted {
 	AHashMap<int64_t, Point *> points;
 	HashSet<Segment, Segment> 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<int64_t> 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<int64_t> 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;
 

+ 14 - 0
doc/classes/AStar2D.xml

@@ -29,6 +29,15 @@
 				Note that this function is hidden in the default [AStar2D] class.
 			</description>
 		</method>
+		<method name="_filter_neighbor" qualifiers="virtual const">
+			<return type="bool" />
+			<param index="0" name="from_id" type="int" />
+			<param index="1" name="neighbor_id" type="int" />
+			<description>
+				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.
+			</description>
+		</method>
 		<method name="add_point">
 			<return type="void" />
 			<param index="0" name="id" type="int" />
@@ -307,4 +316,9 @@
 			</description>
 		</method>
 	</methods>
+	<members>
+		<member name="neighbor_filter_enabled" type="bool" setter="set_neighbor_filter_enabled" getter="is_neighbor_filter_enabled" default="false">
+			If [code]true[/code] enables the filtering of neighbors via [method _filter_neighbor].
+		</member>
+	</members>
 </class>

+ 14 - 0
doc/classes/AStar3D.xml

@@ -70,6 +70,15 @@
 				Note that this function is hidden in the default [AStar3D] class.
 			</description>
 		</method>
+		<method name="_filter_neighbor" qualifiers="virtual const">
+			<return type="bool" />
+			<param index="0" name="from_id" type="int" />
+			<param index="1" name="neighbor_id" type="int" />
+			<description>
+				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.
+			</description>
+		</method>
 		<method name="add_point">
 			<return type="void" />
 			<param index="0" name="id" type="int" />
@@ -346,4 +355,9 @@
 			</description>
 		</method>
 	</methods>
+	<members>
+		<member name="neighbor_filter_enabled" type="bool" setter="set_neighbor_filter_enabled" getter="is_neighbor_filter_enabled" default="false">
+			If [code]true[/code] enables the filtering of neighbors via [method _filter_neighbor].
+		</member>
+	</members>
 </class>