Adjust the movement animation speed every frame (Fixes #1921)

This commit is contained in:
scrawl 2015-07-25 18:22:48 +02:00
parent 278076e609
commit e0ee2fc01b
2 changed files with 24 additions and 22 deletions

View file

@ -408,14 +408,13 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
mCurrentMovement = movementAnimName; mCurrentMovement = movementAnimName;
if(!mCurrentMovement.empty()) if(!mCurrentMovement.empty())
{ {
float vel, speedmult = 1.0f;
bool isrunning = mPtr.getClass().getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run) bool isrunning = mPtr.getClass().getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run)
&& !MWBase::Environment::get().getWorld()->isFlying(mPtr); && !MWBase::Environment::get().getWorld()->isFlying(mPtr);
// For non-flying creatures, MW uses the Walk animation to calculate the animation velocity // For non-flying creatures, MW uses the Walk animation to calculate the animation velocity
// even if we are running. This must be replicated, otherwise the observed speed would differ drastically. // even if we are running. This must be replicated, otherwise the observed speed would differ drastically.
std::string anim = mCurrentMovement; std::string anim = mCurrentMovement;
mAdjustMovementAnimSpeed = true;
if (mPtr.getClass().getTypeName() == typeid(ESM::Creature).name() if (mPtr.getClass().getTypeName() == typeid(ESM::Creature).name()
&& !(mPtr.get<ESM::Creature>()->mBase->mFlags & ESM::Creature::Flies)) && !(mPtr.get<ESM::Creature>()->mBase->mFlags & ESM::Creature::Flies))
{ {
@ -423,30 +422,28 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
const StateInfo *stateinfo = std::find_if(sMovementList, sMovementListEnd, FindCharState(walkState)); const StateInfo *stateinfo = std::find_if(sMovementList, sMovementListEnd, FindCharState(walkState));
anim = stateinfo->groupname; anim = stateinfo->groupname;
if (mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(anim)) > 1.0f) mMovementAnimSpeed = mAnimation->getVelocity(anim);
speedmult = mMovementSpeed / vel; if (mMovementAnimSpeed <= 1.0f)
else {
// Another bug: when using a fallback animation (e.g. RunForward as fallback to SwimRunForward), // Another bug: when using a fallback animation (e.g. RunForward as fallback to SwimRunForward),
// then the equivalent Walk animation will not use a fallback, and if that animation doesn't exist // then the equivalent Walk animation will not use a fallback, and if that animation doesn't exist
// we will play without any scaling. // we will play without any scaling.
// Makes the speed attribute of most water creatures totally useless. // Makes the speed attribute of most water creatures totally useless.
// And again, this can not be fixed without patching game data. // And again, this can not be fixed without patching game data.
speedmult = 1.f; mAdjustMovementAnimSpeed = false;
mMovementAnimSpeed = 1.f;
}
} }
else else
{ {
if(mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(anim)) > 1.0f) mMovementAnimSpeed = mAnimation->getVelocity(anim);
{
speedmult = mMovementSpeed / vel; if (mMovementAnimSpeed <= 1.0f)
}
else if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight)
speedmult = 1.f; // adjusted each frame
else if (mMovementSpeed > 0.0f)
{ {
// The first person anims don't have any velocity to calculate a speed multiplier from. // The first person anims don't have any velocity to calculate a speed multiplier from.
// We use the third person velocities instead. // We use the third person velocities instead.
// FIXME: should be pulled from the actual animation, but it is not presently loaded. // FIXME: should be pulled from the actual animation, but it is not presently loaded.
speedmult = mMovementSpeed / (isrunning ? 222.857f : 154.064f); mMovementAnimSpeed = (isrunning ? 222.857f : 154.064f);
mMovementAnimationControlled = false; mMovementAnimationControlled = false;
} }
} }
@ -462,7 +459,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
} }
mAnimation->play(mCurrentMovement, priorityMovement, movemask, false, mAnimation->play(mCurrentMovement, priorityMovement, movemask, false,
speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul); 1.f, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul);
} }
} }
@ -655,7 +652,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
, mAnimation(anim) , mAnimation(anim)
, mIdleState(CharState_None) , mIdleState(CharState_None)
, mMovementState(CharState_None) , mMovementState(CharState_None)
, mMovementSpeed(0.0f)
, mHasMovedInXY(false) , mHasMovedInXY(false)
, mMovementAnimationControlled(true) , mMovementAnimationControlled(true)
, mDeathState(CharState_None) , mDeathState(CharState_None)
@ -1487,6 +1483,7 @@ void CharacterController::update(float duration)
MWBase::World *world = MWBase::Environment::get().getWorld(); MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Class &cls = mPtr.getClass(); const MWWorld::Class &cls = mPtr.getClass();
osg::Vec3f movement(0.f, 0.f, 0.f); osg::Vec3f movement(0.f, 0.f, 0.f);
float speed = 0.f;
updateMagicEffects(); updateMagicEffects();
@ -1550,10 +1547,10 @@ void CharacterController::update(float duration)
vec = osg::Vec3f(0.f, 0.f, 0.f); vec = osg::Vec3f(0.f, 0.f, 0.f);
osg::Vec3f rot = cls.getRotationVector(mPtr); osg::Vec3f rot = cls.getRotationVector(mPtr);
mMovementSpeed = cls.getSpeed(mPtr); speed = cls.getSpeed(mPtr);
vec.x() *= mMovementSpeed; vec.x() *= speed;
vec.y() *= mMovementSpeed; vec.y() *= speed;
CharacterState movestate = CharState_None; CharacterState movestate = CharState_None;
CharacterState idlestate = CharState_SpecialIdle; CharacterState idlestate = CharState_SpecialIdle;
@ -1807,6 +1804,11 @@ void CharacterController::update(float duration)
if (duration > 0) if (duration > 0)
mAnimation->adjustSpeedMult(mCurrentMovement, std::min(1.5f, std::abs(rot.z()) / duration / static_cast<float>(osg::PI))); mAnimation->adjustSpeedMult(mCurrentMovement, std::min(1.5f, std::abs(rot.z()) / duration / static_cast<float>(osg::PI)));
} }
else if (mMovementState != CharState_None && mAdjustMovementAnimSpeed)
{
float speedmult = speed / mMovementAnimSpeed;
mAnimation->adjustSpeedMult(mCurrentMovement, speedmult);
}
if (!mSkipAnim) if (!mSkipAnim)
{ {
@ -1845,7 +1847,7 @@ void CharacterController::update(float duration)
moved = osg::Vec3f(0.f, 0.f, 0.f); moved = osg::Vec3f(0.f, 0.f, 0.f);
// Ensure we're moving in generally the right direction... // Ensure we're moving in generally the right direction...
if(mMovementSpeed > 0.f) if(speed > 0.f)
{ {
float l = moved.length(); float l = moved.length();
@ -1927,7 +1929,6 @@ void CharacterController::clearAnimQueue()
mAnimQueue.clear(); mAnimQueue.clear();
} }
void CharacterController::forceStateUpdate() void CharacterController::forceStateUpdate()
{ {
if(!mAnimation) if(!mAnimation)

View file

@ -150,7 +150,8 @@ class CharacterController : public MWRender::Animation::TextKeyListener
CharacterState mMovementState; CharacterState mMovementState;
std::string mCurrentMovement; std::string mCurrentMovement;
float mMovementSpeed; float mMovementAnimSpeed;
bool mAdjustMovementAnimSpeed;
bool mHasMovedInXY; bool mHasMovedInXY;
bool mMovementAnimationControlled; bool mMovementAnimationControlled;