Merge remote-tracking branch 'dteviot/FixStuckDraft'

sceneinput
Marc Zinnschlag 9 years ago
commit a8bee25757

@ -19,7 +19,7 @@
MWMechanics::AiPackage::~AiPackage() {} MWMechanics::AiPackage::~AiPackage() {}
MWMechanics::AiPackage::AiPackage() : mTimer(0.26f), mStuckTimer(0) { //mTimer starts at .26 to force initial pathbuild MWMechanics::AiPackage::AiPackage() : mTimer(0.26f) { //mTimer starts at .26 to force initial pathbuild
} }
@ -28,7 +28,6 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po
{ {
//Update various Timers //Update various Timers
mTimer += duration; //Update timer mTimer += duration; //Update timer
mStuckTimer += duration; //Update stuck timer
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
@ -91,40 +90,36 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Po
//************************ //************************
if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1])) //Path finished? if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1])) //Path finished?
return true; return true;
else if(mStuckTimer>0.5) //Every half second see if we need to take action to avoid something else
{ {
/// TODO (tluppi#1#): Use ObstacleCheck here. Not working for some reason evadeObstacles(actor, duration, pos);
//if(mObstacleCheck.check(actor, duration)) { }
if(distance(start, mStuckPos.pos[0], mStuckPos.pos[1], mStuckPos.pos[2]) < actor.getClass().getSpeed(actor)*0.05 && distance(dest, start) > 20) { //Actually stuck, and far enough away from destination to care return false;
// first check if we're walking into a door }
MWWorld::Ptr door = getNearbyDoor(actor);
if(door != MWWorld::Ptr()) // NOTE: checks interior cells only void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos)
{ {
if(!door.getCellRef().getTeleport() && door.getCellRef().getTrap().empty() && door.getClass().getDoorState(door) == 0) { //Open the door if untrapped zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]));
MWBase::Environment::get().getWorld()->activateDoor(door, 1);
} MWMechanics::Movement& movement = actor.getClass().getMovementSettings(actor);
} if (mObstacleCheck.check(actor, duration))
else // probably walking into another NPC {
{ // first check if we're walking into a door
actor.getClass().getMovementSettings(actor).mPosition[0] = 1; MWWorld::Ptr door = getNearbyDoor(actor);
actor.getClass().getMovementSettings(actor).mPosition[1] = 1; if (door != MWWorld::Ptr()) // NOTE: checks interior cells only
// change the angle a bit, too {
zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1])); if (!door.getCellRef().getTeleport() && door.getCellRef().getTrap().empty() && door.getClass().getDoorState(door) == 0) { //Open the door if untrapped
MWBase::Environment::get().getWorld()->activateDoor(door, 1);
} }
} }
else { //Not stuck, so reset things else // probably walking into another NPC
mStuckTimer = 0; {
mStuckPos = pos; mObstacleCheck.takeEvasiveAction(movement);
actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward
} }
} }
else { else { //Not stuck, so reset things
actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward the rest of the time movement.mPosition[1] = 1; //Just run forward
} }
zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]));
return false;
} }
bool MWMechanics::AiPackage::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell) bool MWMechanics::AiPackage::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell)

@ -83,10 +83,12 @@ namespace MWMechanics
ObstacleCheck mObstacleCheck; ObstacleCheck mObstacleCheck;
float mTimer; float mTimer;
float mStuckTimer;
ESM::Position mStuckPos;
ESM::Pathgrid::Point mPrevDest; ESM::Pathgrid::Point mPrevDest;
private:
void evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos);
}; };
} }

@ -27,7 +27,7 @@
namespace MWMechanics namespace MWMechanics
{ {
static const int COUNT_BEFORE_RESET = 200; // TODO: maybe no longer needed static const int COUNT_BEFORE_RESET = 10;
static const float DOOR_CHECK_INTERVAL = 1.5f; static const float DOOR_CHECK_INTERVAL = 1.5f;
static const float REACTION_INTERVAL = 0.25f; static const float REACTION_INTERVAL = 0.25f;
static const int GREETING_SHOULD_START = 4; //how many reaction intervals should pass before NPC can greet player static const int GREETING_SHOULD_START = 4; //how many reaction intervals should pass before NPC can greet player
@ -381,11 +381,7 @@ namespace MWMechanics
else else
{ {
// have not yet reached the destination // have not yet reached the destination
//... turn towards the next point in mPath evadeObstacles(actor, storage, duration, pos);
zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]));
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
evadeObstacles(actor, storage, duration);
} }
} }
@ -417,8 +413,12 @@ namespace MWMechanics
storage.mState = Wander_IdleNow; storage.mState = Wander_IdleNow;
} }
void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos)
{ {
// turn towards the next point in mPath
zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]));
MWMechanics::Movement& movement = actor.getClass().getMovementSettings(actor);
if (mObstacleCheck.check(actor, duration)) if (mObstacleCheck.check(actor, duration))
{ {
// first check if we're walking into a door // first check if we're walking into a door
@ -435,16 +435,16 @@ namespace MWMechanics
{ {
// TODO: diagonal should have same animation as walk forward // TODO: diagonal should have same animation as walk forward
// but doesn't seem to do that? // but doesn't seem to do that?
actor.getClass().getMovementSettings(actor).mPosition[0] = 1; mObstacleCheck.takeEvasiveAction(movement);
actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f;
// change the angle a bit, too
const ESM::Position& pos = actor.getRefData().getPosition();
zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]));
} }
mStuckCount++; // TODO: maybe no longer needed mStuckCount++; // TODO: maybe no longer needed
} }
//#if 0 else
// TODO: maybe no longer needed {
movement.mPosition[1] = 1;
}
// if stuck for sufficiently long, act like current location was the destination
if (mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset if (mStuckCount >= COUNT_BEFORE_RESET) // something has gone wrong, reset
{ {
//std::cout << "Reset \""<< cls.getName(actor) << "\"" << std::endl; //std::cout << "Reset \""<< cls.getName(actor) << "\"" << std::endl;
@ -454,7 +454,6 @@ namespace MWMechanics
storage.mState = Wander_ChooseAction; storage.mState = Wander_ChooseAction;
mStuckCount = 0; mStuckCount = 0;
} }
//#endif
} }
void AiWander::playIdleDialogueRandomly(const MWWorld::Ptr& actor) void AiWander::playIdleDialogueRandomly(const MWWorld::Ptr& actor)

@ -83,7 +83,7 @@ namespace MWMechanics
short unsigned getRandomIdle(); short unsigned getRandomIdle();
void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos);
void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage); void playGreetingIfPlayerGetsTooClose(const MWWorld::Ptr& actor, AiWanderStorage& storage);
void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration, ESM::Position& pos);
void playIdleDialogueRandomly(const MWWorld::Ptr& actor); void playIdleDialogueRandomly(const MWWorld::Ptr& actor);
void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage);
void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos);

@ -6,6 +6,8 @@
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
#include "movement.hpp"
namespace MWMechanics namespace MWMechanics
{ {
// NOTE: determined empirically but probably need further tweaking // NOTE: determined empirically but probably need further tweaking
@ -67,6 +69,7 @@ namespace MWMechanics
, mStuckDuration(0) , mStuckDuration(0)
, mEvadeDuration(0) , mEvadeDuration(0)
, mDistSameSpot(-1) // avoid calculating it each time , mDistSameSpot(-1) // avoid calculating it each time
, mEvadeDirection(1.0f)
{ {
} }
@ -155,6 +158,7 @@ namespace MWMechanics
/* FALL THROUGH */ /* FALL THROUGH */
case State_Evade: case State_Evade:
{ {
chooseEvasionDirection(samePosition);
mEvadeDuration += duration; mEvadeDuration += duration;
if(mEvadeDuration < DURATION_TO_EVADE) if(mEvadeDuration < DURATION_TO_EVADE)
return true; return true;
@ -169,4 +173,20 @@ namespace MWMechanics
} }
return false; // no obstacles to evade (yet) return false; // no obstacles to evade (yet)
} }
void ObstacleCheck::takeEvasiveAction(MWMechanics::Movement& actorMovement)
{
actorMovement.mPosition[0] = mEvadeDirection;
actorMovement.mPosition[1] = 0;
}
void ObstacleCheck::chooseEvasionDirection(bool samePosition)
{
// change direction if attempt didn't work
if (samePosition && (0 < mEvadeDuration))
{
mEvadeDirection = mEvadeDirection == 1.0f ? -1.0f : 1.0f;
}
}
} }

@ -8,6 +8,8 @@ namespace MWWorld
namespace MWMechanics namespace MWMechanics
{ {
struct Movement;
/// NOTE: determined empirically based on in-game behaviour /// NOTE: determined empirically based on in-game behaviour
static const float MIN_DIST_TO_DOOR_SQUARED = 128*128; static const float MIN_DIST_TO_DOOR_SQUARED = 128*128;
@ -36,6 +38,9 @@ namespace MWMechanics
// should be taken // should be taken
bool check(const MWWorld::Ptr& actor, float duration); bool check(const MWWorld::Ptr& actor, float duration);
// change direction to try to fix "stuck" actor
void takeEvasiveAction(MWMechanics::Movement& actorMovement);
private: private:
// for checking if we're stuck (ignoring Z axis) // for checking if we're stuck (ignoring Z axis)
@ -53,6 +58,9 @@ namespace MWMechanics
float mStuckDuration; // accumulate time here while in same spot float mStuckDuration; // accumulate time here while in same spot
float mEvadeDuration; float mEvadeDuration;
float mDistSameSpot; // take account of actor's speed float mDistSameSpot; // take account of actor's speed
float mEvadeDirection;
void chooseEvasionDirection(bool samePosition);
}; };
} }

@ -225,19 +225,16 @@ namespace MWMechanics
ESM::Pathgrid::Point temp(mPathgrid->mPoints[startNode]); ESM::Pathgrid::Point temp(mPathgrid->mPoints[startNode]);
converter.ToWorld(temp); converter.ToWorld(temp);
mPath.push_back(temp); mPath.push_back(temp);
mPath.push_back(endPoint);
return;
} }
else
mPath = mCell->aStarSearch(startNode, endNode.first);
if (mPath.empty())
return;
// convert supplied path to world co-ordinates
for (std::list<ESM::Pathgrid::Point>::iterator iter(mPath.begin()); iter != mPath.end(); ++iter)
{ {
converter.ToWorld(*iter); mPath = mCell->aStarSearch(startNode, endNode.first);
// convert supplied path to world co-ordinates
for (std::list<ESM::Pathgrid::Point>::iterator iter(mPath.begin()); iter != mPath.end(); ++iter)
{
converter.ToWorld(*iter);
}
} }
// If endNode found is NOT the closest PathGrid point to the endPoint, // If endNode found is NOT the closest PathGrid point to the endPoint,
@ -254,8 +251,6 @@ namespace MWMechanics
// The AI routines will have to deal with such situations. // The AI routines will have to deal with such situations.
if(endNode.second) if(endNode.second)
mPath.push_back(endPoint); mPath.push_back(endPoint);
return;
} }
float PathFinder::getZAngleToNext(float x, float y) const float PathFinder::getZAngleToNext(float x, float y) const

Loading…
Cancel
Save