Be smarter about handling non-moving animations

Don't rely on being told by the play method, so the animation can
automatically change without impacting the character controller.
actorid
Chris Robinson 12 years ago
parent 4ea347ac52
commit 2c556e4036

@ -149,7 +149,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
, mCharState(state)
, mWeaponType(WeapType_None)
, mSkipAnim(false)
, mMovingAnim(false)
, mSecondsOfRunning(0)
, mSecondsOfSwimming(0)
, mLooping(false)
@ -171,9 +170,9 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
std::string group;
getCurrentGroup(group);
mMovingAnim = mAnimation->play(group, MWRender::Animation::Priority_Default,
MWRender::Animation::Group_All, false,
"start", "stop", 1.0f, loop ? (~(size_t)0) : 0);
mAnimation->play(group, MWRender::Animation::Priority_Default,
MWRender::Animation::Group_All, false,
"start", "stop", 1.0f, loop ? (~(size_t)0) : 0);
}
CharacterController::~CharacterController()
@ -317,10 +316,7 @@ void CharacterController::update(float duration, Movement &movement)
setState(inwater ? (isrunning ? CharState_SwimRunLeft : CharState_SwimWalkLeft)
: (sneak ? CharState_SneakLeft : (isrunning ? CharState_RunLeft : CharState_WalkLeft)), true);
// If this animation isn't moving us sideways, do it manually
if(!mMovingAnim)
movement.mPosition[0] += vec.x * (speed*duration);
// Apply any forward/backward movement manually
movement.mPosition[0] += vec.x * (speed*duration);
movement.mPosition[1] += vec.y * (speed*duration);
}
else if(vec.y != 0.0f && speed > 0.0f)
@ -332,11 +328,8 @@ void CharacterController::update(float duration, Movement &movement)
setState(inwater ? (isrunning ? CharState_SwimRunBack : CharState_SwimWalkBack)
: (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack)), true);
// Apply any sideways movement manually
movement.mPosition[0] += vec.x * (speed*duration);
// If this animation isn't moving us forward/backward, do it manually
if(!mMovingAnim)
movement.mPosition[1] += vec.y * (speed*duration);
movement.mPosition[1] += vec.y * (speed*duration);
}
else if(rot.z != 0.0f && !inwater && !sneak)
{
@ -351,11 +344,9 @@ void CharacterController::update(float duration, Movement &movement)
setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true);
else
{
mMovingAnim = mAnimation->play(mAnimQueue.front().first,
MWRender::Animation::Priority_Default,
MWRender::Animation::Group_All, false,
"start", "stop", 0.0f,
mAnimQueue.front().second);
mAnimation->play(mAnimQueue.front().first, MWRender::Animation::Priority_Default,
MWRender::Animation::Group_All, false,
"start", "stop", 0.0f, mAnimQueue.front().second);
mAnimQueue.pop_front();
}
}
@ -368,10 +359,22 @@ void CharacterController::update(float duration, Movement &movement)
if(mAnimation && !mSkipAnim)
{
mAnimation->setSpeed(speed);
Ogre::Vector3 moved = mAnimation->runAnimation(duration);
movement.mPosition[0] += moved.x;
movement.mPosition[1] += moved.y;
movement.mPosition[2] += moved.z;
// Ensure we're moving in generally the right direction
if((movement.mPosition[0] < 0.0f && movement.mPosition[0] < moved.x*2.0f) ||
(movement.mPosition[0] > 0.0f && movement.mPosition[0] > moved.x*2.0f))
moved.x = movement.mPosition[0];
if((movement.mPosition[1] < 0.0f && movement.mPosition[1] < moved.y*2.0f) ||
(movement.mPosition[1] > 0.0f && movement.mPosition[1] > moved.y*2.0f))
moved.y = movement.mPosition[1];
if((movement.mPosition[2] < 0.0f && movement.mPosition[2] < moved.z*2.0f) ||
(movement.mPosition[2] > 0.0f && movement.mPosition[2] > moved.z*2.0f))
moved.z = movement.mPosition[2];
movement.mPosition[0] = moved.x;
movement.mPosition[1] = moved.y;
movement.mPosition[2] = moved.z;
}
mSkipAnim = false;
}
@ -389,9 +392,9 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int
mAnimQueue.clear();
mCharState = CharState_SpecialIdle;
mLooping = false;
mMovingAnim = mAnimation->play(groupname, MWRender::Animation::Priority_Default,
MWRender::Animation::Group_All, false,
((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1);
mAnimation->play(groupname, MWRender::Animation::Priority_Default,
MWRender::Animation::Group_All, false,
((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1);
}
else if(mode == 0)
{
@ -425,9 +428,9 @@ void CharacterController::forceStateUpdate()
std::string group;
getCurrentGroup(group);
mMovingAnim = mAnimation->play(group, MWRender::Animation::Priority_Default,
MWRender::Animation::Group_All, false,
"start", "stop", 0.0f, mLooping ? (~(size_t)0) : 0);
mAnimation->play(group, MWRender::Animation::Priority_Default,
MWRender::Animation::Group_All, false,
"start", "stop", 0.0f, mLooping ? (~(size_t)0) : 0);
mAnimation->showWeapons(mWeaponType != WeapType_None && mWeaponType != WeapType_HandToHand &&
mWeaponType != WeapType_Spell);

@ -98,8 +98,6 @@ class CharacterController
float mSecondsOfSwimming;
float mSecondsOfRunning;
bool mMovingAnim;
// Gets an animation group name from the current character state.
void getCurrentGroup(std::string &group) const;

@ -279,7 +279,7 @@ void Animation::setAccumulation(const Ogre::Vector3 &accum)
void Animation::setSpeed(float speed)
{
mAnimSpeedMult = 1.0f;
if(mAnimVelocity > 1.0f && speed > 0.0f)
if(speed > 0.0f && mAnimVelocity > 1.0f)
mAnimSpeedMult = speed / mAnimVelocity;
}
@ -316,7 +316,7 @@ float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::Node
Ogre::Vector3 startpos = nonaccumctrl->getTranslation(starttime) * accum;
Ogre::Vector3 endpos = nonaccumctrl->getTranslation(stoptime) * accum;
return startpos.distance(endpos) / (stoptime-starttime);
return startpos.distance(endpos) / (stoptime - starttime);
}
return 0.0f;
@ -479,13 +479,16 @@ bool Animation::handleTextKey(AnimState &state, const std::string &groupname, co
}
bool Animation::play(const std::string &groupname, Priority priority, int groups, bool autodisable, const std::string &start, const std::string &stop, float startpoint, size_t loops)
void Animation::play(const std::string &groupname, Priority priority, int groups, bool autodisable, const std::string &start, const std::string &stop, float startpoint, size_t loops)
{
if(!mSkelBase)
return false;
return;
if(groupname.empty())
return resetActiveGroups();
{
resetActiveGroups();
return;
}
AnimStateMap::iterator stateiter = mStates.begin();
while(stateiter != mStates.end())
@ -500,7 +503,8 @@ bool Animation::play(const std::string &groupname, Priority priority, int groups
if(stateiter != mStates.end())
{
stateiter->second.mPriority = priority;
return resetActiveGroups();
resetActiveGroups();
return;
}
/* Look in reverse; last-inserted source has priority. */
@ -524,10 +528,10 @@ bool Animation::play(const std::string &groupname, Priority priority, int groups
if(iter == mAnimSources.rend())
std::cerr<< "Failed to find animation "<<groupname <<std::endl;
return resetActiveGroups();
resetActiveGroups();
}
bool Animation::resetActiveGroups()
void Animation::resetActiveGroups()
{
for(size_t grp = 0;grp < sNumGroups;grp++)
{
@ -551,13 +555,11 @@ bool Animation::resetActiveGroups()
mAnimVelocity = 0.0f;
if(!mNonAccumRoot || mAccumulate == Ogre::Vector3(0.0f))
return false;
return;
AnimStateMap::const_iterator state = mStates.find(mAnimationValuePtr[0]->getAnimName());
if(state == mStates.end())
return false;
bool ismoving = false;
return;
const Ogre::SharedPtr<AnimSource> &animsrc = state->second.mSource;
const NifOgre::TextKeyMap &keys = animsrc->mTextKeys;
@ -569,8 +571,6 @@ bool Animation::resetActiveGroups()
if(dstval->getNode() == mNonAccumRoot)
{
mAnimVelocity = calcAnimVelocity(keys, dstval, mAccumulate, state->first);
ismoving = (mAnimVelocity > 1.0f);
mNonAccumCtrl = dstval;
break;
}
@ -599,8 +599,6 @@ bool Animation::resetActiveGroups()
}
}
}
return ismoving;
}
@ -623,12 +621,12 @@ bool Animation::getInfo(const std::string &groupname, float *complete, std::stri
}
bool Animation::disable(const std::string &groupname)
void Animation::disable(const std::string &groupname)
{
AnimStateMap::iterator iter = mStates.find(groupname);
if(iter != mStates.end())
mStates.erase(iter);
return resetActiveGroups();
resetActiveGroups();
}

@ -92,17 +92,16 @@ protected:
NifOgre::NodeTargetValue<Ogre::Real> *mNonAccumCtrl;
Ogre::Vector3 mAccumulate;
float mAnimVelocity;
float mAnimSpeedMult;
AnimStateMap mStates;
Ogre::SharedPtr<AnimationValue> mAnimationValuePtr[sNumGroups];
float mAnimVelocity;
float mAnimSpeedMult;
/* Sets the appropriate animations on the bone groups based on priority.
* Returns true if the NonAccum root will provide movement.
*/
bool resetActiveGroups();
void resetActiveGroups();
static size_t detectAnimGroup(const Ogre::Node *node);
@ -173,10 +172,8 @@ public:
* \param loops How many times to loop the animation. This will use the
* "loop start" and "loop stop" markers if they exist,
* otherwise it will use "start" and "stop".
* \return Boolean specifying whether the animation will return movement
* for the character at all.
*/
bool play(const std::string &groupname, Priority priority, int groups, bool autodisable,
void play(const std::string &groupname, Priority priority, int groups, bool autodisable,
const std::string &start, const std::string &stop,
float startpoint, size_t loops);
@ -191,10 +188,8 @@ public:
/** Disables the specified animation group;
* \param groupname Animation group to disable.
* \return Boolean specifying whether the animation will continue to return
* movement for the character at all.
*/
bool disable(const std::string &groupname);
void disable(const std::string &groupname);
virtual Ogre::Vector3 runAnimation(float duration);

Loading…
Cancel
Save