summaryrefslogtreecommitdiffstats
path: root/core/math
diff options
context:
space:
mode:
authorDanil Alexeev <danil@alexeev.xyz>2023-02-28 12:30:10 +0300
committerDanil Alexeev <danil@alexeev.xyz>2023-04-26 09:29:33 +0300
commit76ee3d4f3103fe824d7c59893782a54c2173b3a0 (patch)
treeaaa40d1e387ee51dbbb97a898f9c6c507ab7c501 /core/math
parent45cd5dcad39274da18440d6ea3c2121bec248eaa (diff)
downloadredot-engine-76ee3d4f3103fe824d7c59893782a54c2173b3a0.tar.gz
Allow negative coordinates in `AStarGrid2D`
Diffstat (limited to 'core/math')
-rw-r--r--core/math/a_star_grid_2d.cpp74
-rw-r--r--core/math/a_star_grid_2d.h15
2 files changed, 57 insertions, 32 deletions
diff --git a/core/math/a_star_grid_2d.cpp b/core/math/a_star_grid_2d.cpp
index 139dc3afb1..63f7c80bdd 100644
--- a/core/math/a_star_grid_2d.cpp
+++ b/core/math/a_star_grid_2d.cpp
@@ -32,6 +32,8 @@
#include "core/variant/typed_array.h"
+#define GET_POINT_UNCHECKED(m_id) points[m_id.y - region.position.y][m_id.x - region.position.x]
+
static real_t heuristic_euclidian(const Vector2i &p_from, const Vector2i &p_to) {
real_t dx = (real_t)ABS(p_to.x - p_from.x);
real_t dy = (real_t)ABS(p_to.y - p_from.y);
@@ -59,16 +61,29 @@ static real_t heuristic_chebyshev(const Vector2i &p_from, const Vector2i &p_to)
static real_t (*heuristics[AStarGrid2D::HEURISTIC_MAX])(const Vector2i &, const Vector2i &) = { heuristic_euclidian, heuristic_manhattan, heuristic_octile, heuristic_chebyshev };
+void AStarGrid2D::set_region(const Rect2i &p_region) {
+ ERR_FAIL_COND(p_region.size.x < 0 || p_region.size.y < 0);
+ if (p_region != region) {
+ region = p_region;
+ dirty = true;
+ }
+}
+
+Rect2i AStarGrid2D::get_region() const {
+ return region;
+}
+
void AStarGrid2D::set_size(const Size2i &p_size) {
+ WARN_DEPRECATED_MSG(R"(The "size" property is deprecated, use "region" instead.)");
ERR_FAIL_COND(p_size.x < 0 || p_size.y < 0);
- if (p_size != size) {
- size = p_size;
+ if (p_size != region.size) {
+ region.size = p_size;
dirty = true;
}
}
Size2i AStarGrid2D::get_size() const {
- return size;
+ return region.size;
}
void AStarGrid2D::set_offset(const Vector2 &p_offset) {
@@ -95,9 +110,11 @@ Size2 AStarGrid2D::get_cell_size() const {
void AStarGrid2D::update() {
points.clear();
- for (int64_t y = 0; y < size.y; y++) {
+ const int64_t end_x = region.position.x + region.size.width;
+ const int64_t end_y = region.position.y + region.size.height;
+ for (int64_t y = region.position.y; y < end_y; y++) {
LocalVector<Point> line;
- for (int64_t x = 0; x < size.x; x++) {
+ for (int64_t x = region.position.x; x < end_x; x++) {
line.push_back(Point(Vector2i(x, y), offset + Vector2(x, y) * cell_size));
}
points.push_back(line);
@@ -106,11 +123,11 @@ void AStarGrid2D::update() {
}
bool AStarGrid2D::is_in_bounds(int p_x, int p_y) const {
- return p_x >= 0 && p_x < size.width && p_y >= 0 && p_y < size.height;
+ return region.has_point(Vector2i(p_x, p_y));
}
bool AStarGrid2D::is_in_boundsv(const Vector2i &p_id) const {
- return p_id.x >= 0 && p_id.x < size.width && p_id.y >= 0 && p_id.y < size.height;
+ return region.has_point(p_id);
}
bool AStarGrid2D::is_dirty() const {
@@ -154,27 +171,27 @@ AStarGrid2D::Heuristic AStarGrid2D::get_default_estimate_heuristic() const {
void AStarGrid2D::set_point_solid(const Vector2i &p_id, bool p_solid) {
ERR_FAIL_COND_MSG(dirty, "Grid is not initialized. Call the update method.");
- ERR_FAIL_COND_MSG(!is_in_boundsv(p_id), vformat("Can't set if point is disabled. Point out of bounds (%s/%s, %s/%s).", p_id.x, size.width, p_id.y, size.height));
- points[p_id.y][p_id.x].solid = p_solid;
+ ERR_FAIL_COND_MSG(!is_in_boundsv(p_id), vformat("Can't set if point is disabled. Point %s out of bounds %s.", p_id, region));
+ GET_POINT_UNCHECKED(p_id).solid = p_solid;
}
bool AStarGrid2D::is_point_solid(const Vector2i &p_id) const {
ERR_FAIL_COND_V_MSG(dirty, false, "Grid is not initialized. Call the update method.");
- ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_id), false, vformat("Can't get if point is disabled. Point out of bounds (%s/%s, %s/%s).", p_id.x, size.width, p_id.y, size.height));
- return points[p_id.y][p_id.x].solid;
+ ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_id), false, vformat("Can't get if point is disabled. Point %s out of bounds %s.", p_id, region));
+ return GET_POINT_UNCHECKED(p_id).solid;
}
void AStarGrid2D::set_point_weight_scale(const Vector2i &p_id, real_t p_weight_scale) {
ERR_FAIL_COND_MSG(dirty, "Grid is not initialized. Call the update method.");
- ERR_FAIL_COND_MSG(!is_in_boundsv(p_id), vformat("Can't set point's weight scale. Point out of bounds (%s/%s, %s/%s).", p_id.x, size.width, p_id.y, size.height));
+ ERR_FAIL_COND_MSG(!is_in_boundsv(p_id), vformat("Can't set point's weight scale. Point %s out of bounds %s.", p_id, region));
ERR_FAIL_COND_MSG(p_weight_scale < 0.0, vformat("Can't set point's weight scale less than 0.0: %f.", p_weight_scale));
- points[p_id.y][p_id.x].weight_scale = p_weight_scale;
+ GET_POINT_UNCHECKED(p_id).weight_scale = p_weight_scale;
}
real_t AStarGrid2D::get_point_weight_scale(const Vector2i &p_id) const {
ERR_FAIL_COND_V_MSG(dirty, 0, "Grid is not initialized. Call the update method.");
- ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_id), 0, vformat("Can't get point's weight scale. Point out of bounds (%s/%s, %s/%s).", p_id.x, size.width, p_id.y, size.height));
- return points[p_id.y][p_id.x].weight_scale;
+ ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_id), 0, vformat("Can't get point's weight scale. Point %s out of bounds %s.", p_id, region));
+ return GET_POINT_UNCHECKED(p_id).weight_scale;
}
AStarGrid2D::Point *AStarGrid2D::_jump(Point *p_from, Point *p_to) {
@@ -285,15 +302,15 @@ void AStarGrid2D::_get_nbors(Point *p_point, LocalVector<Point *> &r_nbors) {
bool has_left = false;
bool has_right = false;
- if (p_point->id.x - 1 >= 0) {
+ if (p_point->id.x - 1 >= region.position.x) {
left = _get_point_unchecked(p_point->id.x - 1, p_point->id.y);
has_left = true;
}
- if (p_point->id.x + 1 < size.width) {
+ if (p_point->id.x + 1 < region.position.x + region.size.width) {
right = _get_point_unchecked(p_point->id.x + 1, p_point->id.y);
has_right = true;
}
- if (p_point->id.y - 1 >= 0) {
+ if (p_point->id.y - 1 >= region.position.y) {
top = _get_point_unchecked(p_point->id.x, p_point->id.y - 1);
if (has_left) {
top_left = _get_point_unchecked(p_point->id.x - 1, p_point->id.y - 1);
@@ -302,7 +319,7 @@ void AStarGrid2D::_get_nbors(Point *p_point, LocalVector<Point *> &r_nbors) {
top_right = _get_point_unchecked(p_point->id.x + 1, p_point->id.y - 1);
}
}
- if (p_point->id.y + 1 < size.height) {
+ if (p_point->id.y + 1 < region.position.y + region.size.height) {
bottom = _get_point_unchecked(p_point->id.x, p_point->id.y + 1);
if (has_left) {
bottom_left = _get_point_unchecked(p_point->id.x - 1, p_point->id.y + 1);
@@ -461,19 +478,19 @@ real_t AStarGrid2D::_compute_cost(const Vector2i &p_from_id, const Vector2i &p_t
void AStarGrid2D::clear() {
points.clear();
- size = Vector2i();
+ region = Rect2i();
}
Vector2 AStarGrid2D::get_point_position(const Vector2i &p_id) const {
ERR_FAIL_COND_V_MSG(dirty, Vector2(), "Grid is not initialized. Call the update method.");
- ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_id), Vector2(), vformat("Can't get point's position. Point out of bounds (%s/%s, %s/%s).", p_id.x, size.width, p_id.y, size.height));
- return points[p_id.y][p_id.x].pos;
+ ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_id), Vector2(), vformat("Can't get point's position. Point %s out of bounds %s.", p_id, region));
+ return GET_POINT_UNCHECKED(p_id).pos;
}
Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vector2i &p_to_id) {
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 out of bounds (%s/%s, %s/%s)", p_from_id.x, size.width, p_from_id.y, size.height));
- ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_to_id), Vector<Vector2>(), vformat("Can't get id path. Point out of bounds (%s/%s, %s/%s)", p_to_id.x, size.width, p_to_id.y, size.height));
+ 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));
Point *a = _get_point(p_from_id.x, p_from_id.y);
Point *b = _get_point(p_to_id.x, p_to_id.y);
@@ -520,8 +537,8 @@ Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vec
TypedArray<Vector2i> AStarGrid2D::get_id_path(const Vector2i &p_from_id, const Vector2i &p_to_id) {
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 out of bounds (%s/%s, %s/%s)", p_from_id.x, size.width, p_from_id.y, size.height));
- ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_to_id), TypedArray<Vector2i>(), vformat("Can't get id path. Point out of bounds (%s/%s, %s/%s)", p_to_id.x, size.width, p_to_id.y, size.height));
+ 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));
Point *a = _get_point(p_from_id.x, p_from_id.y);
Point *b = _get_point(p_to_id.x, p_to_id.y);
@@ -565,6 +582,8 @@ TypedArray<Vector2i> AStarGrid2D::get_id_path(const Vector2i &p_from_id, const V
}
void AStarGrid2D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_region", "region"), &AStarGrid2D::set_region);
+ ClassDB::bind_method(D_METHOD("get_region"), &AStarGrid2D::get_region);
ClassDB::bind_method(D_METHOD("set_size", "size"), &AStarGrid2D::set_size);
ClassDB::bind_method(D_METHOD("get_size"), &AStarGrid2D::get_size);
ClassDB::bind_method(D_METHOD("set_offset", "offset"), &AStarGrid2D::set_offset);
@@ -596,6 +615,7 @@ void AStarGrid2D::_bind_methods() {
GDVIRTUAL_BIND(_estimate_cost, "from_id", "to_id")
GDVIRTUAL_BIND(_compute_cost, "from_id", "to_id")
+ ADD_PROPERTY(PropertyInfo(Variant::RECT2I, "region"), "set_region", "get_region");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "size"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "cell_size"), "set_cell_size", "get_cell_size");
@@ -617,3 +637,5 @@ void AStarGrid2D::_bind_methods() {
BIND_ENUM_CONSTANT(DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES);
BIND_ENUM_CONSTANT(DIAGONAL_MODE_MAX);
}
+
+#undef GET_POINT_UNCHECKED
diff --git a/core/math/a_star_grid_2d.h b/core/math/a_star_grid_2d.h
index e4e62ec360..50df58e0e9 100644
--- a/core/math/a_star_grid_2d.h
+++ b/core/math/a_star_grid_2d.h
@@ -58,7 +58,7 @@ public:
};
private:
- Size2i size;
+ Rect2i region;
Vector2 offset;
Size2 cell_size = Size2(1, 1);
bool dirty = false;
@@ -107,21 +107,21 @@ private:
private: // Internal routines.
_FORCE_INLINE_ bool _is_walkable(int64_t p_x, int64_t p_y) const {
- if (p_x >= 0 && p_y >= 0 && p_x < size.width && p_y < size.height) {
- return !points[p_y][p_x].solid;
+ if (region.has_point(Vector2i(p_x, p_y))) {
+ return !points[p_y - region.position.y][p_x - region.position.x].solid;
}
return false;
}
_FORCE_INLINE_ Point *_get_point(int64_t p_x, int64_t p_y) {
- if (p_x >= 0 && p_y >= 0 && p_x < size.width && p_y < size.height) {
- return &points[p_y][p_x];
+ if (region.has_point(Vector2i(p_x, p_y))) {
+ return &points[p_y - region.position.y][p_x - region.position.x];
}
return nullptr;
}
_FORCE_INLINE_ Point *_get_point_unchecked(int64_t p_x, int64_t p_y) {
- return &points[p_y][p_x];
+ return &points[p_y - region.position.y][p_x - region.position.x];
}
void _get_nbors(Point *p_point, LocalVector<Point *> &r_nbors);
@@ -138,6 +138,9 @@ protected:
GDVIRTUAL2RC(real_t, _compute_cost, Vector2i, Vector2i)
public:
+ void set_region(const Rect2i &p_region);
+ Rect2i get_region() const;
+
void set_size(const Size2i &p_size);
Size2i get_size() const;