mirror of
https://github.com/godotengine/godot.git
synced 2024-11-24 21:22:48 +00:00
add partial path return option for astar
* AStar2D, AStar3D and AStarGrid2D now can return a partial path if the destination point isn't reachable but still in the map. This option is available for both get_point_path and get_id_path
This commit is contained in:
parent
f47f4a02c8
commit
aa1bbe1542
59
core/math/a_star.compat.inc
Normal file
59
core/math/a_star.compat.inc
Normal file
@ -0,0 +1,59 @@
|
||||
/**************************************************************************/
|
||||
/* a_star.compat.inc */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
|
||||
Vector<int64_t> AStar3D::_get_id_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id) {
|
||||
return get_id_path(p_from_id, p_to_id, false);
|
||||
}
|
||||
|
||||
Vector<Vector3> AStar3D::_get_point_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id) {
|
||||
return get_point_path(p_from_id, p_to_id, false);
|
||||
}
|
||||
|
||||
void AStar3D::_bind_compatibility_methods() {
|
||||
ClassDB::bind_compatibility_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStar3D::_get_id_path_bind_compat_88047);
|
||||
ClassDB::bind_compatibility_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStar3D::_get_point_path_bind_compat_88047);
|
||||
}
|
||||
|
||||
Vector<int64_t> AStar2D::_get_id_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id) {
|
||||
return get_id_path(p_from_id, p_to_id, false);
|
||||
}
|
||||
|
||||
Vector<Vector2> AStar2D::_get_point_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id) {
|
||||
return get_point_path(p_from_id, p_to_id, false);
|
||||
}
|
||||
|
||||
void AStar2D::_bind_compatibility_methods() {
|
||||
ClassDB::bind_compatibility_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStar2D::_get_id_path_bind_compat_88047);
|
||||
ClassDB::bind_compatibility_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStar2D::_get_point_path_bind_compat_88047);
|
||||
}
|
||||
|
||||
#endif // DISABLE_DEPRECATED
|
@ -29,6 +29,7 @@
|
||||
/**************************************************************************/
|
||||
|
||||
#include "a_star.h"
|
||||
#include "a_star.compat.inc"
|
||||
|
||||
#include "core/math/geometry_3d.h"
|
||||
#include "core/object/script_language.h"
|
||||
@ -319,6 +320,7 @@ Vector3 AStar3D::get_closest_position_in_segment(const Vector3 &p_point) const {
|
||||
}
|
||||
|
||||
bool AStar3D::_solve(Point *begin_point, Point *end_point) {
|
||||
last_closest_point = nullptr;
|
||||
pass++;
|
||||
|
||||
if (!end_point->enabled) {
|
||||
@ -332,11 +334,18 @@ bool AStar3D::_solve(Point *begin_point, Point *end_point) {
|
||||
|
||||
begin_point->g_score = 0;
|
||||
begin_point->f_score = _estimate_cost(begin_point->id, end_point->id);
|
||||
begin_point->abs_g_score = 0;
|
||||
begin_point->abs_f_score = _estimate_cost(begin_point->id, end_point->id);
|
||||
open_list.push_back(begin_point);
|
||||
|
||||
while (!open_list.is_empty()) {
|
||||
Point *p = open_list[0]; // The currently processed point.
|
||||
|
||||
// Find point closer to end_point, or same distance to end_point but closer to begin_point.
|
||||
if (last_closest_point == nullptr || last_closest_point->abs_f_score > p->abs_f_score || (last_closest_point->abs_f_score >= p->abs_f_score && last_closest_point->abs_g_score > p->abs_g_score)) {
|
||||
last_closest_point = p;
|
||||
}
|
||||
|
||||
if (p == end_point) {
|
||||
found_route = true;
|
||||
break;
|
||||
@ -368,6 +377,8 @@ bool AStar3D::_solve(Point *begin_point, Point *end_point) {
|
||||
e->prev_point = p;
|
||||
e->g_score = tentative_g_score;
|
||||
e->f_score = e->g_score + _estimate_cost(e->id, end_point->id);
|
||||
e->abs_g_score = tentative_g_score;
|
||||
e->abs_f_score = e->f_score - e->g_score;
|
||||
|
||||
if (new_point) { // The position of the new points is already known.
|
||||
sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptr());
|
||||
@ -414,7 +425,7 @@ real_t AStar3D::_compute_cost(int64_t p_from_id, int64_t p_to_id) {
|
||||
return from_point->pos.distance_to(to_point->pos);
|
||||
}
|
||||
|
||||
Vector<Vector3> AStar3D::get_point_path(int64_t p_from_id, int64_t p_to_id) {
|
||||
Vector<Vector3> AStar3D::get_point_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path) {
|
||||
Point *a = nullptr;
|
||||
bool from_exists = points.lookup(p_from_id, a);
|
||||
ERR_FAIL_COND_V_MSG(!from_exists, Vector<Vector3>(), vformat("Can't get point path. Point with id: %d doesn't exist.", p_from_id));
|
||||
@ -434,7 +445,12 @@ Vector<Vector3> AStar3D::get_point_path(int64_t p_from_id, int64_t p_to_id) {
|
||||
|
||||
bool found_route = _solve(begin_point, end_point);
|
||||
if (!found_route) {
|
||||
return Vector<Vector3>();
|
||||
if (!p_allow_partial_path || last_closest_point == nullptr) {
|
||||
return Vector<Vector3>();
|
||||
}
|
||||
|
||||
// Use closest point instead.
|
||||
end_point = last_closest_point;
|
||||
}
|
||||
|
||||
Point *p = end_point;
|
||||
@ -463,7 +479,7 @@ Vector<Vector3> AStar3D::get_point_path(int64_t p_from_id, int64_t p_to_id) {
|
||||
return path;
|
||||
}
|
||||
|
||||
Vector<int64_t> AStar3D::get_id_path(int64_t p_from_id, int64_t p_to_id) {
|
||||
Vector<int64_t> AStar3D::get_id_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path) {
|
||||
Point *a = nullptr;
|
||||
bool from_exists = points.lookup(p_from_id, a);
|
||||
ERR_FAIL_COND_V_MSG(!from_exists, Vector<int64_t>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_from_id));
|
||||
@ -483,7 +499,12 @@ Vector<int64_t> AStar3D::get_id_path(int64_t p_from_id, int64_t p_to_id) {
|
||||
|
||||
bool found_route = _solve(begin_point, end_point);
|
||||
if (!found_route) {
|
||||
return Vector<int64_t>();
|
||||
if (!p_allow_partial_path || last_closest_point == nullptr) {
|
||||
return Vector<int64_t>();
|
||||
}
|
||||
|
||||
// Use closest point instead.
|
||||
end_point = last_closest_point;
|
||||
}
|
||||
|
||||
Point *p = end_point;
|
||||
@ -555,8 +576,8 @@ void AStar3D::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_closest_point", "to_position", "include_disabled"), &AStar3D::get_closest_point, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("get_closest_position_in_segment", "to_position"), &AStar3D::get_closest_position_in_segment);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStar3D::get_point_path);
|
||||
ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStar3D::get_id_path);
|
||||
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(_estimate_cost, "from_id", "to_id")
|
||||
GDVIRTUAL_BIND(_compute_cost, "from_id", "to_id")
|
||||
@ -688,7 +709,7 @@ real_t AStar2D::_compute_cost(int64_t p_from_id, int64_t p_to_id) {
|
||||
return from_point->pos.distance_to(to_point->pos);
|
||||
}
|
||||
|
||||
Vector<Vector2> AStar2D::get_point_path(int64_t p_from_id, int64_t p_to_id) {
|
||||
Vector<Vector2> AStar2D::get_point_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path) {
|
||||
AStar3D::Point *a = nullptr;
|
||||
bool from_exists = astar.points.lookup(p_from_id, a);
|
||||
ERR_FAIL_COND_V_MSG(!from_exists, Vector<Vector2>(), vformat("Can't get point path. Point with id: %d doesn't exist.", p_from_id));
|
||||
@ -707,7 +728,12 @@ Vector<Vector2> AStar2D::get_point_path(int64_t p_from_id, int64_t p_to_id) {
|
||||
|
||||
bool found_route = _solve(begin_point, end_point);
|
||||
if (!found_route) {
|
||||
return Vector<Vector2>();
|
||||
if (!p_allow_partial_path || astar.last_closest_point == nullptr) {
|
||||
return Vector<Vector2>();
|
||||
}
|
||||
|
||||
// Use closest point instead.
|
||||
end_point = astar.last_closest_point;
|
||||
}
|
||||
|
||||
AStar3D::Point *p = end_point;
|
||||
@ -736,7 +762,7 @@ Vector<Vector2> AStar2D::get_point_path(int64_t p_from_id, int64_t p_to_id) {
|
||||
return path;
|
||||
}
|
||||
|
||||
Vector<int64_t> AStar2D::get_id_path(int64_t p_from_id, int64_t p_to_id) {
|
||||
Vector<int64_t> AStar2D::get_id_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path) {
|
||||
AStar3D::Point *a = nullptr;
|
||||
bool from_exists = astar.points.lookup(p_from_id, a);
|
||||
ERR_FAIL_COND_V_MSG(!from_exists, Vector<int64_t>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_from_id));
|
||||
@ -756,7 +782,12 @@ Vector<int64_t> AStar2D::get_id_path(int64_t p_from_id, int64_t p_to_id) {
|
||||
|
||||
bool found_route = _solve(begin_point, end_point);
|
||||
if (!found_route) {
|
||||
return Vector<int64_t>();
|
||||
if (!p_allow_partial_path || astar.last_closest_point == nullptr) {
|
||||
return Vector<int64_t>();
|
||||
}
|
||||
|
||||
// Use closest point instead.
|
||||
end_point = astar.last_closest_point;
|
||||
}
|
||||
|
||||
AStar3D::Point *p = end_point;
|
||||
@ -786,6 +817,7 @@ Vector<int64_t> AStar2D::get_id_path(int64_t p_from_id, int64_t p_to_id) {
|
||||
}
|
||||
|
||||
bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point) {
|
||||
astar.last_closest_point = nullptr;
|
||||
astar.pass++;
|
||||
|
||||
if (!end_point->enabled) {
|
||||
@ -799,11 +831,18 @@ bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point) {
|
||||
|
||||
begin_point->g_score = 0;
|
||||
begin_point->f_score = _estimate_cost(begin_point->id, end_point->id);
|
||||
begin_point->abs_g_score = 0;
|
||||
begin_point->abs_f_score = _estimate_cost(begin_point->id, end_point->id);
|
||||
open_list.push_back(begin_point);
|
||||
|
||||
while (!open_list.is_empty()) {
|
||||
AStar3D::Point *p = open_list[0]; // The currently processed point.
|
||||
|
||||
// Find point closer to end_point, or same distance to end_point but closer to begin_point.
|
||||
if (astar.last_closest_point == nullptr || astar.last_closest_point->abs_f_score > p->abs_f_score || (astar.last_closest_point->abs_f_score >= p->abs_f_score && astar.last_closest_point->abs_g_score > p->abs_g_score)) {
|
||||
astar.last_closest_point = p;
|
||||
}
|
||||
|
||||
if (p == end_point) {
|
||||
found_route = true;
|
||||
break;
|
||||
@ -835,6 +874,8 @@ bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point) {
|
||||
e->prev_point = p;
|
||||
e->g_score = tentative_g_score;
|
||||
e->f_score = e->g_score + _estimate_cost(e->id, end_point->id);
|
||||
e->abs_g_score = tentative_g_score;
|
||||
e->abs_f_score = e->f_score - e->g_score;
|
||||
|
||||
if (new_point) { // The position of the new points is already known.
|
||||
sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptr());
|
||||
@ -874,8 +915,8 @@ void AStar2D::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_closest_point", "to_position", "include_disabled"), &AStar2D::get_closest_point, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("get_closest_position_in_segment", "to_position"), &AStar2D::get_closest_position_in_segment);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStar2D::get_point_path);
|
||||
ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStar2D::get_id_path);
|
||||
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(_estimate_cost, "from_id", "to_id")
|
||||
GDVIRTUAL_BIND(_compute_cost, "from_id", "to_id")
|
||||
|
@ -60,6 +60,10 @@ class AStar3D : public RefCounted {
|
||||
real_t f_score = 0;
|
||||
uint64_t open_pass = 0;
|
||||
uint64_t closed_pass = 0;
|
||||
|
||||
// Used for getting closest_point_of_last_pathing_call.
|
||||
real_t abs_g_score = 0;
|
||||
real_t abs_f_score = 0;
|
||||
};
|
||||
|
||||
struct SortPoints {
|
||||
@ -109,6 +113,7 @@ class AStar3D : public RefCounted {
|
||||
|
||||
OAHashMap<int64_t, Point *> points;
|
||||
HashSet<Segment, Segment> segments;
|
||||
Point *last_closest_point = nullptr;
|
||||
|
||||
bool _solve(Point *begin_point, Point *end_point);
|
||||
|
||||
@ -121,6 +126,12 @@ protected:
|
||||
GDVIRTUAL2RC(real_t, _estimate_cost, int64_t, int64_t)
|
||||
GDVIRTUAL2RC(real_t, _compute_cost, int64_t, int64_t)
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
Vector<int64_t> _get_id_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id);
|
||||
Vector<Vector3> _get_point_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id);
|
||||
static void _bind_compatibility_methods();
|
||||
#endif
|
||||
|
||||
public:
|
||||
int64_t get_available_point_id() const;
|
||||
|
||||
@ -149,8 +160,8 @@ public:
|
||||
int64_t get_closest_point(const Vector3 &p_point, bool p_include_disabled = false) const;
|
||||
Vector3 get_closest_position_in_segment(const Vector3 &p_point) const;
|
||||
|
||||
Vector<Vector3> get_point_path(int64_t p_from_id, int64_t p_to_id);
|
||||
Vector<int64_t> get_id_path(int64_t p_from_id, int64_t p_to_id);
|
||||
Vector<Vector3> get_point_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path = false);
|
||||
Vector<int64_t> get_id_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path = false);
|
||||
|
||||
AStar3D() {}
|
||||
~AStar3D();
|
||||
@ -171,6 +182,12 @@ protected:
|
||||
GDVIRTUAL2RC(real_t, _estimate_cost, int64_t, int64_t)
|
||||
GDVIRTUAL2RC(real_t, _compute_cost, int64_t, int64_t)
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
Vector<int64_t> _get_id_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id);
|
||||
Vector<Vector2> _get_point_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id);
|
||||
static void _bind_compatibility_methods();
|
||||
#endif
|
||||
|
||||
public:
|
||||
int64_t get_available_point_id() const;
|
||||
|
||||
@ -199,8 +216,8 @@ public:
|
||||
int64_t get_closest_point(const Vector2 &p_point, bool p_include_disabled = false) const;
|
||||
Vector2 get_closest_position_in_segment(const Vector2 &p_point) const;
|
||||
|
||||
Vector<Vector2> get_point_path(int64_t p_from_id, int64_t p_to_id);
|
||||
Vector<int64_t> get_id_path(int64_t p_from_id, int64_t p_to_id);
|
||||
Vector<Vector2> get_point_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path = false);
|
||||
Vector<int64_t> get_id_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path = false);
|
||||
|
||||
AStar2D() {}
|
||||
~AStar2D() {}
|
||||
|
48
core/math/a_star_grid_2d.compat.inc
Normal file
48
core/math/a_star_grid_2d.compat.inc
Normal file
@ -0,0 +1,48 @@
|
||||
/**************************************************************************/
|
||||
/* a_star_grid_2d.compat.inc */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
|
||||
#include "core/variant/typed_array.h"
|
||||
|
||||
TypedArray<Vector2i> AStarGrid2D::_get_id_path_bind_compat_88047(const Vector2i &p_from_id, const Vector2i &p_to_id) {
|
||||
return get_id_path(p_from_id, p_to_id, false);
|
||||
}
|
||||
|
||||
Vector<Vector2> AStarGrid2D::_get_point_path_bind_compat_88047(const Vector2i &p_from_id, const Vector2i &p_to_id) {
|
||||
return get_point_path(p_from_id, p_to_id, false);
|
||||
}
|
||||
|
||||
void AStarGrid2D::_bind_compatibility_methods() {
|
||||
ClassDB::bind_compatibility_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStarGrid2D::_get_id_path_bind_compat_88047);
|
||||
ClassDB::bind_compatibility_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStarGrid2D::_get_point_path_bind_compat_88047);
|
||||
}
|
||||
|
||||
#endif // DISABLE_DEPRECATED
|
@ -29,6 +29,7 @@
|
||||
/**************************************************************************/
|
||||
|
||||
#include "a_star_grid_2d.h"
|
||||
#include "a_star_grid_2d.compat.inc"
|
||||
|
||||
#include "core/variant/typed_array.h"
|
||||
|
||||
@ -446,6 +447,7 @@ void AStarGrid2D::_get_nbors(Point *p_point, LocalVector<Point *> &r_nbors) {
|
||||
}
|
||||
|
||||
bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point) {
|
||||
last_closest_point = nullptr;
|
||||
pass++;
|
||||
|
||||
if (p_end_point->solid) {
|
||||
@ -459,12 +461,19 @@ bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point) {
|
||||
|
||||
p_begin_point->g_score = 0;
|
||||
p_begin_point->f_score = _estimate_cost(p_begin_point->id, p_end_point->id);
|
||||
p_begin_point->abs_g_score = 0;
|
||||
p_begin_point->abs_f_score = _estimate_cost(p_begin_point->id, p_end_point->id);
|
||||
open_list.push_back(p_begin_point);
|
||||
end = p_end_point;
|
||||
|
||||
while (!open_list.is_empty()) {
|
||||
Point *p = open_list[0]; // The currently processed point.
|
||||
|
||||
// Find point closer to end_point, or same distance to end_point but closer to begin_point.
|
||||
if (last_closest_point == nullptr || last_closest_point->abs_f_score > p->abs_f_score || (last_closest_point->abs_f_score >= p->abs_f_score && last_closest_point->abs_g_score > p->abs_g_score)) {
|
||||
last_closest_point = p;
|
||||
}
|
||||
|
||||
if (p == p_end_point) {
|
||||
found_route = true;
|
||||
break;
|
||||
@ -508,6 +517,9 @@ bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point) {
|
||||
e->g_score = tentative_g_score;
|
||||
e->f_score = e->g_score + _estimate_cost(e->id, p_end_point->id);
|
||||
|
||||
e->abs_g_score = tentative_g_score;
|
||||
e->abs_f_score = e->f_score - e->g_score;
|
||||
|
||||
if (new_point) { // The position of the new points is already known.
|
||||
sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptr());
|
||||
} else {
|
||||
@ -546,7 +558,7 @@ Vector2 AStarGrid2D::get_point_position(const Vector2i &p_id) const {
|
||||
return _get_point_unchecked(p_id)->pos;
|
||||
}
|
||||
|
||||
Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vector2i &p_to_id) {
|
||||
Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vector2i &p_to_id, bool p_allow_partial_path) {
|
||||
ERR_FAIL_COND_V_MSG(dirty, Vector<Vector2>(), "Grid is not initialized. Call the update method.");
|
||||
ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_from_id), Vector<Vector2>(), vformat("Can't get id path. Point %s out of bounds %s.", p_from_id, region));
|
||||
ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_to_id), Vector<Vector2>(), vformat("Can't get id path. Point %s out of bounds %s.", p_to_id, region));
|
||||
@ -565,7 +577,12 @@ Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vec
|
||||
|
||||
bool found_route = _solve(begin_point, end_point);
|
||||
if (!found_route) {
|
||||
return Vector<Vector2>();
|
||||
if (!p_allow_partial_path || last_closest_point == nullptr) {
|
||||
return Vector<Vector2>();
|
||||
}
|
||||
|
||||
// Use closest point instead.
|
||||
end_point = last_closest_point;
|
||||
}
|
||||
|
||||
Point *p = end_point;
|
||||
@ -594,7 +611,7 @@ Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vec
|
||||
return path;
|
||||
}
|
||||
|
||||
TypedArray<Vector2i> AStarGrid2D::get_id_path(const Vector2i &p_from_id, const Vector2i &p_to_id) {
|
||||
TypedArray<Vector2i> AStarGrid2D::get_id_path(const Vector2i &p_from_id, const Vector2i &p_to_id, bool p_allow_partial_path) {
|
||||
ERR_FAIL_COND_V_MSG(dirty, TypedArray<Vector2i>(), "Grid is not initialized. Call the update method.");
|
||||
ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_from_id), TypedArray<Vector2i>(), vformat("Can't get id path. Point %s out of bounds %s.", p_from_id, region));
|
||||
ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_to_id), TypedArray<Vector2i>(), vformat("Can't get id path. Point %s out of bounds %s.", p_to_id, region));
|
||||
@ -613,7 +630,12 @@ TypedArray<Vector2i> AStarGrid2D::get_id_path(const Vector2i &p_from_id, const V
|
||||
|
||||
bool found_route = _solve(begin_point, end_point);
|
||||
if (!found_route) {
|
||||
return TypedArray<Vector2i>();
|
||||
if (!p_allow_partial_path || last_closest_point == nullptr) {
|
||||
return TypedArray<Vector2i>();
|
||||
}
|
||||
|
||||
// Use closest point instead.
|
||||
end_point = last_closest_point;
|
||||
}
|
||||
|
||||
Point *p = end_point;
|
||||
@ -672,8 +694,8 @@ void AStarGrid2D::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("clear"), &AStarGrid2D::clear);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_point_position", "id"), &AStarGrid2D::get_point_position);
|
||||
ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStarGrid2D::get_point_path);
|
||||
ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStarGrid2D::get_id_path);
|
||||
ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id", "allow_partial_path"), &AStarGrid2D::get_point_path, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id", "allow_partial_path"), &AStarGrid2D::get_id_path, DEFVAL(false));
|
||||
|
||||
GDVIRTUAL_BIND(_estimate_cost, "from_id", "to_id")
|
||||
GDVIRTUAL_BIND(_compute_cost, "from_id", "to_id")
|
||||
|
@ -89,6 +89,10 @@ private:
|
||||
uint64_t open_pass = 0;
|
||||
uint64_t closed_pass = 0;
|
||||
|
||||
// Used for getting last_closest_point.
|
||||
real_t abs_g_score = 0;
|
||||
real_t abs_f_score = 0;
|
||||
|
||||
Point() {}
|
||||
|
||||
Point(const Vector2i &p_id, const Vector2 &p_pos) :
|
||||
@ -109,6 +113,7 @@ private:
|
||||
|
||||
LocalVector<LocalVector<Point>> points;
|
||||
Point *end = nullptr;
|
||||
Point *last_closest_point = nullptr;
|
||||
|
||||
uint64_t pass = 1;
|
||||
|
||||
@ -152,6 +157,12 @@ protected:
|
||||
GDVIRTUAL2RC(real_t, _estimate_cost, Vector2i, Vector2i)
|
||||
GDVIRTUAL2RC(real_t, _compute_cost, Vector2i, Vector2i)
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
TypedArray<Vector2i> _get_id_path_bind_compat_88047(const Vector2i &p_from, const Vector2i &p_to);
|
||||
Vector<Vector2> _get_point_path_bind_compat_88047(const Vector2i &p_from, const Vector2i &p_to);
|
||||
static void _bind_compatibility_methods();
|
||||
#endif
|
||||
|
||||
public:
|
||||
void set_region(const Rect2i &p_region);
|
||||
Rect2i get_region() const;
|
||||
@ -198,8 +209,8 @@ public:
|
||||
void clear();
|
||||
|
||||
Vector2 get_point_position(const Vector2i &p_id) const;
|
||||
Vector<Vector2> get_point_path(const Vector2i &p_from, const Vector2i &p_to);
|
||||
TypedArray<Vector2i> get_id_path(const Vector2i &p_from, const Vector2i &p_to);
|
||||
Vector<Vector2> get_point_path(const Vector2i &p_from, const Vector2i &p_to, bool p_allow_partial_path = false);
|
||||
TypedArray<Vector2i> get_id_path(const Vector2i &p_from, const Vector2i &p_to, bool p_allow_partial_path = false);
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(AStarGrid2D::DiagonalMode);
|
||||
|
@ -139,8 +139,10 @@
|
||||
<return type="PackedInt64Array" />
|
||||
<param index="0" name="from_id" type="int" />
|
||||
<param index="1" name="to_id" type="int" />
|
||||
<param index="2" name="allow_partial_path" type="bool" default="false" />
|
||||
<description>
|
||||
Returns an array with the IDs of the points that form the path found by AStar2D between the given points. The array is ordered from the starting point to the ending point of the path.
|
||||
If there is no valid path to the target, and [param allow_partial_path] is [code]true[/code], returns a path to the point closest to the target that can be reached.
|
||||
[codeblocks]
|
||||
[gdscript]
|
||||
var astar = AStar2D.new()
|
||||
@ -228,8 +230,10 @@
|
||||
<return type="PackedVector2Array" />
|
||||
<param index="0" name="from_id" type="int" />
|
||||
<param index="1" name="to_id" type="int" />
|
||||
<param index="2" name="allow_partial_path" type="bool" default="false" />
|
||||
<description>
|
||||
Returns an array with the points that are in the path found by AStar2D between the given points. The array is ordered from the starting point to the ending point of the path.
|
||||
If there is no valid path to the target, and [param allow_partial_path] is [code]true[/code], returns a path to the point closest to the target that can be reached.
|
||||
[b]Note:[/b] This method is not thread-safe. If called from a [Thread], it will return an empty [PackedVector2Array] and will print an error message.
|
||||
</description>
|
||||
</method>
|
||||
|
@ -168,8 +168,10 @@
|
||||
<return type="PackedInt64Array" />
|
||||
<param index="0" name="from_id" type="int" />
|
||||
<param index="1" name="to_id" type="int" />
|
||||
<param index="2" name="allow_partial_path" type="bool" default="false" />
|
||||
<description>
|
||||
Returns an array with the IDs of the points that form the path found by AStar3D between the given points. The array is ordered from the starting point to the ending point of the path.
|
||||
If there is no valid path to the target, and [param allow_partial_path] is [code]true[/code], returns a path to the point closest to the target that can be reached.
|
||||
[codeblocks]
|
||||
[gdscript]
|
||||
var astar = AStar3D.new()
|
||||
@ -255,8 +257,10 @@
|
||||
<return type="PackedVector3Array" />
|
||||
<param index="0" name="from_id" type="int" />
|
||||
<param index="1" name="to_id" type="int" />
|
||||
<param index="2" name="allow_partial_path" type="bool" default="false" />
|
||||
<description>
|
||||
Returns an array with the points that are in the path found by AStar3D between the given points. The array is ordered from the starting point to the ending point of the path.
|
||||
If there is no valid path to the target, and [param allow_partial_path] is [code]true[/code], returns a path to the point closest to the target that can be reached.
|
||||
[b]Note:[/b] This method is not thread-safe. If called from a [Thread], it will return an empty [PackedVector3Array] and will print an error message.
|
||||
</description>
|
||||
</method>
|
||||
|
@ -75,16 +75,20 @@
|
||||
<return type="Vector2i[]" />
|
||||
<param index="0" name="from_id" type="Vector2i" />
|
||||
<param index="1" name="to_id" type="Vector2i" />
|
||||
<param index="2" name="allow_partial_path" type="bool" default="false" />
|
||||
<description>
|
||||
Returns an array with the IDs of the points that form the path found by AStar2D between the given points. The array is ordered from the starting point to the ending point of the path.
|
||||
If there is no valid path to the target, and [param allow_partial_path] is [code]true[/code], returns a path to the point closest to the target that can be reached.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_point_path">
|
||||
<return type="PackedVector2Array" />
|
||||
<param index="0" name="from_id" type="Vector2i" />
|
||||
<param index="1" name="to_id" type="Vector2i" />
|
||||
<param index="2" name="allow_partial_path" type="bool" default="false" />
|
||||
<description>
|
||||
Returns an array with the points that are in the path found by [AStarGrid2D] between the given points. The array is ordered from the starting point to the ending point of the path.
|
||||
If there is no valid path to the target, and [param allow_partial_path] is [code]true[/code], returns a path to the point closest to the target that can be reached.
|
||||
[b]Note:[/b] This method is not thread-safe. If called from a [Thread], it will return an empty [PackedVector3Array] and will print an error message.
|
||||
</description>
|
||||
</method>
|
||||
|
@ -255,3 +255,16 @@ GH-89992
|
||||
Validate extension JSON: Error: Field 'classes/Node/methods/replace_by/arguments': size changed value in new API, from 2 to 3.
|
||||
|
||||
Added optional argument to prevent children to be reparented during replace_by. Compatibility method registered.
|
||||
|
||||
|
||||
GH-88047
|
||||
--------
|
||||
Validate extension JSON: Error: Field 'classes/AStar2D/methods/get_id_path/arguments': size changed value in new API, from 2 to 3.
|
||||
Validate extension JSON: Error: Field 'classes/AStar2D/methods/get_point_path/arguments': size changed value in new API, from 2 to 3.
|
||||
Validate extension JSON: Error: Field 'classes/AStar3D/methods/get_id_path/arguments': size changed value in new API, from 2 to 3.
|
||||
Validate extension JSON: Error: Field 'classes/AStar3D/methods/get_point_path/arguments': size changed value in new API, from 2 to 3.
|
||||
Validate extension JSON: Error: Field 'classes/AStarGrid2D/methods/get_id_path/arguments': size changed value in new API, from 2 to 3.
|
||||
Validate extension JSON: Error: Field 'classes/AStarGrid2D/methods/get_point_path/arguments': size changed value in new API, from 2 to 3.
|
||||
|
||||
Added optional "allow_partial_path" argument to get_id_path and get_point_path methods in AStar classes.
|
||||
Compatibility methods registered.
|
||||
|
Loading…
Reference in New Issue
Block a user