Merge remote-tracking branch 'dteviot/FixStuckDraft'

sceneinput
Marc Zinnschlag 9 years ago
commit a8bee25757

@ -19,7 +19,7 @@
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
mTimer += duration; //Update timer
mStuckTimer += duration; //Update stuck timer
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?
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
//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
// first check if we're walking into a door
MWWorld::Ptr door = getNearbyDoor(actor);
if(door != MWWorld::Ptr()) // NOTE: checks interior cells only
{
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 // probably walking into another NPC
{
actor.getClass().getMovementSettings(actor).mPosition[0] = 1;
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
// change the angle a bit, too
zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]));
evadeObstacles(actor, duration, pos);
}
return false;
}
void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float duration, ESM::Position& pos)
{
zTurn(actor, mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]));
MWMechanics::Movement& movement = actor.getClass().getMovementSettings(actor);
if (mObstacleCheck.check(actor, duration))
{
// first check if we're walking into a door
MWWorld::Ptr door = getNearbyDoor(actor);
if (door != MWWorld::Ptr()) // NOTE: checks interior cells only
{
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
mStuckTimer = 0;
mStuckPos = pos;
actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward
else // probably walking into another NPC
{
mObstacleCheck.takeEvasiveAction(movement);
}
}
else {
actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward the rest of the time
else { //Not stuck, so reset things
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)

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

@ -27,7 +27,7 @@
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 REACTION_INTERVAL = 0.25f;
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
{
// have not yet reached the destination
//... turn towards the next point in mPath
zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]));
actor.getClass().getMovementSettings(actor).mPosition[1] = 1;
evadeObstacles(actor, storage, duration);
evadeObstacles(actor, storage, duration, pos);
}
}
@ -417,8 +413,12 @@ namespace MWMechanics
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))
{
// first check if we're walking into a door
@ -435,16 +435,16 @@ namespace MWMechanics
{
// TODO: diagonal should have same animation as walk forward
// but doesn't seem to do that?
actor.getClass().getMovementSettings(actor).mPosition[0] = 1;
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]));
mObstacleCheck.takeEvasiveAction(movement);
}
mStuckCount++; // TODO: maybe no longer needed
}
//#if 0
// TODO: maybe no longer needed
else
{
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
{
//std::cout << "Reset \""<< cls.getName(actor) << "\"" << std::endl;
@ -454,7 +454,6 @@ namespace MWMechanics
storage.mState = Wander_ChooseAction;
mStuckCount = 0;
}
//#endif
}
void AiWander::playIdleDialogueRandomly(const MWWorld::Ptr& actor)

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

@ -6,6 +6,8 @@
#include "../mwworld/class.hpp"
#include "../mwworld/cellstore.hpp"
#include "movement.hpp"
namespace MWMechanics
{
// NOTE: determined empirically but probably need further tweaking
@ -67,6 +69,7 @@ namespace MWMechanics
, mStuckDuration(0)
, mEvadeDuration(0)
, mDistSameSpot(-1) // avoid calculating it each time
, mEvadeDirection(1.0f)
{
}
@ -155,6 +158,7 @@ namespace MWMechanics
/* FALL THROUGH */
case State_Evade:
{
chooseEvasionDirection(samePosition);
mEvadeDuration += duration;
if(mEvadeDuration < DURATION_TO_EVADE)
return true;
@ -169,4 +173,20 @@ namespace MWMechanics
}
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
{
struct Movement;
/// NOTE: determined empirically based on in-game behaviour
static const float MIN_DIST_TO_DOOR_SQUARED = 128*128;
@ -36,6 +38,9 @@ namespace MWMechanics
// should be taken
bool check(const MWWorld::Ptr& actor, float duration);
// change direction to try to fix "stuck" actor
void takeEvasiveAction(MWMechanics::Movement& actorMovement);
private:
// 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 mEvadeDuration;
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]);
converter.ToWorld(temp);
mPath.push_back(temp);
mPath.push_back(endPoint);
return;
}
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)
else
{
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,
@ -254,8 +251,6 @@ namespace MWMechanics
// The AI routines will have to deal with such situations.
if(endNode.second)
mPath.push_back(endPoint);
return;
}
float PathFinder::getZAngleToNext(float x, float y) const

Loading…
Cancel
Save