AiWander uses points between PathGrid points (Fixes #1317)

When there is only on PathGrid point within a NPC's wander distance, expand possible wander destinations by using positions between PathGrid points.
This commit is contained in:
dteviot 2015-07-05 18:21:35 +12:00
parent eb2aa965b9
commit 1239667cb4
3 changed files with 50 additions and 2 deletions

View file

@ -216,7 +216,7 @@ namespace MWMechanics
// Are we there yet? // Are we there yet?
bool& chooseAction = storage.mChooseAction; bool& chooseAction = storage.mChooseAction;
if(walking && if(walking &&
storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], 64.f)) storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1]))
{ {
stopWalking(actor, storage); stopWalking(actor, storage);
moveNow = false; moveNow = false;
@ -694,11 +694,19 @@ namespace MWMechanics
// 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
int pointIndex = 0;
for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++) for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++)
{ {
osg::Vec3f nodePos(PathFinder::MakeOsgVec3(pathgrid->mPoints[counter])); osg::Vec3f nodePos(PathFinder::MakeOsgVec3(pathgrid->mPoints[counter]));
if((npcPos - nodePos).length2() <= mDistance * mDistance) if((npcPos - nodePos).length2() <= mDistance * mDistance)
{
mAllowedNodes.push_back(pathgrid->mPoints[counter]); mAllowedNodes.push_back(pathgrid->mPoints[counter]);
pointIndex = counter;
}
}
if (mAllowedNodes.size() == 1)
{
AddNonPathGridAllowedPoints(npcPos, pathgrid, pointIndex);
} }
if(!mAllowedNodes.empty()) if(!mAllowedNodes.empty())
{ {
@ -708,6 +716,40 @@ namespace MWMechanics
} }
} }
// When only one path grid point in wander distance,
// additional points for NPC to wander to are:
// 1. NPC's initial location
// 2. Partway along the path between the point and its connected points.
void AiWander::AddNonPathGridAllowedPoints(osg::Vec3f npcPos, const ESM::Pathgrid * pathGrid, int pointIndex)
{
mAllowedNodes.push_back(PathFinder::MakePathgridPoint(npcPos));
for (std::vector<ESM::Pathgrid::Edge>::const_iterator it = pathGrid->mEdges.begin(); it != pathGrid->mEdges.end(); ++it)
{
if (it->mV0 == pointIndex)
{
AddPointBetweenPathGridPoints(pathGrid->mPoints[it->mV0], pathGrid->mPoints[it->mV1]);
}
}
}
void AiWander::AddPointBetweenPathGridPoints(const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end)
{
osg::Vec3f vectorStart = PathFinder::MakeOsgVec3(start);
osg::Vec3f delta = PathFinder::MakeOsgVec3(end) - vectorStart;
float length = delta.length();
delta.normalize();
// destination must be far enough away that NPC will need to move to get there.
const int threshold = PathFinder::PathTolerance * 2;
int distance = std::max(mDistance / 2, threshold);
// must not travel more than 1/2 way between waypoints,
// otherwise, NPC goes to far endpoint then comes back. Looks weird.
distance = std::min(distance, static_cast<int>(length / 2));
delta *= distance;
mAllowedNodes.push_back(PathFinder::MakePathgridPoint(vectorStart + delta));
}
void AiWander::SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos) void AiWander::SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos)
{ {
float distanceToClosestNode = FLT_MAX; float distanceToClosestNode = FLT_MAX;

View file

@ -123,6 +123,10 @@ namespace MWMechanics
void SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos); void SetCurrentNodeToClosestAllowedNode(osg::Vec3f npcPos);
void AddNonPathGridAllowedPoints(osg::Vec3f npcPos, const ESM::Pathgrid * pathGrid, int pointIndex);
void AddPointBetweenPathGridPoints(const ESM::Pathgrid::Point& start, const ESM::Pathgrid::Point& end);
/// lookup table for converting idleSelect value to groupName /// lookup table for converting idleSelect value to groupName
static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1]; static const std::string sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1];
}; };

View file

@ -19,6 +19,8 @@ namespace MWMechanics
public: public:
PathFinder(); PathFinder();
static const int PathTolerance = 32;
static float sgn(float val) static float sgn(float val)
{ {
if(val > 0) if(val > 0)
@ -35,7 +37,7 @@ namespace MWMechanics
void clearPath(); void clearPath();
bool checkPathCompleted(float x, float y, float tolerance=32.f); bool checkPathCompleted(float x, float y, float tolerance = PathTolerance);
///< \Returns true if we are within \a tolerance units of the last path point. ///< \Returns true if we are within \a tolerance units of the last path point.
/// In degrees /// In degrees