From 1ceeeb4a224753c6df6fae64c3bf2f6d9929fa74 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 13 Apr 2014 07:35:26 +1000 Subject: [PATCH] Fix movement glitches for actors with low speeds (e.g. a rat). Was caused by false detection of being stuck. --- apps/openmw/mwmechanics/aiwander.cpp | 30 ++++++++++++++++++---------- apps/openmw/mwmechanics/aiwander.hpp | 3 ++- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e89d43ca4c..c50506c75d 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -35,6 +35,7 @@ namespace MWMechanics , mPrevX(0) , mPrevY(0) , mWalkState(State_Norm) + , mDistSameSpot(0) , mStuckCount(0) , mEvadeDuration(0) , mStuckDuration(0) @@ -71,7 +72,6 @@ namespace MWMechanics return new AiWander(*this); } - // TODO: duration is passed in but never used, check if it is needed bool AiWander::execute (const MWWorld::Ptr& actor,float duration) { actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing); @@ -113,7 +113,9 @@ namespace MWMechanics mCellX = actor.getCell()->getCell()->mData.mX; mCellY = actor.getCell()->getCell()->mData.mY; - // TODO: If there is no path does this actor get stuck forever? + // If there is no path this actor doesn't go anywhere. See: + // https://forum.openmw.org/viewtopic.php?t=1556 + // http://www.fliggerty.com/phpBB3/viewtopic.php?f=30&t=5833 if(!mPathgrid) mDistance = 0; else if(mPathgrid->mPoints.empty()) @@ -166,7 +168,7 @@ namespace MWMechanics } } - // TODO: Does this actor stay in one spot forever while in AiWander? + // Actor becomes stationary - see above URL's for previous research if(mAllowedNodes.empty()) mDistance = 0; @@ -277,8 +279,10 @@ namespace MWMechanics { assert(mAllowedNodes.size()); unsigned int randNode = (int)(rand() / ((double)RAND_MAX + 1) * mAllowedNodes.size()); + // NOTE: destNodePos initially constructed with local (i.e. cell) co-ordinates Ogre::Vector3 destNodePos(mAllowedNodes[randNode].mX, mAllowedNodes[randNode].mY, mAllowedNodes[randNode].mZ); + // convert dest to use world co-ordinates ESM::Pathgrid::Point dest; dest.mX = destNodePos[0] + mXCell; dest.mY = destNodePos[1] + mYCell; @@ -338,9 +342,15 @@ namespace MWMechanics * f = one frame * t = how long before considered stuck * u = how long to move sideways + * + * DIST_SAME_SPOT is calibrated for movement speed of around 150. + * A rat has walking speed of around 30, so we need to adjust for + * that. */ - bool samePosition = (abs(pos.pos[0] - mPrevX) < DIST_SAME_SPOT) && - (abs(pos.pos[1] - mPrevY) < DIST_SAME_SPOT); + if(!mDistSameSpot) + mDistSameSpot = DIST_SAME_SPOT * (actor.getClass().getSpeed(actor) / 150); + bool samePosition = (abs(pos.pos[0] - mPrevX) < mDistSameSpot) && + (abs(pos.pos[1] - mPrevY) < mDistSameSpot); switch(mWalkState) { @@ -364,14 +374,14 @@ namespace MWMechanics { mStuckDuration += duration; // consider stuck only if position unchanges for a period - if(mStuckDuration > DURATION_SAME_SPOT) + if(mStuckDuration < DURATION_SAME_SPOT) + break; // still checking, note duration added to timer + else { - mWalkState = State_Evade; mStuckDuration = 0; mStuckCount++; + mWalkState = State_Evade; } - else - break; // still in the same state, but duration added to timer } } /* FALL THROUGH */ @@ -395,7 +405,7 @@ namespace MWMechanics // diagonal should have same animation as walk forward actor.getClass().getMovementSettings(actor).mPosition[0] = 1; - actor.getClass().getMovementSettings(actor).mPosition[1] = 0.01f; + actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; // change the angle a bit, too zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); } diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 75621911e1..dd718a6770 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -58,8 +58,9 @@ namespace MWMechanics WalkState mWalkState; int mStuckCount; - float mStuckDuration; + float mStuckDuration; // accumulate time here while in same spot float mEvadeDuration; + float mDistSameSpot; // take account of actor's speed bool mStoredAvailableNodes; bool mChooseAction;