Update A* pathfinding to use higher tile precision.
This commit is contained in:
parent
5f1b07d8b5
commit
49a5f1dfe6
Adventures in Lestoria
@ -414,7 +414,7 @@ void Monster::StartPathfinding(float pathingTime){
|
|||||||
void Monster::PathAroundBehavior(float fElapsedTime){
|
void Monster::PathAroundBehavior(float fElapsedTime){
|
||||||
if(path.points.size()>0){
|
if(path.points.size()>0){
|
||||||
//Move towards the new path.
|
//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){
|
if(moveTowardsLine.length()>2){
|
||||||
SetPos(pos+moveTowardsLine.vector().norm()*100*fElapsedTime*GetMoveSpdMult());
|
SetPos(pos+moveTowardsLine.vector().norm()*100*fElapsedTime*GetMoveSpdMult());
|
||||||
if(moveTowardsLine.vector().x>0){
|
if(moveTowardsLine.vector().x>0){
|
||||||
|
@ -44,16 +44,15 @@ INCLUDE_game
|
|||||||
void Pathfinding::Initialize(){
|
void Pathfinding::Initialize(){
|
||||||
nodes.clear();
|
nodes.clear();
|
||||||
sNode*lastNodeAdded=nullptr;
|
sNode*lastNodeAdded=nullptr;
|
||||||
for (int x = 0; x < game->GetCurrentMapData().width; x++)
|
for (int x = 0; x < game->GetCurrentMapData().width; x+=gridSpacing.x)
|
||||||
for (int y = 0; y < game->GetCurrentMapData().height; y++)
|
for (int y = 0; y < game->GetCurrentMapData().height; y+=gridSpacing.y)
|
||||||
{
|
{
|
||||||
nodes.insert({x,y});
|
sNode&node=nodes[{x,y}];
|
||||||
sNode node=*nodes.find({x,y});
|
|
||||||
node.x = x; // ...because we give each node its own coordinates
|
node.x = x; // ...because we give each node its own coordinates
|
||||||
node.y = y; // ...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)});
|
geom2d::rect<int>tile=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;
|
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.bObstacleUpper = tile.pos!=game->NO_COLLISION.pos||tile.size!=game->NO_COLLISION.size;
|
||||||
node.parent = nullptr;
|
node.parent = nullptr;
|
||||||
node.bVisited = false;
|
node.bVisited = false;
|
||||||
@ -63,58 +62,44 @@ void Pathfinding::Initialize(){
|
|||||||
nodeEnd=&node;
|
nodeEnd=&node;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int x = 0; x < game->GetCurrentMapData().width; x++)
|
for (auto&[key,node]:nodes){
|
||||||
for (int y = 0; y < game->GetCurrentMapData().height; y++)
|
if(nodes.find({node.x,node.y-1})!=nodes.end()){
|
||||||
{
|
node.vecNeighbours.push_back(&node);
|
||||||
sNode&node=const_cast<sNode&>(*nodes.find({x,y}));
|
}
|
||||||
if(y>0){
|
if(nodes.find({node.x,node.y+1})!=nodes.end()){
|
||||||
if(nodes.find({x,y-1})!=nodes.end()){
|
node.vecNeighbours.push_back(&node);
|
||||||
node.vecNeighbours.push_back(&*nodes.find({x,y-1}));
|
}
|
||||||
}
|
if(nodes.find({node.x-1,node.y})!=nodes.end()){
|
||||||
}
|
node.vecNeighbours.push_back(&node);
|
||||||
if(y<game->GetCurrentMapData().height-1){
|
}
|
||||||
if(nodes.find({x,y+1})!=nodes.end()){
|
if(nodes.find({node.x+1,node.y})!=nodes.end()){
|
||||||
node.vecNeighbours.push_back(&*nodes.find({x,y+1}));
|
node.vecNeighbours.push_back(&node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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){
|
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)));
|
float dist=float(sqrt(pow(endPos.x-startPos.x,2)+pow(endPos.y-startPos.y,2)));
|
||||||
if(dist>maxRange*game->GetCurrentMapData().tilewidth)return {};
|
if(dist>maxRange*game->GetCurrentMapData().tilewidth)return {};
|
||||||
if(nodes.find(sNode{int(startPos.x),int(startPos.y)})==nodes.end())return{};
|
if(nodes.find(startPos)==nodes.end())return{};
|
||||||
if(nodes.find(sNode{int(endPos.x),int(endPos.y)})==nodes.end())return{};
|
if(nodes.find(endPos)==nodes.end())return{};
|
||||||
|
|
||||||
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)}));
|
|
||||||
|
|
||||||
|
nodeStart=&nodes[startPos];
|
||||||
|
nodeEnd=&nodes[endPos];
|
||||||
|
|
||||||
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))}};
|
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))}};
|
||||||
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.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))};
|
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 (auto&[key,node]:nodes){
|
||||||
for (int y = 0; y < game->GetCurrentMapData().height; y++){
|
if(geom2d::overlaps(posPerimeter,vi2d{node.x,node.y})){
|
||||||
if(geom2d::overlaps(posPerimeter,vi2d{x*game->GetCurrentMapData().tilewidth,y*game->GetCurrentMapData().tilewidth})){
|
node.bVisited = false;
|
||||||
nodes[y*game->GetCurrentMapData().width + x].bVisited = false;
|
}else{
|
||||||
} else {
|
node.bVisited = true;
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
node.fGlobalGoal = INFINITY;
|
||||||
|
node.fLocalGoal = INFINITY;
|
||||||
|
node.parent = nullptr; // No parents
|
||||||
}
|
}
|
||||||
|
|
||||||
auto distance = [](sNode* a, sNode* b) // For convenience
|
auto distance = [](sNode* a, sNode* b) // For convenience
|
||||||
@ -299,9 +284,4 @@ float Pathfinding::sSpline::GetNormalisedOffset(float p){
|
|||||||
|
|
||||||
// The fractional is the offset
|
// The fractional is the offset
|
||||||
return (float)i + (p / points[i].length);
|
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); }
|
|
@ -37,6 +37,7 @@ All rights reserved.
|
|||||||
#pragma endregion
|
#pragma endregion
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "olcPixelGameEngine.h"
|
#include "olcPixelGameEngine.h"
|
||||||
|
#include <set>
|
||||||
|
|
||||||
struct Pathfinding{
|
struct Pathfinding{
|
||||||
struct sNode
|
struct sNode
|
||||||
@ -48,7 +49,7 @@ struct Pathfinding{
|
|||||||
bool bVisited = false; // Have we searched this node before?
|
bool bVisited = false; // Have we searched this node before?
|
||||||
float fGlobalGoal=0; // Distance to goal so far
|
float fGlobalGoal=0; // Distance to goal so far
|
||||||
float fLocalGoal=0; // Distance to goal if we took the alternative route
|
float fLocalGoal=0; // Distance to goal if we took the alternative route
|
||||||
std::vector<const sNode*> vecNeighbours; // Connections to neighbours
|
std::vector<sNode*> vecNeighbours; // Connections to neighbours
|
||||||
sNode* parent=nullptr; // Node connecting to this node that offers shortest parent
|
sNode* parent=nullptr; // Node connecting to this node that offers shortest parent
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -69,13 +70,16 @@ struct Pathfinding{
|
|||||||
float GetNormalisedOffset(float p);
|
float GetNormalisedOffset(float p);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::set<sNode>nodes;
|
std::map<vi2d,sNode>nodes;
|
||||||
|
|
||||||
sNode *nodeStart = nullptr;
|
sNode *nodeStart = nullptr;
|
||||||
sNode *nodeEnd = nullptr;
|
sNode *nodeEnd = nullptr;
|
||||||
|
|
||||||
|
const vi2d gridSpacing = {12,12}; //Decrease this for more precision
|
||||||
|
|
||||||
void Initialize();
|
void Initialize();
|
||||||
//maxRange in tiles. Returns the path as points.
|
//maxRange in tiles. Returns the path as points.
|
||||||
|
[[nodiscard]]
|
||||||
std::vector<vf2d> Solve_AStar(vf2d startPos,vf2d endPos,float maxRange=8,bool upperLevel=false);
|
std::vector<vf2d> 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);
|
sSpline Solve_WalkPath(vf2d startPos,vf2d endPos,float maxRange=8,bool upperLevel=false);
|
||||||
};
|
};
|
@ -39,7 +39,7 @@ All rights reserved.
|
|||||||
#define VERSION_MAJOR 0
|
#define VERSION_MAJOR 0
|
||||||
#define VERSION_MINOR 2
|
#define VERSION_MINOR 2
|
||||||
#define VERSION_PATCH 1
|
#define VERSION_PATCH 1
|
||||||
#define VERSION_BUILD 5582
|
#define VERSION_BUILD 5583
|
||||||
|
|
||||||
#define stringify(a) stringify_(a)
|
#define stringify(a) stringify_(a)
|
||||||
#define stringify_(a) #a
|
#define stringify_(a) #a
|
||||||
|
Loading…
x
Reference in New Issue
Block a user