mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-26 18:35:20 +00:00
Merge remote-tracking branch 'dteviot/FixStuckDraft'
This commit is contained in:
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]));
|
||||
}
|
||||
}
|
||||
else { //Not stuck, so reset things
|
||||
mStuckTimer = 0;
|
||||
mStuckPos = pos;
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward
|
||||
}
|
||||
}
|
||||
else {
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward the rest of the time
|
||||
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]));
|
||||
|
||||
return false;
|
||||
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 // probably walking into another NPC
|
||||
{
|
||||
mObstacleCheck.takeEvasiveAction(movement);
|
||||
}
|
||||
}
|
||||
else { //Not stuck, so reset things
|
||||
movement.mPosition[1] = 1; //Just run forward
|
||||
}
|
||||
}
|
||||
|
||||
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…
x
Reference in New Issue
Block a user