1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-25 06:35:30 +00:00

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.
This commit is contained in:
Chris Robinson 2013-05-12 04:29:42 -07:00
parent 4ea347ac52
commit 2c556e4036
4 changed files with 51 additions and 57 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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();
}

View File

@ -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);