|
|
|
@ -42,55 +42,62 @@ All rights reserved. |
|
|
|
|
INCLUDE_game |
|
|
|
|
|
|
|
|
|
void Pathfinding::Initialize(){ |
|
|
|
|
if(nodes!=nullptr){ |
|
|
|
|
delete[] nodes; |
|
|
|
|
} |
|
|
|
|
nodes = NEW sNode[game->GetCurrentMapData().width * game->GetCurrentMapData().height]; |
|
|
|
|
nodes.clear(); |
|
|
|
|
sNode*lastNodeAdded=nullptr; |
|
|
|
|
for (int x = 0; x < game->GetCurrentMapData().width; x++) |
|
|
|
|
for (int y = 0; y < game->GetCurrentMapData().height; y++) |
|
|
|
|
{ |
|
|
|
|
nodes[y * game->GetCurrentMapData().width + x].x = x; // ...because we give each node its own coordinates
|
|
|
|
|
nodes[y * game->GetCurrentMapData().width + x].y = y; |
|
|
|
|
nodes.insert({x,y}); |
|
|
|
|
sNode node=*nodes.find({x,y}); |
|
|
|
|
node.x = x; // ...because we give each node its own coordinates
|
|
|
|
|
node.y = y; // ...because we give each node its own coordinates
|
|
|
|
|
geom2d::rect<int>tile=game->GetTileCollision(game->GetCurrentLevel(),{float(x*game->GetCurrentMapData().tilewidth),float(y*game->GetCurrentMapData().tilewidth)}); |
|
|
|
|
nodes[y * game->GetCurrentMapData().width + x].bObstacle = tile.pos!=game->NO_COLLISION.pos||tile.size!=game->NO_COLLISION.size; |
|
|
|
|
node.bObstacle = tile.pos!=game->NO_COLLISION.pos||tile.size!=game->NO_COLLISION.size; |
|
|
|
|
tile=game->GetTileCollision(game->GetCurrentLevel(),{float(x*game->GetCurrentMapData().tilewidth),float(y*game->GetCurrentMapData().tilewidth)},true); |
|
|
|
|
nodes[y * game->GetCurrentMapData().width + x].bObstacleUpper = tile.pos!=game->NO_COLLISION.pos||tile.size!=game->NO_COLLISION.size; |
|
|
|
|
nodes[y * game->GetCurrentMapData().width + x].parent = nullptr; |
|
|
|
|
nodes[y * game->GetCurrentMapData().width + x].bVisited = false; |
|
|
|
|
node.bObstacleUpper = tile.pos!=game->NO_COLLISION.pos||tile.size!=game->NO_COLLISION.size; |
|
|
|
|
node.parent = nullptr; |
|
|
|
|
node.bVisited = false; |
|
|
|
|
if(nodes.size()==1){//This is the first node added, set as the start node.
|
|
|
|
|
nodeStart=&node; |
|
|
|
|
} |
|
|
|
|
nodeEnd=&node; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (int x = 0; x < game->GetCurrentMapData().width; x++) |
|
|
|
|
for (int y = 0; y < game->GetCurrentMapData().height; y++) |
|
|
|
|
{ |
|
|
|
|
if(y>0) |
|
|
|
|
nodes[y*game->GetCurrentMapData().width + x].vecNeighbours.push_back(&nodes[(y - 1) * game->GetCurrentMapData().width + (x + 0)]); |
|
|
|
|
if(y<game->GetCurrentMapData().height-1) |
|
|
|
|
nodes[y*game->GetCurrentMapData().width + x].vecNeighbours.push_back(&nodes[(y + 1) * game->GetCurrentMapData().width + (x + 0)]); |
|
|
|
|
if (x>0) |
|
|
|
|
nodes[y*game->GetCurrentMapData().width + x].vecNeighbours.push_back(&nodes[(y + 0) * game->GetCurrentMapData().width + (x - 1)]); |
|
|
|
|
if(x<game->GetCurrentMapData().width-1) |
|
|
|
|
nodes[y*game->GetCurrentMapData().width + x].vecNeighbours.push_back(&nodes[(y + 0) * game->GetCurrentMapData().width + (x + 1)]); |
|
|
|
|
/*if (y>0 && x>0)
|
|
|
|
|
nodes[y*game->GetCurrentMapData().width + x].vecNeighbours.push_back(&nodes[(y - 1) * game->GetCurrentMapData().width + (x - 1)]); |
|
|
|
|
if (y<game->GetCurrentMapData().height-1 && x>0) |
|
|
|
|
nodes[y*game->GetCurrentMapData().width + x].vecNeighbours.push_back(&nodes[(y + 1) * game->GetCurrentMapData().width + (x - 1)]); |
|
|
|
|
if (y>0 && x<game->GetCurrentMapData().width-1) |
|
|
|
|
nodes[y*game->GetCurrentMapData().width + x].vecNeighbours.push_back(&nodes[(y - 1) * game->GetCurrentMapData().width + (x + 1)]); |
|
|
|
|
if (y<game->GetCurrentMapData().height - 1 && x<game->GetCurrentMapData().width-1) |
|
|
|
|
nodes[y*game->GetCurrentMapData().width + x].vecNeighbours.push_back(&nodes[(y + 1) * game->GetCurrentMapData().width + (x + 1)]);*/ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Manually position the start and end markers so they are not nullptr
|
|
|
|
|
nodeStart = &nodes[(game->GetCurrentMapData().height / 2) * game->GetCurrentMapData().width + 1]; |
|
|
|
|
nodeEnd = &nodes[(game->GetCurrentMapData().height / 2) * game->GetCurrentMapData().width + game->GetCurrentMapData().width-2]; |
|
|
|
|
sNode&node=const_cast<sNode&>(*nodes.find({x,y})); |
|
|
|
|
if(y>0){ |
|
|
|
|
if(nodes.find({x,y-1})!=nodes.end()){ |
|
|
|
|
node.vecNeighbours.push_back(&*nodes.find({x,y-1})); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if(y<game->GetCurrentMapData().height-1){ |
|
|
|
|
if(nodes.find({x,y+1})!=nodes.end()){ |
|
|
|
|
node.vecNeighbours.push_back(&*nodes.find({x,y+1})); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if(x>0){ |
|
|
|
|
if(nodes.find({x-1,y})!=nodes.end()){ |
|
|
|
|
node.vecNeighbours.push_back(&*nodes.find({x-1,y})); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if(x<game->GetCurrentMapData().width-1){ |
|
|
|
|
if(nodes.find({x+1,y})!=nodes.end()){ |
|
|
|
|
node.vecNeighbours.push_back(&*nodes.find({x+1,y})); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
std::vector<vf2d> Pathfinding::Solve_AStar(vf2d startPos,vf2d endPos,float maxRange,bool upperLevel){ |
|
|
|
|
float dist=float(sqrt(pow(endPos.x-startPos.x,2)+pow(endPos.y-startPos.y,2))); |
|
|
|
|
if(dist>maxRange*game->GetCurrentMapData().tilewidth)return {}; |
|
|
|
|
if(nodes.find(sNode{int(startPos.x),int(startPos.y)})==nodes.end())return{}; |
|
|
|
|
if(nodes.find(sNode{int(endPos.x),int(endPos.y)})==nodes.end())return{}; |
|
|
|
|
|
|
|
|
|
nodeStart=&nodes[int(startPos.y/game->GetCurrentMapData().tilewidth)*game->GetCurrentMapData().width+int(startPos.x/game->GetCurrentMapData().tilewidth)]; |
|
|
|
|
nodeEnd=&nodes[int(endPos.y/game->GetCurrentMapData().tilewidth)*game->GetCurrentMapData().width+int(endPos.x/game->GetCurrentMapData().tilewidth)]; |
|
|
|
|
nodeStart=const_cast<sNode*>(&*nodes.find(sNode{int(startPos.x),int(startPos.y)})); |
|
|
|
|
nodeEnd=const_cast<sNode*>(&*nodes.find(sNode{int(endPos.x),int(endPos.y)})); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
geom2d::rect<int>posPerimeter{{int(std::min(startPos.x,endPos.x)),int(std::min(startPos.y,endPos.y))},{int(abs(endPos.x-startPos.x)),int(abs(endPos.y-startPos.y))}}; |
|
|
|
@ -176,3 +183,125 @@ std::vector<vf2d> Pathfinding::Solve_AStar(vf2d startPos,vf2d endPos,float maxRa |
|
|
|
|
return {}; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Pathfinding::sSpline Pathfinding::Solve_WalkPath(vf2d startPos,vf2d endPos,float maxRange,bool upperLevel){ |
|
|
|
|
Pathfinding::sSpline newSpline{}; |
|
|
|
|
newSpline.Initialize(Solve_AStar(startPos,endPos,maxRange,upperLevel)); |
|
|
|
|
return newSpline; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void Pathfinding::sSpline::Initialize(const std::vector<vf2d>&points){ |
|
|
|
|
this->points.clear(); |
|
|
|
|
for(const vf2d&point:points){ |
|
|
|
|
this->points.push_back({point}); |
|
|
|
|
} |
|
|
|
|
fTotalSplineLength=0.f; |
|
|
|
|
for (int i = 0; i < this->points.size(); i++) |
|
|
|
|
{ |
|
|
|
|
fTotalSplineLength += (this->points[i].length = CalculateSegmentLength(i, true)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Pathfinding::sPoint2D Pathfinding::sSpline::GetSplinePoint(float t, bool bLooped){ |
|
|
|
|
int p0, p1, p2, p3; |
|
|
|
|
float t1=t; |
|
|
|
|
if (!bLooped) |
|
|
|
|
{ |
|
|
|
|
p1 = (int)t1 + 1; |
|
|
|
|
p2 = p1 + 1; |
|
|
|
|
p3 = p2 + 1; |
|
|
|
|
p0 = p1 - 1; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
p1 = (int)t1; |
|
|
|
|
p2 = (p1 + 1) % points.size(); |
|
|
|
|
p3 = (p2 + 1) % points.size(); |
|
|
|
|
p0 = p1 >= 1 ? p1 - 1 : points.size() - 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
t = t - (int)t; |
|
|
|
|
|
|
|
|
|
float tt = t * t; |
|
|
|
|
float ttt = tt * t; |
|
|
|
|
|
|
|
|
|
float q1 = -ttt + 2.0f*tt - t; |
|
|
|
|
float q2 = 3.0f*ttt - 5.0f*tt + 2.0f; |
|
|
|
|
float q3 = -3.0f*ttt + 4.0f*tt + t; |
|
|
|
|
float q4 = ttt - tt; |
|
|
|
|
|
|
|
|
|
float tx = 0.5f * (points[p0].pos.x * q1 + points[p1].pos.x * q2 + points[p2].pos.x * q3 + points[p3].pos.x * q4); |
|
|
|
|
float ty = 0.5f * (points[p0].pos.y * q1 + points[p1].pos.y * q2 + points[p2].pos.y * q3 + points[p3].pos.y * q4); |
|
|
|
|
|
|
|
|
|
return{ {tx, ty} }; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Pathfinding::sPoint2D Pathfinding::sSpline::GetSplineGradient(float t, bool bLooped){ |
|
|
|
|
int p0, p1, p2, p3; |
|
|
|
|
float t1=t; |
|
|
|
|
if (!bLooped) |
|
|
|
|
{ |
|
|
|
|
p1 = (int)t1 + 1; |
|
|
|
|
p2 = p1 + 1; |
|
|
|
|
p3 = p2 + 1; |
|
|
|
|
p0 = p1 - 1; |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
p1 = (int)t1; |
|
|
|
|
p2 = (p1 + 1) % points.size(); |
|
|
|
|
p3 = (p2 + 1) % points.size(); |
|
|
|
|
p0 = p1 >= 1 ? p1 - 1 : points.size() - 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
t = t - (int)t; |
|
|
|
|
|
|
|
|
|
float tt = t * t; |
|
|
|
|
float ttt = tt * t; |
|
|
|
|
|
|
|
|
|
float q1 = -3.0f * tt + 4.0f*t - 1; |
|
|
|
|
float q2 = 9.0f*tt - 10.0f*t; |
|
|
|
|
float q3 = -9.0f*tt + 8.0f*t + 1.0f; |
|
|
|
|
float q4 = 3.0f*tt - 2.0f*t; |
|
|
|
|
|
|
|
|
|
float tx = 0.5f * (points[p0].pos.x * q1 + points[p1].pos.x * q2 + points[p2].pos.x * q3 + points[p3].pos.x * q4); |
|
|
|
|
float ty = 0.5f * (points[p0].pos.y * q1 + points[p1].pos.y * q2 + points[p2].pos.y * q3 + points[p3].pos.y * q4); |
|
|
|
|
|
|
|
|
|
return{ {tx, ty} }; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
float Pathfinding::sSpline::CalculateSegmentLength(int node, bool bLooped){ |
|
|
|
|
float fLength = 0.0f; |
|
|
|
|
float fStepSize = 0.005; |
|
|
|
|
|
|
|
|
|
sPoint2D old_point, new_point; |
|
|
|
|
old_point = GetSplinePoint((float)node, bLooped); |
|
|
|
|
|
|
|
|
|
for (float t = 0; t < 1.0f; t += fStepSize) |
|
|
|
|
{ |
|
|
|
|
new_point = GetSplinePoint(fmod((float)node + t,1.0f), bLooped); |
|
|
|
|
fLength += sqrtf((new_point.pos.x - old_point.pos.x)*(new_point.pos.x - old_point.pos.x) |
|
|
|
|
+ (new_point.pos.y - old_point.pos.y)*(new_point.pos.y - old_point.pos.y)); |
|
|
|
|
old_point = new_point; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return fLength; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
float Pathfinding::sSpline::GetNormalisedOffset(float p){ |
|
|
|
|
// Which node is the base?
|
|
|
|
|
int i = 0; |
|
|
|
|
while (p > points[i].length) |
|
|
|
|
{ |
|
|
|
|
p -= points[i].length; |
|
|
|
|
i++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// The fractional is the offset
|
|
|
|
|
return (float)i + (p / points[i].length); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
inline bool operator < (const Pathfinding::sNode& lhs, const Pathfinding::sNode& rhs) |
|
|
|
|
{ return lhs.y < rhs.y || (lhs.y == rhs.y && lhs.x < rhs.x); } |
|
|
|
|
inline bool operator > (const Pathfinding::sNode& lhs, const Pathfinding::sNode& rhs) |
|
|
|
|
{ return lhs.y > rhs.y || (lhs.y == rhs.y && lhs.x > rhs.x); } |