Using pass system for nodes instead of state field.
Housekeeping.
This commit is contained in:
@@ -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))
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user