Pathfinding Overhaul - Master cleanup! Cleaned pathfinding entirely, all AI packages that are implemented as well, Increased buffer! This makes the intro guard no longer walk into you or go to far into the room (not tested against vanilla distances but it seems accurate enough until the next itteration of pathfinding fixes).

This commit is contained in:
Torben Carrington 2013-05-31 17:49:52 -07:00
parent a4caec56cf
commit 09beafd044
4 changed files with 515 additions and 494 deletions

View file

@ -13,8 +13,9 @@ namespace
{
float sgn(float a)
{
if(a > 0) return 1.0;
else return -1.0;
if(a > 0)
return 1.0;
return -1.0;
}
}
@ -24,7 +25,9 @@ namespace
TODO: Take account for actors being in different cells.
*/
MWMechanics::AiEscort::AiEscort(const std::string &actorId,int duration, float x, float y, float z)
namespace MWMechanics
{
AiEscort::AiEscort(const std::string &actorId, int duration, float x, float y, float z)
: mActorId(actorId), mX(x), mY(y), mZ(z), mDuration(duration)
{
mMaxDist = 470;
@ -41,7 +44,7 @@ MWMechanics::AiEscort::AiEscort(const std::string &actorId,int duration, float x
}
}
MWMechanics::AiEscort::AiEscort(const std::string &actorId,const std::string &cellId,int duration, float x, float y, float z)
AiEscort::AiEscort(const std::string &actorId, const std::string &cellId,int duration, float x, float y, float z)
: mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mDuration(duration)
{
mMaxDist = 470;
@ -59,12 +62,12 @@ MWMechanics::AiEscort::AiEscort(const std::string &actorId,const std::string &ce
}
MWMechanics::AiEscort *MWMechanics::AiEscort::clone() const
AiEscort *MWMechanics::AiEscort::clone() const
{
return new AiEscort(*this);
}
bool MWMechanics::AiEscort::execute (const MWWorld::Ptr& actor)
bool AiEscort::execute (const MWWorld::Ptr& actor)
{
// If AiEscort has ran for as long or longer then the duration specified
// and the duration is not infinite, the package is complete.
@ -76,19 +79,19 @@ bool MWMechanics::AiEscort::execute (const MWWorld::Ptr& actor)
return true;
}
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
ESM::Position pos = actor.getRefData().getPosition();
bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY;
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
const ESM::Pathgrid *pathgrid =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
{
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
// Check if actor is near the border of an inactive cell. If so, disable AiEscort.
// FIXME: This *should* pause the AiEscort package instead of terminating it.
if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / 2. - 200))
if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE /
2.0 - 200))
{
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
return true;
@ -99,7 +102,8 @@ bool MWMechanics::AiEscort::execute (const MWWorld::Ptr& actor)
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
// Check if actor is near the border of an inactive cell. If so, disable AiEscort.
// FIXME: This *should* pause the AiEscort package instead of terminating it.
if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / 2. - 200))
if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE /
2.0 - 200))
{
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
return true;
@ -129,7 +133,7 @@ bool MWMechanics::AiEscort::execute (const MWWorld::Ptr& actor)
start.mY = pos.pos[1];
start.mZ = pos.pos[2];
mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, 1);
mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, true);
}
if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]))
@ -143,11 +147,12 @@ bool MWMechanics::AiEscort::execute (const MWWorld::Ptr& actor)
const float* const followerPos = follower.getRefData().getPosition().pos;
double differenceBetween[3];
for (short i = 0; i < 3; ++i)
differenceBetween[i] = (leaderPos[i] - followerPos[i]);
for (short counter = 0; counter < 3; counter++)
differenceBetween[counter] = (leaderPos[counter] - followerPos[counter]);
float distanceBetweenResult =
(differenceBetween[0] * differenceBetween[0]) + (differenceBetween[1] * differenceBetween[1]) + (differenceBetween[2] * differenceBetween[2]);
(differenceBetween[0] * differenceBetween[0]) + (differenceBetween[1] * differenceBetween[1]) + (differenceBetween[2] *
differenceBetween[2]);
if(distanceBetweenResult <= mMaxDist * mMaxDist)
{
@ -167,8 +172,9 @@ bool MWMechanics::AiEscort::execute (const MWWorld::Ptr& actor)
return false;
}
int MWMechanics::AiEscort::getTypeId() const
int AiEscort::getTypeId() const
{
return 2;
}
}

View file

@ -2,44 +2,47 @@
#include "movement.hpp"
#include "../mwworld/class.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/player.hpp"
namespace
{
float sgn(float a)
{
if(a > 0) return 1.;
else return -1.;
if(a > 0)
return 1.0;
return -1.0;
}
}
MWMechanics::AiTravel::AiTravel(float x, float y, float z)
namespace MWMechanics
{
AiTravel::AiTravel(float x, float y, float z)
: mX(x),mY(y),mZ(z),mPathFinder()
{
}
MWMechanics::AiTravel *MWMechanics::AiTravel::clone() const
AiTravel *MWMechanics::AiTravel::clone() const
{
return new AiTravel(*this);
}
bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor)
bool AiTravel::execute (const MWWorld::Ptr& actor)
{
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
ESM::Position pos = actor.getRefData().getPosition();
bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY;
const ESM::Pathgrid *pathgrid =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell);
ESM::Position pos = actor.getRefData().getPosition();
bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY;
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX)
{
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
//check if actor is near the border of an inactive cell. If so, disable aitravel.
if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 200))
if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE /
2.0 - 200))
{
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
return true;
@ -49,7 +52,8 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor)
{
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
//check if actor is near the border of an inactive cell. If so, disable aitravel.
if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 200))
if(sideY * (pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE /
2.0 - 200))
{
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
return true;
@ -62,6 +66,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor)
cellY = actor.getCell()->mCell->mData.mY;
float xCell = 0;
float yCell = 0;
if (actor.getCell()->mCell->isExterior())
{
xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE;
@ -78,7 +83,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor)
start.mY = pos.pos[1];
start.mZ = pos.pos[2];
mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, 1);
mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, true);
}
if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2]))
@ -94,7 +99,9 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor)
return false;
}
int MWMechanics::AiTravel::getTypeId() const
int AiTravel::getTypeId() const
{
return 1;
}
}

View file

@ -14,12 +14,15 @@ namespace
{
float sgn(float a)
{
if(a > 0) return 1.0;
else return -1.0;
if(a > 0)
return 1.0;
return -1.0;
}
}
MWMechanics::AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<int>& idle, bool repeat):
namespace MWMechanics
{
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<int>& idle, bool repeat):
mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat)
{
for(unsigned short counter = 0; counter < mIdle.size(); counter++)
@ -49,12 +52,12 @@ MWMechanics::AiWander::AiWander(int distance, int duration, int timeOfDay, const
mWalking = false;
}
MWMechanics::AiPackage * MWMechanics::AiWander::clone() const
AiPackage * MWMechanics::AiWander::clone() const
{
return new AiWander(*this);
}
bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor)
bool AiWander::execute (const MWWorld::Ptr& actor)
{
if(mDuration)
{
@ -114,7 +117,8 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor)
for(unsigned int counter = 0; counter < mPathgrid->mPoints.size(); counter++)
{
Ogre::Vector3 nodePos(mPathgrid->mPoints[counter].mX, mPathgrid->mPoints[counter].mY, mPathgrid->mPoints[counter].mZ);
Ogre::Vector3 nodePos(mPathgrid->mPoints[counter].mX, mPathgrid->mPoints[counter].mY,
mPathgrid->mPoints[counter].mZ);
if(npcPos.squaredDistance(nodePos) <= mDistance * mDistance)
mAllowedNodes.push_back(mPathgrid->mPoints[counter]);
}
@ -125,7 +129,8 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor)
unsigned int index = 0;
for(unsigned int counterThree = 1; counterThree < mAllowedNodes.size(); counterThree++)
{
Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY, mAllowedNodes[counterThree].mZ);
Ogre::Vector3 nodePos(mAllowedNodes[counterThree].mX, mAllowedNodes[counterThree].mY,
mAllowedNodes[counterThree].mZ);
float tempDist = npcPos.squaredDistance(nodePos);
if(tempDist < closestNode)
index = counterThree;
@ -147,7 +152,8 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor)
int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX);
// Check if actor is near the border of an inactive cell. If so, disable AiWander.
// FIXME: This *should* pause the AiWander package instead of terminating it.
if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / 2.0 - 200))
if(sideX * (pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE /
2.0 - 200))
{
stopWalking(actor);
return true;
@ -159,7 +165,8 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor)
int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY);
// Check if actor is near the border of an inactive cell. If so, disable AiWander.
// FIXME: This *should* pause the AiWander package instead of terminating it.
if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / 2.0 - 200))
if(sideY * (pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE /
2.0 - 200))
{
stopWalking(actor);
return true;
@ -229,7 +236,7 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor)
start.mY = pos.pos[1];
start.mZ = pos.pos[2];
mPathFinder.buildPath(start, dest, mPathgrid, mXCell, mYCell, 0);
mPathFinder.buildPath(start, dest, mPathgrid, mXCell, mYCell, false);
if(mPathFinder.isPathConstructed())
{
@ -274,18 +281,18 @@ bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor)
return false;
}
int MWMechanics::AiWander::getTypeId() const
int AiWander::getTypeId() const
{
return 0;
}
void MWMechanics::AiWander::stopWalking(const MWWorld::Ptr& actor)
void AiWander::stopWalking(const MWWorld::Ptr& actor)
{
mPathFinder.clearPath();
MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0;
}
void MWMechanics::AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect)
void AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect)
{
if(idleSelect == 2)
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle2", 0, 1);
@ -305,7 +312,7 @@ void MWMechanics::AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short i
MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(actor, "idle9", 0, 1);
}
bool MWMechanics::AiWander::checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect)
bool AiWander::checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect)
{
if(idleSelect == 2)
return MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(actor, "idle2");
@ -326,4 +333,5 @@ bool MWMechanics::AiWander::checkIdle(const MWWorld::Ptr& actor, unsigned short
else
return false;
}
}

View file

@ -205,7 +205,7 @@ namespace MWMechanics
return true;
ESM::Pathgrid::Point nextPoint = *mPath.begin();
if(distanceZCorrected(nextPoint, x, y, z) < 20)
if(distanceZCorrected(nextPoint, x, y, z) < 40)
{
mPath.pop_front();
if(mPath.empty())