mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-26 09:35:28 +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)
|
, mCharState(state)
|
||||||
, mWeaponType(WeapType_None)
|
, mWeaponType(WeapType_None)
|
||||||
, mSkipAnim(false)
|
, mSkipAnim(false)
|
||||||
, mMovingAnim(false)
|
|
||||||
, mSecondsOfRunning(0)
|
, mSecondsOfRunning(0)
|
||||||
, mSecondsOfSwimming(0)
|
, mSecondsOfSwimming(0)
|
||||||
, mLooping(false)
|
, mLooping(false)
|
||||||
@ -171,9 +170,9 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
|||||||
|
|
||||||
std::string group;
|
std::string group;
|
||||||
getCurrentGroup(group);
|
getCurrentGroup(group);
|
||||||
mMovingAnim = mAnimation->play(group, MWRender::Animation::Priority_Default,
|
mAnimation->play(group, MWRender::Animation::Priority_Default,
|
||||||
MWRender::Animation::Group_All, false,
|
MWRender::Animation::Group_All, false,
|
||||||
"start", "stop", 1.0f, loop ? (~(size_t)0) : 0);
|
"start", "stop", 1.0f, loop ? (~(size_t)0) : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
CharacterController::~CharacterController()
|
CharacterController::~CharacterController()
|
||||||
@ -317,10 +316,7 @@ void CharacterController::update(float duration, Movement &movement)
|
|||||||
setState(inwater ? (isrunning ? CharState_SwimRunLeft : CharState_SwimWalkLeft)
|
setState(inwater ? (isrunning ? CharState_SwimRunLeft : CharState_SwimWalkLeft)
|
||||||
: (sneak ? CharState_SneakLeft : (isrunning ? CharState_RunLeft : CharState_WalkLeft)), true);
|
: (sneak ? CharState_SneakLeft : (isrunning ? CharState_RunLeft : CharState_WalkLeft)), true);
|
||||||
|
|
||||||
// If this animation isn't moving us sideways, do it manually
|
movement.mPosition[0] += vec.x * (speed*duration);
|
||||||
if(!mMovingAnim)
|
|
||||||
movement.mPosition[0] += vec.x * (speed*duration);
|
|
||||||
// Apply any forward/backward movement manually
|
|
||||||
movement.mPosition[1] += vec.y * (speed*duration);
|
movement.mPosition[1] += vec.y * (speed*duration);
|
||||||
}
|
}
|
||||||
else if(vec.y != 0.0f && speed > 0.0f)
|
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)
|
setState(inwater ? (isrunning ? CharState_SwimRunBack : CharState_SwimWalkBack)
|
||||||
: (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack)), true);
|
: (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack)), true);
|
||||||
|
|
||||||
// Apply any sideways movement manually
|
|
||||||
movement.mPosition[0] += vec.x * (speed*duration);
|
movement.mPosition[0] += vec.x * (speed*duration);
|
||||||
// If this animation isn't moving us forward/backward, do it manually
|
movement.mPosition[1] += vec.y * (speed*duration);
|
||||||
if(!mMovingAnim)
|
|
||||||
movement.mPosition[1] += vec.y * (speed*duration);
|
|
||||||
}
|
}
|
||||||
else if(rot.z != 0.0f && !inwater && !sneak)
|
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);
|
setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mMovingAnim = mAnimation->play(mAnimQueue.front().first,
|
mAnimation->play(mAnimQueue.front().first, MWRender::Animation::Priority_Default,
|
||||||
MWRender::Animation::Priority_Default,
|
MWRender::Animation::Group_All, false,
|
||||||
MWRender::Animation::Group_All, false,
|
"start", "stop", 0.0f, mAnimQueue.front().second);
|
||||||
"start", "stop", 0.0f,
|
|
||||||
mAnimQueue.front().second);
|
|
||||||
mAnimQueue.pop_front();
|
mAnimQueue.pop_front();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -368,10 +359,22 @@ void CharacterController::update(float duration, Movement &movement)
|
|||||||
if(mAnimation && !mSkipAnim)
|
if(mAnimation && !mSkipAnim)
|
||||||
{
|
{
|
||||||
mAnimation->setSpeed(speed);
|
mAnimation->setSpeed(speed);
|
||||||
|
|
||||||
Ogre::Vector3 moved = mAnimation->runAnimation(duration);
|
Ogre::Vector3 moved = mAnimation->runAnimation(duration);
|
||||||
movement.mPosition[0] += moved.x;
|
// Ensure we're moving in generally the right direction
|
||||||
movement.mPosition[1] += moved.y;
|
if((movement.mPosition[0] < 0.0f && movement.mPosition[0] < moved.x*2.0f) ||
|
||||||
movement.mPosition[2] += moved.z;
|
(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;
|
mSkipAnim = false;
|
||||||
}
|
}
|
||||||
@ -389,9 +392,9 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int
|
|||||||
mAnimQueue.clear();
|
mAnimQueue.clear();
|
||||||
mCharState = CharState_SpecialIdle;
|
mCharState = CharState_SpecialIdle;
|
||||||
mLooping = false;
|
mLooping = false;
|
||||||
mMovingAnim = mAnimation->play(groupname, MWRender::Animation::Priority_Default,
|
mAnimation->play(groupname, MWRender::Animation::Priority_Default,
|
||||||
MWRender::Animation::Group_All, false,
|
MWRender::Animation::Group_All, false,
|
||||||
((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1);
|
((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1);
|
||||||
}
|
}
|
||||||
else if(mode == 0)
|
else if(mode == 0)
|
||||||
{
|
{
|
||||||
@ -425,9 +428,9 @@ void CharacterController::forceStateUpdate()
|
|||||||
|
|
||||||
std::string group;
|
std::string group;
|
||||||
getCurrentGroup(group);
|
getCurrentGroup(group);
|
||||||
mMovingAnim = mAnimation->play(group, MWRender::Animation::Priority_Default,
|
mAnimation->play(group, MWRender::Animation::Priority_Default,
|
||||||
MWRender::Animation::Group_All, false,
|
MWRender::Animation::Group_All, false,
|
||||||
"start", "stop", 0.0f, mLooping ? (~(size_t)0) : 0);
|
"start", "stop", 0.0f, mLooping ? (~(size_t)0) : 0);
|
||||||
|
|
||||||
mAnimation->showWeapons(mWeaponType != WeapType_None && mWeaponType != WeapType_HandToHand &&
|
mAnimation->showWeapons(mWeaponType != WeapType_None && mWeaponType != WeapType_HandToHand &&
|
||||||
mWeaponType != WeapType_Spell);
|
mWeaponType != WeapType_Spell);
|
||||||
|
@ -98,8 +98,6 @@ class CharacterController
|
|||||||
float mSecondsOfSwimming;
|
float mSecondsOfSwimming;
|
||||||
float mSecondsOfRunning;
|
float mSecondsOfRunning;
|
||||||
|
|
||||||
bool mMovingAnim;
|
|
||||||
|
|
||||||
// Gets an animation group name from the current character state.
|
// Gets an animation group name from the current character state.
|
||||||
void getCurrentGroup(std::string &group) const;
|
void getCurrentGroup(std::string &group) const;
|
||||||
|
|
||||||
|
@ -279,7 +279,7 @@ void Animation::setAccumulation(const Ogre::Vector3 &accum)
|
|||||||
void Animation::setSpeed(float speed)
|
void Animation::setSpeed(float speed)
|
||||||
{
|
{
|
||||||
mAnimSpeedMult = 1.0f;
|
mAnimSpeedMult = 1.0f;
|
||||||
if(mAnimVelocity > 1.0f && speed > 0.0f)
|
if(speed > 0.0f && mAnimVelocity > 1.0f)
|
||||||
mAnimSpeedMult = speed / mAnimVelocity;
|
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 startpos = nonaccumctrl->getTranslation(starttime) * accum;
|
||||||
Ogre::Vector3 endpos = nonaccumctrl->getTranslation(stoptime) * accum;
|
Ogre::Vector3 endpos = nonaccumctrl->getTranslation(stoptime) * accum;
|
||||||
|
|
||||||
return startpos.distance(endpos) / (stoptime-starttime);
|
return startpos.distance(endpos) / (stoptime - starttime);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0.0f;
|
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)
|
if(!mSkelBase)
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
if(groupname.empty())
|
if(groupname.empty())
|
||||||
return resetActiveGroups();
|
{
|
||||||
|
resetActiveGroups();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
AnimStateMap::iterator stateiter = mStates.begin();
|
AnimStateMap::iterator stateiter = mStates.begin();
|
||||||
while(stateiter != mStates.end())
|
while(stateiter != mStates.end())
|
||||||
@ -500,7 +503,8 @@ bool Animation::play(const std::string &groupname, Priority priority, int groups
|
|||||||
if(stateiter != mStates.end())
|
if(stateiter != mStates.end())
|
||||||
{
|
{
|
||||||
stateiter->second.mPriority = priority;
|
stateiter->second.mPriority = priority;
|
||||||
return resetActiveGroups();
|
resetActiveGroups();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look in reverse; last-inserted source has priority. */
|
/* 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())
|
if(iter == mAnimSources.rend())
|
||||||
std::cerr<< "Failed to find animation "<<groupname <<std::endl;
|
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++)
|
for(size_t grp = 0;grp < sNumGroups;grp++)
|
||||||
{
|
{
|
||||||
@ -551,13 +555,11 @@ bool Animation::resetActiveGroups()
|
|||||||
mAnimVelocity = 0.0f;
|
mAnimVelocity = 0.0f;
|
||||||
|
|
||||||
if(!mNonAccumRoot || mAccumulate == Ogre::Vector3(0.0f))
|
if(!mNonAccumRoot || mAccumulate == Ogre::Vector3(0.0f))
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
AnimStateMap::const_iterator state = mStates.find(mAnimationValuePtr[0]->getAnimName());
|
AnimStateMap::const_iterator state = mStates.find(mAnimationValuePtr[0]->getAnimName());
|
||||||
if(state == mStates.end())
|
if(state == mStates.end())
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
bool ismoving = false;
|
|
||||||
|
|
||||||
const Ogre::SharedPtr<AnimSource> &animsrc = state->second.mSource;
|
const Ogre::SharedPtr<AnimSource> &animsrc = state->second.mSource;
|
||||||
const NifOgre::TextKeyMap &keys = animsrc->mTextKeys;
|
const NifOgre::TextKeyMap &keys = animsrc->mTextKeys;
|
||||||
@ -569,8 +571,6 @@ bool Animation::resetActiveGroups()
|
|||||||
if(dstval->getNode() == mNonAccumRoot)
|
if(dstval->getNode() == mNonAccumRoot)
|
||||||
{
|
{
|
||||||
mAnimVelocity = calcAnimVelocity(keys, dstval, mAccumulate, state->first);
|
mAnimVelocity = calcAnimVelocity(keys, dstval, mAccumulate, state->first);
|
||||||
ismoving = (mAnimVelocity > 1.0f);
|
|
||||||
|
|
||||||
mNonAccumCtrl = dstval;
|
mNonAccumCtrl = dstval;
|
||||||
break;
|
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);
|
AnimStateMap::iterator iter = mStates.find(groupname);
|
||||||
if(iter != mStates.end())
|
if(iter != mStates.end())
|
||||||
mStates.erase(iter);
|
mStates.erase(iter);
|
||||||
return resetActiveGroups();
|
resetActiveGroups();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,17 +92,16 @@ protected:
|
|||||||
NifOgre::NodeTargetValue<Ogre::Real> *mNonAccumCtrl;
|
NifOgre::NodeTargetValue<Ogre::Real> *mNonAccumCtrl;
|
||||||
Ogre::Vector3 mAccumulate;
|
Ogre::Vector3 mAccumulate;
|
||||||
|
|
||||||
float mAnimVelocity;
|
|
||||||
float mAnimSpeedMult;
|
|
||||||
|
|
||||||
AnimStateMap mStates;
|
AnimStateMap mStates;
|
||||||
|
|
||||||
Ogre::SharedPtr<AnimationValue> mAnimationValuePtr[sNumGroups];
|
Ogre::SharedPtr<AnimationValue> mAnimationValuePtr[sNumGroups];
|
||||||
|
|
||||||
|
float mAnimVelocity;
|
||||||
|
float mAnimSpeedMult;
|
||||||
|
|
||||||
/* Sets the appropriate animations on the bone groups based on priority.
|
/* 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);
|
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
|
* \param loops How many times to loop the animation. This will use the
|
||||||
* "loop start" and "loop stop" markers if they exist,
|
* "loop start" and "loop stop" markers if they exist,
|
||||||
* otherwise it will use "start" and "stop".
|
* 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,
|
const std::string &start, const std::string &stop,
|
||||||
float startpoint, size_t loops);
|
float startpoint, size_t loops);
|
||||||
|
|
||||||
@ -191,10 +188,8 @@ public:
|
|||||||
|
|
||||||
/** Disables the specified animation group;
|
/** Disables the specified animation group;
|
||||||
* \param groupname Animation group to disable.
|
* \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);
|
virtual Ogre::Vector3 runAnimation(float duration);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user