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)
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]:
assert(_used_rect.has_point(from))
assert(_used_rect.has_point(to))

View File

@@ -17,18 +17,23 @@ using namespace godot;
static const int STRAIGHT_DISTANCE = 10;
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->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->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
{
return distanceFromStart + distanceToEnd;
@@ -83,6 +111,7 @@ MultilevelAStarEx::MultilevelAStarEx()
//UtilityFunctions::print("Constructor.");
_init = false;
_pass = 0;
}
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(to));
_pass++;
Vector2i from2 = from - _trans;
Vector2i to2 = to - _trans;
Variant result;
std::vector<Node*> open;
std::vector<Node*> closed;
std::vector<Node *> open;
open.reserve(_width * _height);
closed.reserve(_width * _height);
Node *closest = &NODES(from2.x, from2.y);
closest->init(nullptr, 0, to2);
closest->open(_pass, nullptr, 0, to2);
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);
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);
}
else if (node->state == Node::OPEN)
else if (node->state(_pass) == Node::OPEN)
{
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
Node *current = open[0];
@@ -271,14 +298,12 @@ Variant MultilevelAStarEx::find_path(const Vector2i &from, const Vector2i &to, b
if (current->distanceToEnd == 0)
{
// found the path
result = Variant(generate_path(current));
goto cleanup;
return Variant(generate_path(current));
}
// close it
current->state = Node::CLOSED;
current->close(_pass);
open.erase(std::remove(open.begin(), open.end(), current), open.end());
closed.push_back(current);
// expand it
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)
{
// return path to closest
result = Variant(generate_path(closest));
return Variant(generate_path(closest));
}
cleanup:
// release the nodes
for (Node *node : open)
{
node->state = Node::UNUSED;
}
for (Node *node : closed)
{
node->state = Node::UNUSED;
}
return result;
return Variant();
}

View File

@@ -20,7 +20,7 @@ public:
};
private:
NodeState state;
int openPass, closedPass;
int x, y;
Node *parent;
@@ -30,7 +30,9 @@ private:
int distanceToEndForClosest;
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;
public:
@@ -51,6 +53,7 @@ public:
private:
bool _init;
int _pass;
std::vector<TerrainType> _terrain;
std::vector<bool> _units;
std::vector<Node> _nodes;