From 49a5f1dfe6820b01990f6248e4eb8c667d3e9589 Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Wed, 10 Jan 2024 10:52:23 -0500 Subject: [PATCH] Update A* pathfinding to use higher tile precision. --- Adventures in Lestoria/Monster.cpp | 2 +- Adventures in Lestoria/Pathfinding.cpp | 86 ++++++++++---------------- Adventures in Lestoria/Pathfinding.h | 8 ++- Adventures in Lestoria/Version.h | 2 +- 4 files changed, 41 insertions(+), 57 deletions(-) diff --git a/Adventures in Lestoria/Monster.cpp b/Adventures in Lestoria/Monster.cpp index db6f1f65..8aa7dc11 100644 --- a/Adventures in Lestoria/Monster.cpp +++ b/Adventures in Lestoria/Monster.cpp @@ -414,7 +414,7 @@ void Monster::StartPathfinding(float pathingTime){ void Monster::PathAroundBehavior(float fElapsedTime){ if(path.points.size()>0){ //Move towards the new path. - geom2d::line moveTowardsLine=geom2d::line(pos,path.GetSplinePoint(pathIndex).pos*float(game->GetCurrentMapData().tilewidth)); + geom2d::line moveTowardsLine=geom2d::line(pos,path.GetSplinePoint(pathIndex).pos); if(moveTowardsLine.length()>2){ SetPos(pos+moveTowardsLine.vector().norm()*100*fElapsedTime*GetMoveSpdMult()); if(moveTowardsLine.vector().x>0){ diff --git a/Adventures in Lestoria/Pathfinding.cpp b/Adventures in Lestoria/Pathfinding.cpp index 9919e167..eff23de2 100644 --- a/Adventures in Lestoria/Pathfinding.cpp +++ b/Adventures in Lestoria/Pathfinding.cpp @@ -44,16 +44,15 @@ INCLUDE_game void Pathfinding::Initialize(){ nodes.clear(); sNode*lastNodeAdded=nullptr; - for (int x = 0; x < game->GetCurrentMapData().width; x++) - for (int y = 0; y < game->GetCurrentMapData().height; y++) + for (int x = 0; x < game->GetCurrentMapData().width; x+=gridSpacing.x) + for (int y = 0; y < game->GetCurrentMapData().height; y+=gridSpacing.y) { - nodes.insert({x,y}); - sNode node=*nodes.find({x,y}); + sNode&node=nodes[{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::recttile=game->GetTileCollision(game->GetCurrentLevel(),{float(x*game->GetCurrentMapData().tilewidth),float(y*game->GetCurrentMapData().tilewidth)}); + geom2d::recttile=game->GetTileCollision(game->GetCurrentLevel(),{float(x*gridSpacing.x),float(y*gridSpacing.y)}); 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); + tile=game->GetTileCollision(game->GetCurrentLevel(),{float(x*gridSpacing.x),float(y*gridSpacing.y)},true); node.bObstacleUpper = tile.pos!=game->NO_COLLISION.pos||tile.size!=game->NO_COLLISION.size; node.parent = nullptr; node.bVisited = false; @@ -63,58 +62,44 @@ void Pathfinding::Initialize(){ nodeEnd=&node; } - for (int x = 0; x < game->GetCurrentMapData().width; x++) - for (int y = 0; y < game->GetCurrentMapData().height; y++) - { - sNode&node=const_cast(*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(yGetCurrentMapData().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(xGetCurrentMapData().width-1){ - if(nodes.find({x+1,y})!=nodes.end()){ - node.vecNeighbours.push_back(&*nodes.find({x+1,y})); - } - } - } + for (auto&[key,node]:nodes){ + if(nodes.find({node.x,node.y-1})!=nodes.end()){ + node.vecNeighbours.push_back(&node); + } + if(nodes.find({node.x,node.y+1})!=nodes.end()){ + node.vecNeighbours.push_back(&node); + } + if(nodes.find({node.x-1,node.y})!=nodes.end()){ + node.vecNeighbours.push_back(&node); + } + if(nodes.find({node.x+1,node.y})!=nodes.end()){ + node.vecNeighbours.push_back(&node); + } + } } std::vector 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=const_cast(&*nodes.find(sNode{int(startPos.x),int(startPos.y)})); - nodeEnd=const_cast(&*nodes.find(sNode{int(endPos.x),int(endPos.y)})); + if(nodes.find(startPos)==nodes.end())return{}; + if(nodes.find(endPos)==nodes.end())return{}; + nodeStart=&nodes[startPos]; + nodeEnd=&nodes[endPos]; geom2d::rectposPerimeter{{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))}}; posPerimeter.pos={int(std::clamp(posPerimeter.pos.x-maxRange*game->GetCurrentMapData().tilewidth,0.f,game->GetCurrentMapData().width*float(game->GetCurrentMapData().tilewidth))),int(std::clamp(posPerimeter.pos.y-maxRange*game->GetCurrentMapData().tilewidth,0.f,game->GetCurrentMapData().height*float(game->GetCurrentMapData().tilewidth)))}; posPerimeter.size={int(std::clamp(posPerimeter.size.x+maxRange*game->GetCurrentMapData().tilewidth*2,0.f,game->GetCurrentMapData().width*float(game->GetCurrentMapData().tilewidth)-posPerimeter.pos.x)),int(std::clamp(posPerimeter.size.y+maxRange*game->GetCurrentMapData().tilewidth*2,0.f,game->GetCurrentMapData().height*float(game->GetCurrentMapData().tilewidth)-posPerimeter.pos.y))}; - - for (int x = 0; x < game->GetCurrentMapData().width; x++){ - for (int y = 0; y < game->GetCurrentMapData().height; y++){ - if(geom2d::overlaps(posPerimeter,vi2d{x*game->GetCurrentMapData().tilewidth,y*game->GetCurrentMapData().tilewidth})){ - nodes[y*game->GetCurrentMapData().width + x].bVisited = false; - } else { - nodes[y*game->GetCurrentMapData().width + x].bVisited = true; - } - nodes[y*game->GetCurrentMapData().width + x].fGlobalGoal = INFINITY; - nodes[y*game->GetCurrentMapData().width + x].fLocalGoal = INFINITY; - nodes[y*game->GetCurrentMapData().width + x].parent = nullptr; // No parents + + for (auto&[key,node]:nodes){ + if(geom2d::overlaps(posPerimeter,vi2d{node.x,node.y})){ + node.bVisited = false; + }else{ + node.bVisited = true; } + node.fGlobalGoal = INFINITY; + node.fLocalGoal = INFINITY; + node.parent = nullptr; // No parents } auto distance = [](sNode* a, sNode* b) // For convenience @@ -299,9 +284,4 @@ float Pathfinding::sSpline::GetNormalisedOffset(float p){ // 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); } \ No newline at end of file +} \ No newline at end of file diff --git a/Adventures in Lestoria/Pathfinding.h b/Adventures in Lestoria/Pathfinding.h index 8820e283..e44b2ff5 100644 --- a/Adventures in Lestoria/Pathfinding.h +++ b/Adventures in Lestoria/Pathfinding.h @@ -37,6 +37,7 @@ All rights reserved. #pragma endregion #pragma once #include "olcPixelGameEngine.h" +#include struct Pathfinding{ struct sNode @@ -48,7 +49,7 @@ struct Pathfinding{ bool bVisited = false; // Have we searched this node before? float fGlobalGoal=0; // Distance to goal so far float fLocalGoal=0; // Distance to goal if we took the alternative route - std::vector vecNeighbours; // Connections to neighbours + std::vector vecNeighbours; // Connections to neighbours sNode* parent=nullptr; // Node connecting to this node that offers shortest parent }; @@ -69,13 +70,16 @@ struct Pathfinding{ float GetNormalisedOffset(float p); }; - std::setnodes; + std::mapnodes; sNode *nodeStart = nullptr; sNode *nodeEnd = nullptr; + const vi2d gridSpacing = {12,12}; //Decrease this for more precision + void Initialize(); //maxRange in tiles. Returns the path as points. + [[nodiscard]] std::vector Solve_AStar(vf2d startPos,vf2d endPos,float maxRange=8,bool upperLevel=false); sSpline Solve_WalkPath(vf2d startPos,vf2d endPos,float maxRange=8,bool upperLevel=false); }; \ No newline at end of file diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h index a91434e7..93f91c7f 100644 --- a/Adventures in Lestoria/Version.h +++ b/Adventures in Lestoria/Version.h @@ -39,7 +39,7 @@ All rights reserved. #define VERSION_MAJOR 0 #define VERSION_MINOR 2 #define VERSION_PATCH 1 -#define VERSION_BUILD 5582 +#define VERSION_BUILD 5583 #define stringify(a) stringify_(a) #define stringify_(a) #a