From 2c556e4036198a2e753b6afd268c62a6c056185b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 12 May 2013 04:29:42 -0700 Subject: [PATCH] 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. --- apps/openmw/mwmechanics/character.cpp | 55 ++++++++++++++------------- apps/openmw/mwmechanics/character.hpp | 2 - apps/openmw/mwrender/animation.cpp | 34 ++++++++--------- apps/openmw/mwrender/animation.hpp | 17 +++------ 4 files changed, 51 insertions(+), 57 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 85e27e3ca4..4679cdadfe 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -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); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 1d7ae33edf..e00facd157 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -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; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 30b05d7a03..fa8177a9d6 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -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 "<getAnimName()); if(state == mStates.end()) - return false; - - bool ismoving = false; + return; const Ogre::SharedPtr &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(); } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index f570d24a10..117a30d2aa 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -92,17 +92,16 @@ protected: NifOgre::NodeTargetValue *mNonAccumCtrl; Ogre::Vector3 mAccumulate; - float mAnimVelocity; - float mAnimSpeedMult; - AnimStateMap mStates; Ogre::SharedPtr 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);