@ -77,89 +77,94 @@ namespace MWMechanics
}
ObstacleCheck : : ObstacleCheck ( )
: mWalkState ( State_Norm )
, mStuckDuration ( 0 )
, mEvadeDuration ( 0 )
, mDistSameSpot ( - 1 ) // avoid calculating it each time
: mWalkState ( WalkState : : Initial )
, mStateDuration ( 0 )
, mEvadeDirectionIndex ( 0 )
{
}
void ObstacleCheck : : clear ( )
{
mWalkState = State_Norm ;
mStuckDuration = 0 ;
mEvadeDuration = 0 ;
mWalkState = WalkState : : Initial ;
}
bool ObstacleCheck : : isEvading ( ) const
{
return mWalkState = = State_ Evade;
return mWalkState = = WalkState: : Evade;
}
/*
* input - actor , duration ( time since last check )
* output - true if evasive action needs to be taken
*
* Walking state transitions ( player greeting check not shown ) :
* Walking state transitions ( player greeting check not shown ) :
*
* MoveNow < - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
* | d |
* | |
* + - > State_Norm < - - - > State_CheckStuck - - > State_Evade
* ^ ^ | f ^ | t ^ | |
* | | | | | | | |
* | + - - - + + - - - + + - - - + | u
* | any < t < u |
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
* Initial - - - - > Norm < - - - - - - - - > CheckStuck - - - - - - - > Evade - - - +
* ^ ^ | f ^ | t ^ | |
* | | | | | | | |
* | + - + + - - - + + - - - + | u
* | any < t < u |
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*
* f = one reaction time
* d = proximity to a closed door
* t = how long before considered stuck
* u = how long to move sideways
*
*/
void ObstacleCheck : : update ( const MWWorld : : Ptr & actor , float duration )
void ObstacleCheck : : update ( const MWWorld : : Ptr & actor , const osg : : Vec3f & destination , float duration )
{
const osg : : Vec3f pos = actor . getRefData ( ) . getPosition ( ) . asVec3 ( ) ;
const auto position = actor . getRefData ( ) . getPosition ( ) . asVec3 ( ) ;
if ( mDistSameSpot = = - 1 )
mDistSameSpot = DIST_SAME_SPOT * actor . getClass ( ) . getSpeed ( actor ) ;
if ( mWalkState = = WalkState : : Initial )
{
mWalkState = WalkState : : Norm ;
mStateDuration = 0 ;
mPrev = position ;
return ;
}
const float distSameSpot = mDistSameSpot * duration ;
const bool samePosition = ( pos - mPrev ) . length2 ( ) < distSameSpot * distSameSpot ;
if ( mWalkState ! = WalkState : : Evade )
{
const float distSameSpot = DIST_SAME_SPOT * actor . getClass ( ) . getSpeed ( actor ) * duration ;
const float prevDistance = ( destination - mPrev ) . length ( ) ;
const float currentDistance = ( destination - position ) . length ( ) ;
const float movedDistance = prevDistance - currentDistance ;
mPrev = pos ;
mPrev = pos ition ;
if ( mWalkState ! = State_Evade )
{
if ( ! samePosition )
if ( movedDistance > = distSameSpot )
{
mWalkState = WalkState : : Norm ;
mStateDuration = 0 ;
return ;
}
if ( mWalkState = = WalkState : : Norm )
{
mWalkState = State_Norm ;
mStuckDuration = 0 ;
mEvadeDuration = 0 ;
mWalkState = WalkState : : CheckStuck ;
mStateDuration = duration ;
return ;
}
mWalkState = State_CheckStuck ;
mStuckDuration + = duration ;
// consider stuck only if position unchanges for a period
if ( mStuckDuration < DURATION_SAME_SPOT )
return ; // still checking, note duration added to timer
else
mStateDuration + = duration ;
if ( mStateDuration < DURATION_SAME_SPOT )
{
mStuckDuration = 0 ;
mWalkState = State_Evade ;
chooseEvasionDirection ( ) ;
return ;
}
mWalkState = WalkState : : Evade ;
mStateDuration = 0 ;
chooseEvasionDirection ( ) ;
return ;
}
mEvadeDuration + = duration ;
if ( mEvadeDuration > = DURATION_TO_EVADE )
m Stat eDuration + = duration ;
if ( m Stat eDuration > = DURATION_TO_EVADE )
{
// tried to evade, assume all is ok and start again
mWalkState = State_Norm ;
mEvadeDuration = 0 ;
mWalkState = WalkState : : Norm ;
mStateDuration = 0 ;
mPrev = position ;
}
}