forked from mirror/openmw-tes3mp
Merge remote-tracking branch 'dteviot/PathfindingRefactorDraft'
This commit is contained in:
commit
dc72b24f4e
7 changed files with 117 additions and 61 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
43
apps/openmw/mwmechanics/coordinateconverter.cpp
Normal file
43
apps/openmw/mwmechanics/coordinateconverter.cpp
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
37
apps/openmw/mwmechanics/coordinateconverter.hpp
Normal file
37
apps/openmw/mwmechanics/coordinateconverter.hpp
Normal 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
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue