Using pass system for nodes instead of state field.

Housekeeping.
This commit is contained in:
2024-06-04 18:48:05 +02:00
parent cab520a7ae
commit 100c66991b
3 changed files with 57 additions and 36 deletions

View File

@@ -51,6 +51,11 @@ func set_terrain(point: Vector2i, type: MultilevelAStarEx.TerrainType) -> void:
_astar.set_terrain(point, type) _astar.set_terrain(point, type)
func is_blocked(point: Vector2i) -> bool:
assert(_used_rect.has_point(point))
return (_astar.get_terrain(point) == MultilevelAStarEx.BLOCKED) or _astar.get_unit(point)
func find_path(from: Vector2i, to: Vector2i, return_closest: bool = false) -> Array[Vector2i]: func find_path(from: Vector2i, to: Vector2i, return_closest: bool = false) -> Array[Vector2i]:
assert(_used_rect.has_point(from)) assert(_used_rect.has_point(from))
assert(_used_rect.has_point(to)) assert(_used_rect.has_point(to))

View File

@@ -17,18 +17,23 @@ using namespace godot;
static const int STRAIGHT_DISTANCE = 10; static const int STRAIGHT_DISTANCE = 10;
static const int DIAGONAL_DISTANCE = 14; static const int DIAGONAL_DISTANCE = 14;
Node::Node() { } Node::Node()
{
this->openPass = 0;
this->closedPass = 0;
}
Node::Node(int x, int y) Node::Node(int x, int y) : Node()
{ {
this->x = x; this->x = x;
this->y = y; this->y = y;
this->state = UNUSED;
} }
void Node::init(Node *parent, int distanceFromStart, const Vector2i &end) void Node::open(int pass, Node *parent, int distanceFromStart, const Vector2i &end)
{ {
this->state = OPEN; DEV_ASSERT(this->openPass != pass);
this->openPass = pass;
this->parent = parent; this->parent = parent;
this->distanceFromStart = distanceFromStart; this->distanceFromStart = distanceFromStart;
@@ -58,6 +63,29 @@ void Node::init(Node *parent, int distanceFromStart, const Vector2i &end)
} }
} }
void Node::close(int pass)
{
DEV_ASSERT(openPass == pass && closedPass != pass);
closedPass = pass;
}
Node::NodeState Node::state(int pass) const
{
if (closedPass == pass)
{
return CLOSED;
}
else if (openPass == pass)
{
return OPEN;
}
else
{
return UNUSED;
}
}
int Node::total_cost() const int Node::total_cost() const
{ {
return distanceFromStart + distanceToEnd; return distanceFromStart + distanceToEnd;
@@ -83,6 +111,7 @@ MultilevelAStarEx::MultilevelAStarEx()
//UtilityFunctions::print("Constructor."); //UtilityFunctions::print("Constructor.");
_init = false; _init = false;
_pass = 0;
} }
MultilevelAStarEx::~MultilevelAStarEx() MultilevelAStarEx::~MultilevelAStarEx()
@@ -211,29 +240,27 @@ Variant MultilevelAStarEx::find_path(const Vector2i &from, const Vector2i &to, b
DEV_ASSERT(_region.has_point(from)); DEV_ASSERT(_region.has_point(from));
DEV_ASSERT(_region.has_point(to)); DEV_ASSERT(_region.has_point(to));
_pass++;
Vector2i from2 = from - _trans; Vector2i from2 = from - _trans;
Vector2i to2 = to - _trans; Vector2i to2 = to - _trans;
Variant result;
std::vector<Node *> open; std::vector<Node *> open;
std::vector<Node*> closed;
open.reserve(_width * _height); open.reserve(_width * _height);
closed.reserve(_width * _height);
Node *closest = &NODES(from2.x, from2.y); Node *closest = &NODES(from2.x, from2.y);
closest->init(nullptr, 0, to2); closest->open(_pass, nullptr, 0, to2);
open.push_back(closest); open.push_back(closest);
auto process = [this, &open, &closed, &to2, &closest](Node *current, int x, int y, int distance) { auto process = [this, &open, &to2, &closest](Node *current, int x, int y, int distance) {
Node *node = &NODES(x, y); Node *node = &NODES(x, y);
if (node->state == Node::UNUSED) if (node->state(_pass) == Node::UNUSED)
{ {
node->init(current, current->distanceFromStart + distance, to2); node->open(_pass, current, current->distanceFromStart + distance, to2);
open.push_back(node); open.push_back(node);
} }
else if (node->state == Node::OPEN) else if (node->state(_pass) == Node::OPEN)
{ {
if (current->distanceFromStart < node->parent->distanceFromStart) if (current->distanceFromStart < node->parent->distanceFromStart)
{ {
@@ -256,7 +283,7 @@ Variant MultilevelAStarEx::find_path(const Vector2i &from, const Vector2i &to, b
} }
}; };
while (open.size() > 0) while (!open.empty())
{ {
// find closest to destination // find closest to destination
Node *current = open[0]; Node *current = open[0];
@@ -271,14 +298,12 @@ Variant MultilevelAStarEx::find_path(const Vector2i &from, const Vector2i &to, b
if (current->distanceToEnd == 0) if (current->distanceToEnd == 0)
{ {
// found the path // found the path
result = Variant(generate_path(current)); return Variant(generate_path(current));
goto cleanup;
} }
// close it // close it
current->state = Node::CLOSED; current->close(_pass);
open.erase(std::remove(open.begin(), open.end(), current), open.end()); open.erase(std::remove(open.begin(), open.end(), current), open.end());
closed.push_back(current);
// expand it // expand it
if (current->x - 1 >= 0) // left if (current->x - 1 >= 0) // left
@@ -339,23 +364,11 @@ Variant MultilevelAStarEx::find_path(const Vector2i &from, const Vector2i &to, b
} }
} }
// this is skipped if a path was found
if (return_closest) if (return_closest)
{ {
// return path to closest // return path to closest
result = Variant(generate_path(closest)); return Variant(generate_path(closest));
} }
cleanup: return Variant();
// release the nodes
for (Node *node : open)
{
node->state = Node::UNUSED;
}
for (Node *node : closed)
{
node->state = Node::UNUSED;
}
return result;
} }

View File

@@ -20,7 +20,7 @@ public:
}; };
private: private:
NodeState state; int openPass, closedPass;
int x, y; int x, y;
Node *parent; Node *parent;
@@ -30,7 +30,9 @@ private:
int distanceToEndForClosest; int distanceToEndForClosest;
Node(int x, int y); Node(int x, int y);
void init(Node *parent, int distanceFromStart, const Vector2i &end); void open(int pass, Node *parent, int distanceFromStart, const Vector2i &end);
void close(int pass);
NodeState state(int pass) const;
int total_cost() const; int total_cost() const;
public: public:
@@ -51,6 +53,7 @@ public:
private: private:
bool _init; bool _init;
int _pass;
std::vector<TerrainType> _terrain; std::vector<TerrainType> _terrain;
std::vector<bool> _units; std::vector<bool> _units;
std::vector<Node> _nodes; std::vector<Node> _nodes;