Fix issue #77 and improve findPath

This commit is contained in:
Eduardo Bart 2012-08-21 23:10:56 -03:00
parent 3d7e80ea7a
commit 64d607b59e
7 changed files with 64 additions and 25 deletions

View File

@ -405,7 +405,7 @@ function processMouseAction(menuPosition, mouseButton, autoWalkPos, lookThing, u
end end
if autoWalkPos and keyboardModifiers == KeyboardNoModifier and mouseButton == MouseLeftButton then if autoWalkPos and keyboardModifiers == KeyboardNoModifier and mouseButton == MouseLeftButton then
local dirs = g_map.findPath(g_game.getLocalPlayer():getPosition(), autoWalkPos, 127) local dirs = g_map.findPath(g_game.getLocalPlayer():getPosition(), autoWalkPos, 127, PathFindFlags.AllowNullTiles)
if #dirs == 0 then if #dirs == 0 then
modules.game_textmessage.displayStatusMessage(tr('There is no way.')) modules.game_textmessage.displayStatusMessage(tr('There is no way.'))
return true return true

View File

@ -160,9 +160,9 @@ function onMinimapMouseRelease(self, mousePosition, mouseButton)
navigating = false navigating = false
return return
end end
local tile = self:getTile(mousePosition) local pos = self:getPosition(mousePosition)
if tile and mouseButton == MouseLeftButton and self:isPressed() then if pos and mouseButton == MouseLeftButton and self:isPressed() then
local dirs = g_map.findPath(g_game.getLocalPlayer():getPosition(), tile:getPosition(), 127) local dirs = g_map.findPath(g_game.getLocalPlayer():getPosition(), pos, 127, PathFindFlags.AllowNullTiles)
if #dirs == 0 then if #dirs == 0 then
modules.game_textmessage.displayStatusMessage(tr('There is no way.')) modules.game_textmessage.displayStatusMessage(tr('There is no way.'))
return true return true

View File

@ -156,4 +156,19 @@ OsTypes = {
OtclientMac = 12 OtclientMac = 12
} }
PathFindResults = {
Ok = 0,
Position = 1,
Impossipble = 2,
TooFar = 3,
NoWay = 4
}
PathFindFlags = {
AllowNullTiles = 1,
AllowCreatures = 2,
AllowNonPathable = 4,
AllowNonWalkable = 8
}
-- @} -- @}

View File

@ -341,11 +341,18 @@ namespace Otc
}; };
enum PathFindResult { enum PathFindResult {
PATHFIND_OK = 0, PATHFIND_RESULT_OK = 0,
PATHFIND_SAME_POSITION, PATHFIND_RESULT_SAME_POSITION,
PATHFIND_IMPOSSIBLE, PATHFIND_RESULT_IMPOSSIBLE,
PATHFIND_TOO_FAR, PATHFIND_RESULT_TOO_FAR,
PATHFIND_NO_WAY PATHFIND_RESULT_NO_WAY
};
enum PathFindFlag {
PATHFIND_ALLOW_NULLTILES = 1,
PATHFIND_ALLOW_CREATURES = 2,
PATHFIND_ALLOW_NONPATHABLE = 4,
PATHFIND_ALLOW_NONWALKABLE = 8
}; };
} }

View File

@ -428,7 +428,7 @@ int Map::getLastAwareFloor()
return Otc::SEA_FLOOR; return Otc::SEA_FLOOR;
} }
std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> Map::findPath(const Position& startPos, const Position& goalPos, int maxSteps) std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> Map::findPath(const Position& startPos, const Position& goalPos, int maxSteps, int flags)
{ {
// pathfinding using A* search algorithm // pathfinding using A* search algorithm
// as described in http://en.wikipedia.org/wiki/A*_search_algorithm // as described in http://en.wikipedia.org/wiki/A*_search_algorithm
@ -455,20 +455,20 @@ std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> Map::findPath(const
std::vector<Otc::Direction>& dirs = std::get<0>(ret); std::vector<Otc::Direction>& dirs = std::get<0>(ret);
Otc::PathFindResult& result = std::get<1>(ret); Otc::PathFindResult& result = std::get<1>(ret);
result = Otc::PATHFIND_OK; result = Otc::PATHFIND_RESULT_NO_WAY;
if(startPos == goalPos) { if(startPos == goalPos) {
result = Otc::PATHFIND_SAME_POSITION; result = Otc::PATHFIND_RESULT_SAME_POSITION;
return ret; return ret;
} }
if(startPos.z != goalPos.z) { if(startPos.z != goalPos.z) {
result = Otc::PATHFIND_IMPOSSIBLE; result = Otc::PATHFIND_RESULT_IMPOSSIBLE;
return ret; return ret;
} }
if(startPos.distance(goalPos) > maxSteps) { if(startPos.distance(goalPos) > maxSteps) {
result = Otc::PATHFIND_TOO_FAR; result = Otc::PATHFIND_RESULT_TOO_FAR;
return ret; return ret;
} }
@ -479,10 +479,18 @@ std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> Map::findPath(const
currentNode->pos = startPos; currentNode->pos = startPos;
nodes[startPos] = currentNode; nodes[startPos] = currentNode;
Node *foundNode = nullptr; Node *foundNode = nullptr;
while(currentNode && currentNode->steps < maxSteps) { while(currentNode) {
// too far
if(currentNode->steps >= maxSteps) {
result = Otc::PATHFIND_RESULT_TOO_FAR;
break;
}
// path found
if(currentNode->pos == goalPos && (!foundNode || currentNode->cost < foundNode->cost)) if(currentNode->pos == goalPos && (!foundNode || currentNode->cost < foundNode->cost))
foundNode = currentNode; foundNode = currentNode;
// cost too high
if(foundNode && currentNode->totalCost >= foundNode->cost) if(foundNode && currentNode->totalCost >= foundNode->cost)
break; break;
@ -493,8 +501,19 @@ std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> Map::findPath(const
Position neighborPos = currentNode->pos.translated(i, j); Position neighborPos = currentNode->pos.translated(i, j);
const TilePtr& tile = getTile(neighborPos); const TilePtr& tile = getTile(neighborPos);
if(!tile || (!tile->isPathable() && neighborPos != goalPos) || (!tile->isWalkable() && neighborPos == goalPos))
continue; if(neighborPos != goalPos) {
if(!(flags & Otc::PATHFIND_ALLOW_NULLTILES) && !tile)
continue;
if(tile) {
if(!(flags & Otc::PATHFIND_ALLOW_CREATURES) && tile->hasCreature())
continue;
if(!(flags & Otc::PATHFIND_ALLOW_NONPATHABLE) && !tile->isPathable())
continue;
if(!(flags & Otc::PATHFIND_ALLOW_NONWALKABLE) && !tile->isWalkable())
continue;
}
}
float walkFactor; float walkFactor;
Otc::Direction walkDir = currentNode->pos.getDirectionFromPosition(neighborPos); Otc::Direction walkDir = currentNode->pos.getDirectionFromPosition(neighborPos);
@ -503,7 +522,8 @@ std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> Map::findPath(const
else else
walkFactor = 1.0f; walkFactor = 1.0f;
float cost = currentNode->cost + (tile->getGroundSpeed() * walkFactor) / 100.0f; int groundSpeed = tile ? tile->getGroundSpeed() : 100;
float cost = currentNode->cost + (groundSpeed * walkFactor) / 100.0f;
Node *neighborNode; Node *neighborNode;
if(nodes.find(neighborPos) == nodes.end()) { if(nodes.find(neighborPos) == nodes.end()) {
@ -544,8 +564,8 @@ std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> Map::findPath(const
} }
dirs.pop_back(); dirs.pop_back();
std::reverse(dirs.begin(), dirs.end()); std::reverse(dirs.begin(), dirs.end());
} else result = Otc::PATHFIND_RESULT_OK;
result = Otc::PATHFIND_NO_WAY; }
for(auto it : nodes) for(auto it : nodes)
delete it.second; delete it.second;

View File

@ -253,7 +253,7 @@ public:
std::vector<AnimatedTextPtr> getAnimatedTexts() { return m_animatedTexts; } std::vector<AnimatedTextPtr> getAnimatedTexts() { return m_animatedTexts; }
std::vector<StaticTextPtr> getStaticTexts() { return m_staticTexts; } std::vector<StaticTextPtr> getStaticTexts() { return m_staticTexts; }
std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> findPath(const Position& start, const Position& goal, int maxSteps); std::tuple<std::vector<Otc::Direction>, Otc::PathFindResult> findPath(const Position& start, const Position& goal, int maxSteps, int flags = 0);
private: private:
uint getBlockIndex(const Position& pos) { return ((pos.y / BLOCK_SIZE) * (65536 / BLOCK_SIZE)) + (pos.x / BLOCK_SIZE); } uint getBlockIndex(const Position& pos) { return ((pos.y / BLOCK_SIZE) * (65536 / BLOCK_SIZE)) + (pos.x / BLOCK_SIZE); }

View File

@ -469,11 +469,8 @@ bool Tile::changesFloor()
bool Tile::isPathable() bool Tile::isPathable()
{ {
if(!isWalkable())
return false;
for(const ThingPtr& thing : m_things) { for(const ThingPtr& thing : m_things) {
if(thing->isNotPathable() || thing->isCreature()) if(thing->isNotPathable())
return false; return false;
} }