1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-26 22:57:00 +02:00

Pathfinding: make related code aware that layers exist

This commit is contained in:
ArseniyShestakov 2015-11-02 11:06:06 +03:00
parent 118039a368
commit b8253206c7
2 changed files with 80 additions and 33 deletions

View File

@ -79,7 +79,7 @@ void CPathfinder::calculatePaths()
//logGlobal->infoStream() << boost::format("Calculating paths for hero %s (adress %d) of player %d") % hero->name % hero % hero->tempOwner; //logGlobal->infoStream() << boost::format("Calculating paths for hero %s (adress %d) of player %d") % hero->name % hero % hero->tempOwner;
//initial tile - set cost on 0 and add to the queue //initial tile - set cost on 0 and add to the queue
CGPathNode &initialNode = *getNode(out.hpos); CGPathNode &initialNode = *getNode(out.hpos, hero->boat ? EPathfindingLayer::SAIL : EPathfindingLayer::LAND);
initialNode.turns = 0; initialNode.turns = 0;
initialNode.moveRemains = hero->movement; initialNode.moveRemains = hero->movement;
mq.push_back(&initialNode); mq.push_back(&initialNode);
@ -100,7 +100,7 @@ void CPathfinder::calculatePaths()
addNeighbours(cp->coord); addNeighbours(cp->coord);
for(auto & neighbour : neighbours) for(auto & neighbour : neighbours)
{ {
dp = getNode(neighbour); dp = getNode(neighbour, EPathfindingLayer::LAND);
dt = &gs->map->getTile(neighbour); dt = &gs->map->getTile(neighbour);
useEmbarkCost = 0; //0 - usual movement; 1 - embark; 2 - disembark useEmbarkCost = 0; //0 - usual movement; 1 - embark; 2 - disembark
@ -138,12 +138,12 @@ void CPathfinder::calculatePaths()
} //neighbours loop } //neighbours loop
//just add all passable teleport exits //just add all passable teleport exits
if(sTileObj) if(sTileObj && canVisitObject())
{ {
addTeleportExits(); addTeleportExits();
for(auto & neighbour : neighbours) for(auto & neighbour : neighbours)
{ {
dp = getNode(neighbour); dp = getNode(neighbour, EPathfindingLayer::LAND);
if(isBetterWay(movement, turn)) if(isBetterWay(movement, turn))
{ {
dp->moveRemains = movement; dp->moveRemains = movement;
@ -164,13 +164,18 @@ void CPathfinder::addNeighbours(const int3 &coord)
std::vector<int3> tiles; std::vector<int3> tiles;
gs->getNeighbours(*ct, coord, tiles, boost::logic::indeterminate, !cp->land); gs->getNeighbours(*ct, coord, tiles, boost::logic::indeterminate, !cp->land);
sTileObj = ct->topVisitableObj(coord == CGHeroInstance::convertPosition(hero->pos, false)); sTileObj = ct->topVisitableObj(coord == CGHeroInstance::convertPosition(hero->pos, false));
if(sTileObj) if(canVisitObject())
{ {
for(int3 tile: tiles) if(sTileObj)
{ {
if(canMoveBetween(tile, sTileObj->visitablePos())) for(int3 tile: tiles)
neighbours.push_back(tile); {
if(canMoveBetween(tile, sTileObj->visitablePos()))
neighbours.push_back(tile);
}
} }
else
vstd::concatenate(neighbours, tiles);
} }
else else
vstd::concatenate(neighbours, tiles); vstd::concatenate(neighbours, tiles);
@ -310,7 +315,20 @@ bool CPathfinder::isDestinationGuardian()
void CPathfinder::initializeGraph() void CPathfinder::initializeGraph()
{ {
int3 pos; int3 pos;
CGPathNode ***graph = out.nodes; CGPathNode ****graph = out.nodes;
const TerrainTile *tinfo;
auto addNode = [&](EPathfindingLayer layer)
{
CGPathNode &node = graph[pos.x][pos.y][pos.z][layer];
node.accessible = evaluateAccessibility(pos, tinfo);
node.turns = 0xff;
node.moveRemains = 0;
node.coord = pos;
node.land = tinfo->terType != ETerrainType::WATER;
node.theNodeBefore = nullptr;
node.layer = layer;
};
for(pos.x=0; pos.x < out.sizes.x; ++pos.x) for(pos.x=0; pos.x < out.sizes.x; ++pos.x)
{ {
for(pos.y=0; pos.y < out.sizes.y; ++pos.y) for(pos.y=0; pos.y < out.sizes.y; ++pos.y)
@ -318,21 +336,33 @@ void CPathfinder::initializeGraph()
for(pos.z=0; pos.z < out.sizes.z; ++pos.z) for(pos.z=0; pos.z < out.sizes.z; ++pos.z)
{ {
const TerrainTile *tinfo = &gs->map->getTile(pos); const TerrainTile *tinfo = &gs->map->getTile(pos);
CGPathNode &node = graph[pos.x][pos.y][pos.z]; switch (tinfo->terType)
node.accessible = evaluateAccessibility(pos, tinfo); {
node.turns = 0xff; case ETerrainType::WRONG:
node.moveRemains = 0; case ETerrainType::BORDER:
node.coord = pos; case ETerrainType::ROCK:
node.land = tinfo->terType != ETerrainType::WATER; break;
node.theNodeBefore = nullptr; case ETerrainType::WATER:
addNode(EPathfindingLayer::SAIL);
if(options.useFlying)
addNode(EPathfindingLayer::AIR);
if(options.useWaterWalking)
addNode(EPathfindingLayer::WATER);
break;
default:
addNode(EPathfindingLayer::LAND);
if(options.useFlying)
addNode(EPathfindingLayer::AIR);
break;
}
} }
} }
} }
} }
CGPathNode *CPathfinder::getNode(const int3 &coord) CGPathNode *CPathfinder::getNode(const int3 &coord, const EPathfindingLayer &layer)
{ {
return &out.nodes[coord.x][coord.y][coord.z]; return &out.nodes[coord.x][coord.y][coord.z][layer];
} }
CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const int3 &pos, const TerrainTile *tinfo) const CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const int3 &pos, const TerrainTile *tinfo) const
@ -415,6 +445,12 @@ bool CPathfinder::addTeleportWhirlpool(const CGWhirlpool * obj) const
return options.useTeleportWhirlpool && obj; return options.useTeleportWhirlpool && obj;
} }
bool CPathfinder::canVisitObject() const
{
//hero can't visit objects while walking on water or flying
return cp->layer == EPathfindingLayer::LAND || cp->layer == EPathfindingLayer::SAIL;
}
CGPathNode::CGPathNode() CGPathNode::CGPathNode()
:coord(-1,-1,-1) :coord(-1,-1,-1)
{ {
@ -455,13 +491,17 @@ CPathsInfo::CPathsInfo( const int3 &Sizes )
:sizes(Sizes) :sizes(Sizes)
{ {
hero = nullptr; hero = nullptr;
nodes = new CGPathNode**[sizes.x]; nodes = new CGPathNode***[sizes.x];
for(int i = 0; i < sizes.x; i++) for(int i = 0; i < sizes.x; i++)
{ {
nodes[i] = new CGPathNode*[sizes.y]; nodes[i] = new CGPathNode**[sizes.y];
for(int j = 0; j < sizes.y; j++) for(int j = 0; j < sizes.y; j++)
{ {
nodes[i][j] = new CGPathNode[sizes.z]; nodes[i][j] = new CGPathNode*[sizes.z];
for (int z = 0; z < sizes.z; z++)
{
nodes[i][j][z] = new CGPathNode[EPathfindingLayer::NUM_LAYERS];
}
} }
} }
} }
@ -472,6 +512,10 @@ CPathsInfo::~CPathsInfo()
{ {
for(int j = 0; j < sizes.y; j++) for(int j = 0; j < sizes.y; j++)
{ {
for (int z = 0; z < sizes.z; z++)
{
delete [] nodes[i][j][z];
}
delete [] nodes[i][j]; delete [] nodes[i][j];
} }
delete [] nodes[i]; delete [] nodes[i];
@ -479,21 +523,21 @@ CPathsInfo::~CPathsInfo()
delete [] nodes; delete [] nodes;
} }
const CGPathNode * CPathsInfo::getPathInfo( int3 tile ) const const CGPathNode * CPathsInfo::getPathInfo(const int3 &tile, const EPathfindingLayer &layer) const
{ {
boost::unique_lock<boost::mutex> pathLock(pathMx); boost::unique_lock<boost::mutex> pathLock(pathMx);
if(tile.x >= sizes.x || tile.y >= sizes.y || tile.z >= sizes.z) if(tile.x >= sizes.x || tile.y >= sizes.y || tile.z >= sizes.z || layer >= EPathfindingLayer::NUM_LAYERS)
return nullptr; return nullptr;
return &nodes[tile.x][tile.y][tile.z]; return &nodes[tile.x][tile.y][tile.z][layer];
} }
bool CPathsInfo::getPath( const int3 &dst, CGPath &out ) const bool CPathsInfo::getPath(const int3 &dst, const EPathfindingLayer &layer, CGPath &out) const
{ {
boost::unique_lock<boost::mutex> pathLock(pathMx); boost::unique_lock<boost::mutex> pathLock(pathMx);
out.nodes.clear(); out.nodes.clear();
const CGPathNode *curnode = &nodes[dst.x][dst.y][dst.z]; const CGPathNode *curnode = &nodes[dst.x][dst.y][dst.z][layer];
if(!curnode->theNodeBefore) if(!curnode->theNodeBefore)
return false; return false;
@ -507,12 +551,12 @@ bool CPathsInfo::getPath( const int3 &dst, CGPath &out ) const
return true; return true;
} }
int CPathsInfo::getDistance( int3 tile ) const int CPathsInfo::getDistance(const int3 &tile, const EPathfindingLayer &layer) const
{ {
boost::unique_lock<boost::mutex> pathLock(pathMx); boost::unique_lock<boost::mutex> pathLock(pathMx);
CGPath ret; CGPath ret;
if(getPath(tile, ret)) if(getPath(tile, layer, ret))
return ret.nodes.size(); return ret.nodes.size();
else else
return 255; return 255;

View File

@ -36,6 +36,7 @@ struct DLL_LINKAGE CGPathNode
ui32 moveRemains; //remaining tiles after hero reaches the tile ui32 moveRemains; //remaining tiles after hero reaches the tile
CGPathNode * theNodeBefore; CGPathNode * theNodeBefore;
int3 coord; //coordinates int3 coord; //coordinates
EPathfindingLayer layer;
CGPathNode(); CGPathNode();
bool reachable() const; bool reachable() const;
@ -57,13 +58,13 @@ struct DLL_LINKAGE CPathsInfo
const CGHeroInstance *hero; const CGHeroInstance *hero;
int3 hpos; int3 hpos;
int3 sizes; int3 sizes;
CGPathNode ***nodes; //[w][h][level] CGPathNode ****nodes; //[w][h][level][layer]
CPathsInfo(const int3 &Sizes); CPathsInfo(const int3 &Sizes);
~CPathsInfo(); ~CPathsInfo();
const CGPathNode * getPathInfo( int3 tile ) const; const CGPathNode * getPathInfo(const int3 &tile, const EPathfindingLayer &layer) const;
bool getPath(const int3 &dst, CGPath &out) const; bool getPath(const int3 &dst, const EPathfindingLayer &layer, CGPath &out) const;
int getDistance( int3 tile ) const; int getDistance(const int3 &tile, const EPathfindingLayer &layer) const;
}; };
class CPathfinder : private CGameInfoCallback class CPathfinder : private CGameInfoCallback
@ -113,7 +114,7 @@ private:
void initializeGraph(); void initializeGraph();
CGPathNode *getNode(const int3 &coord); CGPathNode *getNode(const int3 &coord, const EPathfindingLayer &layer);
CGPathNode::EAccessibility evaluateAccessibility(const int3 &pos, const TerrainTile *tinfo) const; CGPathNode::EAccessibility evaluateAccessibility(const int3 &pos, const TerrainTile *tinfo) const;
bool canMoveBetween(const int3 &a, const int3 &b) const; //checks only for visitable objects that may make moving between tiles impossible, not other conditions (like tiles itself accessibility) bool canMoveBetween(const int3 &a, const int3 &b) const; //checks only for visitable objects that may make moving between tiles impossible, not other conditions (like tiles itself accessibility)
@ -121,4 +122,6 @@ private:
bool addTeleportOneWay(const CGTeleport * obj) const; bool addTeleportOneWay(const CGTeleport * obj) const;
bool addTeleportOneWayRandom(const CGTeleport * obj) const; bool addTeleportOneWayRandom(const CGTeleport * obj) const;
bool addTeleportWhirlpool(const CGWhirlpool * obj) const; bool addTeleportWhirlpool(const CGWhirlpool * obj) const;
bool canVisitObject() const;
}; };