mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 20:49:56 +00:00
Moved logic for building a Sync'ed path from AiCombat to PathFinding.
Is now used by AiFollow, which should fix "running in circles" bug caused when recalc a path and closest way point is the one NPC has just passed.
This commit is contained in:
parent
6d7e6cd30c
commit
cb8ca2f03a
5 changed files with 56 additions and 53 deletions
|
@ -677,44 +677,32 @@ namespace MWMechanics
|
|||
return false;
|
||||
}
|
||||
|
||||
bool AiCombat::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell)
|
||||
{
|
||||
if (!mPathFinder.getPath().empty())
|
||||
{
|
||||
Ogre::Vector3 currPathTarget(PathFinder::MakeOgreVector3(mPathFinder.getPath().back()));
|
||||
Ogre::Vector3 newPathTarget = PathFinder::MakeOgreVector3(dest);
|
||||
float dist = (newPathTarget - currPathTarget).length();
|
||||
float targetPosThreshold = (cell->isExterior()) ? 300.0f : 100.0f;
|
||||
return dist > targetPosThreshold;
|
||||
}
|
||||
else
|
||||
{
|
||||
// necessarily construct a new path
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void AiCombat::buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target)
|
||||
{
|
||||
Ogre::Vector3 newPathTarget = Ogre::Vector3(target.getRefData().getPosition().pos);
|
||||
|
||||
float dist;
|
||||
|
||||
if(!mPathFinder.getPath().empty())
|
||||
{
|
||||
ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back();
|
||||
Ogre::Vector3 currPathTarget(PathFinder::MakeOgreVector3(lastPt));
|
||||
dist = (newPathTarget - currPathTarget).length();
|
||||
}
|
||||
else dist = 1e+38F; // necessarily construct a new path
|
||||
|
||||
float targetPosThreshold = (actor.getCell()->getCell()->isExterior())? 300.0f : 100.0f;
|
||||
ESM::Pathgrid::Point newPathTarget = PathFinder::MakePathgridPoint(target.getRefData().getPosition());
|
||||
|
||||
//construct new path only if target has moved away more than on [targetPosThreshold]
|
||||
if(dist > targetPosThreshold)
|
||||
if (doesPathNeedRecalc(newPathTarget, actor.getCell()->getCell()))
|
||||
{
|
||||
ESM::Position pos = actor.getRefData().getPosition();
|
||||
|
||||
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos));
|
||||
|
||||
ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(newPathTarget));
|
||||
|
||||
if(!mPathFinder.isPathConstructed())
|
||||
mPathFinder.buildPath(start, dest, actor.getCell(), false);
|
||||
else
|
||||
{
|
||||
PathFinder newPathFinder;
|
||||
newPathFinder.buildPath(start, dest, actor.getCell(), false);
|
||||
|
||||
if(!mPathFinder.getPath().empty())
|
||||
{
|
||||
newPathFinder.syncStart(mPathFinder.getPath());
|
||||
mPathFinder = newPathFinder;
|
||||
}
|
||||
}
|
||||
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actor.getRefData().getPosition()));
|
||||
mPathFinder.buildSyncedPath(start, newPathTarget, actor.getCell(), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,9 @@ namespace MWMechanics
|
|||
|
||||
virtual void writeState(ESM::AiSequence::AiSequence &sequence) const;
|
||||
|
||||
protected:
|
||||
virtual bool doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell);
|
||||
|
||||
private:
|
||||
|
||||
int mTargetActorId;
|
||||
|
|
|
@ -68,7 +68,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po
|
|||
if(mTimer > 0.25)
|
||||
{
|
||||
if (doesPathNeedRecalc(dest, cell)) { //Only rebuild path if it's moved
|
||||
mPathFinder.buildPath(start, dest, actor.getCell(), true); //Rebuild path, in case the target has moved
|
||||
mPathFinder.buildSyncedPath(start, dest, actor.getCell(), true); //Rebuild path, in case the target has moved
|
||||
mPrevDest = dest;
|
||||
}
|
||||
|
||||
|
|
|
@ -301,23 +301,35 @@ namespace MWMechanics
|
|||
return false;
|
||||
}
|
||||
|
||||
// used by AiCombat, see header for the rationale
|
||||
bool PathFinder::syncStart(const std::list<ESM::Pathgrid::Point> &path)
|
||||
// see header for the rationale
|
||||
void PathFinder::buildSyncedPath(const ESM::Pathgrid::Point &startPoint,
|
||||
const ESM::Pathgrid::Point &endPoint,
|
||||
const MWWorld::CellStore* cell,
|
||||
bool allowShortcuts)
|
||||
{
|
||||
if (mPath.size() < 2)
|
||||
return false; //nothing to pop
|
||||
|
||||
std::list<ESM::Pathgrid::Point>::const_iterator oldStart = path.begin();
|
||||
std::list<ESM::Pathgrid::Point>::iterator iter = ++mPath.begin();
|
||||
|
||||
if( (*iter).mX == oldStart->mX
|
||||
&& (*iter).mY == oldStart->mY
|
||||
&& (*iter).mZ == oldStart->mZ)
|
||||
{
|
||||
mPath.pop_front();
|
||||
return true;
|
||||
// if path has one point, then it's the destination.
|
||||
// don't need to worry about bad path for this case
|
||||
buildPath(startPoint, endPoint, cell, allowShortcuts);
|
||||
}
|
||||
else
|
||||
{
|
||||
const ESM::Pathgrid::Point oldStart(*getPath().begin());
|
||||
buildPath(startPoint, endPoint, cell, allowShortcuts);
|
||||
if (mPath.size() >= 2)
|
||||
{
|
||||
// if 2nd waypoint of new path == 1st waypoint of old,
|
||||
// delete 1st waypoint of new path.
|
||||
std::list<ESM::Pathgrid::Point>::iterator iter = ++mPath.begin();
|
||||
if (iter->mX == oldStart.mX
|
||||
&& iter->mY == oldStart.mY
|
||||
&& iter->mZ == oldStart.mZ)
|
||||
{
|
||||
mPath.pop_front();
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -63,13 +63,13 @@ namespace MWMechanics
|
|||
|
||||
/** Synchronize new path with old one to avoid visiting 1 waypoint 2 times
|
||||
@note
|
||||
If the first point is chosen as the nearest one
|
||||
the situation can occur when the 1st point of the new path is undesirable
|
||||
(i.e. the 2nd point of new path == the 1st point of old path).
|
||||
@param path - old path
|
||||
@return true if such point was found and deleted
|
||||
BuildPath() takes closest PathGrid point to NPC as first point of path.
|
||||
This is undesireable if NPC has just passed a Pathgrid point, as this
|
||||
makes the 2nd point of the new path == the 1st point of old path.
|
||||
Which results in NPC "running in a circle" back to the just passed waypoint.
|
||||
*/
|
||||
bool syncStart(const std::list<ESM::Pathgrid::Point> &path);
|
||||
void buildSyncedPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
|
||||
const MWWorld::CellStore* cell, bool allowShortcuts = true);
|
||||
|
||||
void addPointToPath(ESM::Pathgrid::Point &point)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue