From 100c66991b81eea19878f1da152b4ba114b416fb Mon Sep 17 00:00:00 2001 From: Katja Date: Tue, 4 Jun 2024 18:48:05 +0200 Subject: [PATCH] Using pass system for nodes instead of state field. Housekeeping. --- demo/bin/multilevel_astar.gd | 5 +++ src/MultilevelAStarEx.cpp | 81 +++++++++++++++++++++--------------- src/MultilevelAStarEx.h | 7 +++- 3 files changed, 57 insertions(+), 36 deletions(-) diff --git a/demo/bin/multilevel_astar.gd b/demo/bin/multilevel_astar.gd index 3abcdb6..e4fcc94 100644 --- a/demo/bin/multilevel_astar.gd +++ b/demo/bin/multilevel_astar.gd @@ -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)) diff --git a/src/MultilevelAStarEx.cpp b/src/MultilevelAStarEx.cpp index 3649944..74fc974 100644 --- a/src/MultilevelAStarEx.cpp +++ b/src/MultilevelAStarEx.cpp @@ -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 open; - std::vector closed; + std::vector 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(); } diff --git a/src/MultilevelAStarEx.h b/src/MultilevelAStarEx.h index f2e9bd9..c0a6d0b 100644 --- a/src/MultilevelAStarEx.h +++ b/src/MultilevelAStarEx.h @@ -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 _terrain; std::vector _units; std::vector _nodes;