So, how can I improve this pathfinding routine?
[Pathfinding.h]
Code: Select all
class Node {
private:
u32 x, y;
bool Walkable;
bool Occupied;
Node * Parent;
f32 Cost;
public:
Node(
u32 X = 0,
u32 Y = 0,
bool walkable = true,
bool occupied = false
) : x(X), y(Y), Walkable(walkable), Occupied(occupied) {}
inline void setParent(Node * parent) {
Parent = parent;
}
inline void setCost(f32 cost) {
Cost = cost;
}
inline void setLocation(u32 X, u32 Y) {
x = X;
y = Y;
}
inline void setWalkable(bool walkable) {
Walkable = walkable;
}
inline void setOccupied(bool occupied) {
Occupied = occupied;
}
inline u32 &getLocationX() {
return x;
}
inline u32 &getLocationY() {
return y;
}
inline bool &isWalkable() {
return Walkable;
}
inline bool &isOccupied() {
return Occupied;
}
inline Node * getParent() {
return Parent;
}
inline f32 &getCost() {
return Cost;
}
};
class NodePool {
private:
Node * Pool;
u32 w, h;
void getSurroundingNodes(u32 x, u32 y, array<Node *> &nodes);
Node * getNodeWithLeastCost(array<Node *> &possible);
public:
NodePool(u32 x, u32 y, bool * WalkableFlags);
bool findPath(u32 sx, u32 sy, u32 ex, u32 ey, array<Node *> &path);
};
Code: Select all
#include <irrlicht.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdexcept>
#include <assert.h>
using namespace std;
using namespace irr;
using namespace core;
using namespace gui;
using namespace io;
using namespace scene;
using namespace video;
#include <Pathfinding.h>
#define POOL_ELEMENT(x, y) (&Pool[(x) * w + (y)])
NodePool::NodePool(u32 x, u32 y, bool * WalkableFlags) {
w = x;
h = y;
Pool = new Node[x * y];
for(u32 i = 0; i < w; i++) {
for(u32 d = 0; d < h; d++) {
Node *node = POOL_ELEMENT(i, d);
node->setLocation(i, d);
node->setWalkable(WalkableFlags[(i) * w + (d)]);
node->setOccupied(false);
}
}
}
void NodePool::getSurroundingNodes(u32 x, u32 y, array<Node *> &nodes) {
nodes.clear();
if(x > 0) nodes.push_back(POOL_ELEMENT(x - 1, y - 0));
if(y > 0) nodes.push_back(POOL_ELEMENT(x - 0, y - 1));
if(x < w) nodes.push_back(POOL_ELEMENT(x + 1, y + 0));
if(y < h) nodes.push_back(POOL_ELEMENT(x + 0, y + 1));
if(x < w && y < h) nodes.push_back(POOL_ELEMENT(x + 1, y + 1));
if(x > 0 && y < h) nodes.push_back(POOL_ELEMENT(x - 1, y + 1));
if(x > 0 && y > 0) nodes.push_back(POOL_ELEMENT(x - 1, y - 1));
if(x < w && y > 0) nodes.push_back(POOL_ELEMENT(x + 1, y - 1));
}
Node * NodePool::getNodeWithLeastCost(array<Node *> &possible) {
Node * ret = 0;
f32 cost = possible[0]->getCost();
ret = possible[0];
for(u32 i = 1; i < possible.size(); i++) {
if(possible[i]->getCost() < cost) {
ret = possible[i];
cost = ret->getCost();
}
}
return ret;
}
bool NodePool::findPath(u32 sx, u32 sy, u32 ex, u32 ey, array<Node *> &path) {
array<Node *> OpenList;
array<Node *> ClosedList;
OpenList.push_back(POOL_ELEMENT(sx, sy));
POOL_ELEMENT(sx, sy)->setCost(0);
while(OpenList.size()) {
Node * currentNode = getNodeWithLeastCost(OpenList);
ClosedList.push_back(currentNode);
OpenList.erase(OpenList.binary_search(currentNode));
if(currentNode->getLocationX() == ex && currentNode->getLocationY() == ey) {
array<Node *> tmpPath;
Node * node = POOL_ELEMENT(ex, ey);
while(node != POOL_ELEMENT(sx, sy)) {
tmpPath.push_back(node);
node = node->getParent();
assert(node);
}
tmpPath.push_back(POOL_ELEMENT(sx, sy));
printf("Path found from %ux%u to %ux%u with %u steps!\n", sx, sy, ex, ey, tmpPath.size());
for(u32 i = 0; i < tmpPath.size(); i++) {
path.push_back(tmpPath[tmpPath.size() - (1 + i)]);
}
return true;
}
array<Node *> adjecentNodes;
getSurroundingNodes(currentNode->getLocationX(), currentNode->getLocationY(), adjecentNodes);
for(u32 i = 0; i < adjecentNodes.size(); i++) {
if(ClosedList.binary_search(adjecentNodes[i]) != -1 || !adjecentNodes[i]->isWalkable()) {
// ignore it
} else {
if(OpenList.binary_search(adjecentNodes[i]) != -1) {
// its already on the open list
} else {
adjecentNodes[i]->setParent(currentNode);
adjecentNodes[i]->setCost(vector2df(sx, sy).getDistanceFrom(vector2df(adjecentNodes[i]->getLocationX(), adjecentNodes[i]->getLocationY())));
OpenList.push_back(adjecentNodes[i]);
}
}
}
}
return false;
}
[Test.cpp]
Code: Select all
bool WalkableMap[512 * 512];
memset(WalkableMap, 1, sizeof(bool) * 512 * 512);
NodePool * tmpPathfinding = new NodePool(512, 512, WalkableMap);
array<Node *> path;
if(tmpPathfinding->findPath(0, 0, 50, 50, path)) {
for(u32 i = 0; i < path.size(); i++) {
printf("--> Step %u: %ux%u\n", i, path[i]->getLocationX(), path[i]->getLocationY());
}
} else {
printf("Path not found!\n");
}