Merge remote-tracking branch 'dteviot/PathfindingRefactorDraft'

This commit is contained in:
Marc Zinnschlag 2015-08-17 14:04:56 +02:00
commit dc72b24f4e
7 changed files with 117 additions and 61 deletions

View file

@ -82,7 +82,7 @@ add_openmw_dir (mwmechanics
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor
aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning
character actors objects aistate character actors objects aistate coordinateconverter
) )
add_openmw_dir (mwstate add_openmw_dir (mwstate

View file

@ -20,6 +20,7 @@
#include "creaturestats.hpp" #include "creaturestats.hpp"
#include "steering.hpp" #include "steering.hpp"
#include "movement.hpp" #include "movement.hpp"
#include "coordinateconverter.hpp"
@ -587,11 +588,7 @@ namespace MWMechanics
void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell) void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell)
{ {
if (cell->isExterior()) CoordinateConverter(cell).ToWorld(point);
{
point.mX += cell->mData.mX * ESM::Land::REAL_SIZE;
point.mY += cell->mData.mY * ESM::Land::REAL_SIZE;
}
} }
void AiWander::trimAllowedNodes(std::vector<ESM::Pathgrid::Point>& nodes, void AiWander::trimAllowedNodes(std::vector<ESM::Pathgrid::Point>& nodes,
@ -749,11 +746,7 @@ namespace MWMechanics
{ {
// get NPC's position in local (i.e. cell) co-ordinates // get NPC's position in local (i.e. cell) co-ordinates
osg::Vec3f npcPos(mInitialActorPosition); osg::Vec3f npcPos(mInitialActorPosition);
if(cell->isExterior()) CoordinateConverter(cell).ToLocal(npcPos);
{
npcPos[0] = npcPos[0] - static_cast<float>(cell->mData.mX * ESM::Land::REAL_SIZE);
npcPos[1] = npcPos[1] - static_cast<float>(cell->mData.mY * ESM::Land::REAL_SIZE);
}
// mAllowedNodes for this actor with pathgrid point indexes based on mDistance // mAllowedNodes for this actor with pathgrid point indexes based on mDistance
// NOTE: mPoints and mAllowedNodes are in local co-ordinates // NOTE: mPoints and mAllowedNodes are in local co-ordinates

View file

@ -0,0 +1,43 @@
#include "coordinateconverter.hpp"
#include <components/esm/loadcell.hpp>
#include <components/esm/loadland.hpp>
namespace MWMechanics
{
CoordinateConverter::CoordinateConverter(const ESM::Cell* cell)
: mCellX(0), mCellY(0)
{
if (cell->isExterior())
{
mCellX = cell->mData.mX * ESM::Land::REAL_SIZE;
mCellY = cell->mData.mY * ESM::Land::REAL_SIZE;
}
}
void CoordinateConverter::ToWorld(ESM::Pathgrid::Point& point)
{
point.mX += mCellX;
point.mY += mCellY;
}
void CoordinateConverter::ToWorld(osg::Vec3f& point)
{
point.x() += static_cast<float>(mCellX);
point.y() += static_cast<float>(mCellY);
}
void CoordinateConverter::ToLocal(osg::Vec3f& point)
{
point.x() -= static_cast<float>(mCellX);
point.y() -= static_cast<float>(mCellY);
}
osg::Vec3f CoordinateConverter::ToLocalVec3(const ESM::Pathgrid::Point& point)
{
return osg::Vec3f(
static_cast<float>(point.mX - mCellX),
static_cast<float>(point.mY - mCellY),
static_cast<float>(point.mZ));
}
}

View file

@ -0,0 +1,37 @@
#ifndef GAME_MWMECHANICS_COORDINATECONVERTER_H
#define GAME_MWMECHANICS_COORDINATECONVERTER_H
#include <components/esm/defs.hpp>
#include <components/esm/loadpgrd.hpp>
namespace ESM
{
struct Cell;
}
namespace MWMechanics
{
/// \brief convert coordinates between world and local cell
class CoordinateConverter
{
public:
CoordinateConverter(const ESM::Cell* cell);
/// in-place conversion from local to world
void ToWorld(ESM::Pathgrid::Point& point);
/// in-place conversion from local to world
void ToWorld(osg::Vec3f& point);
/// in-place conversion from world to local
void ToLocal(osg::Vec3f& point);
osg::Vec3f ToLocalVec3(const ESM::Pathgrid::Point& point);
private:
int mCellX;
int mCellY;
};
}
#endif

View file

@ -5,6 +5,7 @@
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
#include "coordinateconverter.hpp"
namespace namespace
{ {
@ -25,8 +26,7 @@ namespace
// //
int getClosestPoint(const ESM::Pathgrid* grid, const osg::Vec3f& pos) int getClosestPoint(const ESM::Pathgrid* grid, const osg::Vec3f& pos)
{ {
if(!grid || grid->mPoints.empty()) assert(grid && !grid->mPoints.empty());
return -1;
float distanceBetween = distanceSquared(grid->mPoints[0], pos); float distanceBetween = distanceSquared(grid->mPoints[0], pos);
int closestIndex = 0; int closestIndex = 0;
@ -107,11 +107,6 @@ namespace MWMechanics
return sqrt(x * x + y * y + z * z); return sqrt(x * x + y * y + z * z);
} }
osg::Vec3f ToLocalCoordinates(const ESM::Pathgrid::Point &point, float xCell, float yCell)
{
return osg::Vec3f(point.mX - xCell, point.mY - yCell, static_cast<float>(point.mZ));
}
PathFinder::PathFinder() PathFinder::PathFinder()
: mPathgrid(NULL), : mPathgrid(NULL),
mCell(NULL) mCell(NULL)
@ -195,23 +190,17 @@ namespace MWMechanics
} }
// NOTE: getClosestPoint expects local co-ordinates // NOTE: getClosestPoint expects local co-ordinates
float xCell = 0; CoordinateConverter converter(mCell->getCell());
float yCell = 0;
if (mCell->isExterior())
{
xCell = static_cast<float>(mCell->getCell()->mData.mX * ESM::Land::REAL_SIZE);
yCell = static_cast<float>(mCell->getCell()->mData.mY * ESM::Land::REAL_SIZE);
}
// NOTE: It is possible that getClosestPoint returns a pathgrind point index // NOTE: It is possible that getClosestPoint returns a pathgrind point index
// that is unreachable in some situations. e.g. actor is standing // that is unreachable in some situations. e.g. actor is standing
// outside an area enclosed by walls, but there is a pathgrid // outside an area enclosed by walls, but there is a pathgrid
// point right behind the wall that is closer than any pathgrid // point right behind the wall that is closer than any pathgrid
// point outside the wall // point outside the wall
osg::Vec3f startPointInLocalCoords(ToLocalCoordinates(startPoint, xCell, yCell)); osg::Vec3f startPointInLocalCoords(converter.ToLocalVec3(startPoint));
int startNode = getClosestPoint(mPathgrid, startPointInLocalCoords); int startNode = getClosestPoint(mPathgrid, startPointInLocalCoords);
osg::Vec3f endPointInLocalCoords(ToLocalCoordinates(endPoint, xCell, yCell)); osg::Vec3f endPointInLocalCoords(converter.ToLocalVec3(endPoint));
std::pair<int, bool> endNode = getClosestReachablePoint(mPathgrid, cell, std::pair<int, bool> endNode = getClosestReachablePoint(mPathgrid, cell,
endPointInLocalCoords, endPointInLocalCoords,
startNode); startNode);
@ -223,27 +212,38 @@ namespace MWMechanics
// nodes are the same // nodes are the same
if(startNode == endNode.first) if(startNode == endNode.first)
{ {
ESM::Pathgrid::Point temp(mPathgrid->mPoints[startNode]);
converter.ToWorld(temp);
mPath.push_back(temp);
mPath.push_back(endPoint); mPath.push_back(endPoint);
return; return;
} }
mPath = mCell->aStarSearch(startNode, endNode.first); mPath = mCell->aStarSearch(startNode, endNode.first);
assert(!mPath.empty());
if(!mPath.empty()) // convert supplied path to world co-ordinates
for (std::list<ESM::Pathgrid::Point>::iterator iter(mPath.begin()); iter != mPath.end(); ++iter)
{ {
// Add the destination (which may be different to the closest converter.ToWorld(*iter);
// pathgrid point). However only add if endNode was the closest
// point to endPoint.
//
// This logic can fail in the opposite situate, e.g. endPoint may
// have been reachable but happened to be very close to an
// unreachable pathgrid point.
//
// The AI routines will have to deal with such situations.
if(endNode.second)
mPath.push_back(endPoint);
} }
// If endNode found is NOT the closest PathGrid point to the endPoint,
// assume endPoint is not reachable from endNode. In which case,
// path ends at endNode.
//
// So only add the destination (which may be different to the closest
// pathgrid point) when endNode was the closest point to endPoint.
//
// This logic can fail in the opposite situate, e.g. endPoint may
// have been reachable but happened to be very close to an
// unreachable pathgrid point.
//
// The AI routines will have to deal with such situations.
if(endNode.second)
mPath.push_back(endPoint);
return; return;
} }

View file

@ -312,29 +312,15 @@ namespace MWMechanics
if(current != goal) if(current != goal)
return path; // for some reason couldn't build a path return path; // for some reason couldn't build a path
// reconstruct path to return, using world co-ordinates // reconstruct path to return, using local co-ordinates
int xCell = 0;
int yCell = 0;
if (mIsExterior)
{
xCell = mPathgrid->mData.mX * ESM::Land::REAL_SIZE;
yCell = mPathgrid->mData.mY * ESM::Land::REAL_SIZE;
}
while(graphParent[current] != -1) while(graphParent[current] != -1)
{ {
ESM::Pathgrid::Point pt = mPathgrid->mPoints[current]; path.push_front(mPathgrid->mPoints[current]);
pt.mX += xCell;
pt.mY += yCell;
path.push_front(pt);
current = graphParent[current]; current = graphParent[current];
} }
// add first node to path explicitly // add first node to path explicitly
ESM::Pathgrid::Point pt = mPathgrid->mPoints[start]; path.push_front(mPathgrid->mPoints[start]);
pt.mX += xCell;
pt.mY += yCell;
path.push_front(pt);
return path; return path;
} }
} }

View file

@ -17,6 +17,7 @@
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwmechanics/pathfinding.hpp" #include "../mwmechanics/pathfinding.hpp"
#include "../mwmechanics/coordinateconverter.hpp"
#include "vismask.hpp" #include "vismask.hpp"
@ -207,11 +208,7 @@ void Pathgrid::enableCellPathgrid(const MWWorld::CellStore *store)
if (!pathgrid) return; if (!pathgrid) return;
osg::Vec3f cellPathGridPos(0, 0, 0); osg::Vec3f cellPathGridPos(0, 0, 0);
if (store->getCell()->isExterior()) MWMechanics::CoordinateConverter(store->getCell()).ToWorld(cellPathGridPos);
{
cellPathGridPos.x() = static_cast<float>(store->getCell()->mData.mX * ESM::Land::REAL_SIZE);
cellPathGridPos.y() = static_cast<float>(store->getCell()->mData.mY * ESM::Land::REAL_SIZE);
}
osg::ref_ptr<osg::PositionAttitudeTransform> cellPathGrid = new osg::PositionAttitudeTransform; osg::ref_ptr<osg::PositionAttitudeTransform> cellPathGrid = new osg::PositionAttitudeTransform;
cellPathGrid->setPosition(cellPathGridPos); cellPathGrid->setPosition(cellPathGridPos);