Browse Source

Added ability to change A-star cost function

Fabian Mathews 8 years ago
parent
commit
b541402417
4 changed files with 31 additions and 3 deletions
  1. 22 3
      core/math/a_star.cpp
  2. 3 0
      core/math/a_star.h
  3. 3 0
      scene/scene_string_names.cpp
  4. 3 0
      scene/scene_string_names.h

+ 22 - 3
core/math/a_star.cpp

@@ -28,6 +28,8 @@
 /*************************************************************************/
 #include "a_star.h"
 #include "geometry.h"
+#include "scene/scene_string_names.h"
+#include "script_language.h"
 
 int AStar::get_available_point_id() const {
 
@@ -187,7 +189,7 @@ bool AStar::_solve(Point *begin_point, Point *end_point) {
 
 		Point *n = begin_point->neighbours[i];
 		n->prev_point = begin_point;
-		n->distance = n->pos.distance_to(begin_point->pos);
+		n->distance = _compute_cost(n->id, begin_point->id);
 		n->distance *= n->weight_scale;
 		n->last_pass = pass;
 		open_list.add(&n->list);
@@ -215,7 +217,7 @@ bool AStar::_solve(Point *begin_point, Point *end_point) {
 			Point *p = E->self();
 
 			real_t cost = p->distance;
-			cost += p->pos.distance_to(end_point->pos);
+			cost += _estimate_cost(p->id, end_point->id);
 			cost *= p->weight_scale;
 
 			if (cost < least_cost) {
@@ -233,7 +235,7 @@ bool AStar::_solve(Point *begin_point, Point *end_point) {
 
 			Point *e = p->neighbours[i];
 
-			real_t distance = p->pos.distance_to(e->pos) + p->distance;
+			real_t distance = _compute_cost(p->id, e->id) + p->distance;
 			distance *= e->weight_scale;
 
 			if (e->last_pass == pass) {
@@ -274,6 +276,20 @@ bool AStar::_solve(Point *begin_point, Point *end_point) {
 	return found_route;
 }
 
+float AStar::_estimate_cost(int p_from_id, int p_to_id) {
+	if (get_script_instance() && get_script_instance()->has_method(SceneStringNames::get_singleton()->_estimate_cost))
+		return get_script_instance()->call(SceneStringNames::get_singleton()->_estimate_cost, p_from_id, p_to_id);
+
+	return points[p_from_id]->pos.distance_to(points[p_to_id]->pos);
+}
+
+float AStar::_compute_cost(int p_from_id, int p_to_id) {
+	if (get_script_instance() && get_script_instance()->has_method(SceneStringNames::get_singleton()->_compute_cost))
+		return get_script_instance()->call(SceneStringNames::get_singleton()->_compute_cost, p_from_id, p_to_id);
+
+	return points[p_from_id]->pos.distance_to(points[p_to_id]->pos);
+}
+
 PoolVector<Vector3> AStar::get_point_path(int p_from_id, int p_to_id) {
 
 	ERR_FAIL_COND_V(!points.has(p_from_id), PoolVector<Vector3>());
@@ -395,6 +411,9 @@ void AStar::_bind_methods() {
 
 	ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStar::get_point_path);
 	ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStar::get_id_path);
+
+	BIND_VMETHOD(MethodInfo("_estimate_cost", PropertyInfo(Variant::INT, "from_id"), PropertyInfo(Variant::INT, "to_id")));
+	BIND_VMETHOD(MethodInfo("_compute_cost", PropertyInfo(Variant::INT, "from_id"), PropertyInfo(Variant::INT, "to_id")));
 }
 
 AStar::AStar() {

+ 3 - 0
core/math/a_star.h

@@ -93,6 +93,9 @@ class AStar : public Reference {
 protected:
 	static void _bind_methods();
 
+	virtual float _estimate_cost(int p_from_id, int p_to_id);
+	virtual float _compute_cost(int p_from_id, int p_to_id);
+
 public:
 	int get_available_point_id() const;
 

+ 3 - 0
scene/scene_string_names.cpp

@@ -32,6 +32,9 @@ SceneStringNames *SceneStringNames::singleton = NULL;
 
 SceneStringNames::SceneStringNames() {
 
+	_estimate_cost = StaticCString::create("_estimate_cost");
+	_compute_cost = StaticCString::create("_compute_cost");
+
 	resized = StaticCString::create("resized");
 	dot = StaticCString::create(".");
 	doubledot = StaticCString::create("..");

+ 3 - 0
scene/scene_string_names.h

@@ -49,6 +49,9 @@ class SceneStringNames {
 public:
 	_FORCE_INLINE_ static SceneStringNames *get_singleton() { return singleton; }
 
+	StringName _estimate_cost;
+	StringName _compute_cost;
+
 	StringName resized;
 	StringName dot;
 	StringName doubledot;