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:
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…
x
Reference in New Issue
Block a user