From f9a711d2fd9b9db998b81f7366d94e3b8ae71693 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Wed, 9 Jan 2019 18:05:51 +0300 Subject: [PATCH] Revert poor animation decisions Start force-updated in-air animation from loop start Make movement animations have higher priority than jump animations Make jumping animations have higher priority than turning animations Don't reset idle during landing animation Don't play default landing sound if the character is not on ground --- apps/openmw/mwmechanics/character.cpp | 35 +++++++++++++++------------ apps/openmw/mwmechanics/character.hpp | 6 ++--- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 553b4e406..cdeeece94 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -345,15 +345,14 @@ void CharacterController::refreshHitRecoilAnims(CharacterState& idle) idle = CharState_None; } -void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, CharacterState& idle, CharacterState& movement, bool force) +void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, CharacterState& idle, bool force) { - if (!force && jump == mJumpState && idle == CharState_None && movement == CharState_None) + if (!force && jump == mJumpState && idle == CharState_None) return; - if (jump != JumpState_None && !(mPtr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson())) // FIXME + if (jump == JumpState_InAir) { idle = CharState_None; - movement = CharState_None; } std::string jumpAnimName; @@ -384,6 +383,7 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState if (!force && jump == mJumpState) return; + bool startAtLoop = (jump == mJumpState); mJumpState = jump; if (!mCurrentJump.empty()) @@ -397,7 +397,7 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState if (mAnimation->hasAnimation(jumpAnimName)) { mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, false, - 1.0f, "start", "stop", 0.f, ~0ul); + 1.0f, startAtLoop ? "loop start" : "start", "stop", 0.f, ~0ul); mCurrentJump = jumpAnimName; } } @@ -675,7 +675,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat if (!mPtr.getClass().hasInventoryStore(mPtr)) weap = sWeaponTypeListEnd; - refreshJumpAnims(weap, jump, idle, movement, force); + refreshJumpAnims(weap, jump, idle, force); refreshMovementAnims(weap, movement, idle, force); // idle handled last as it can depend on the other states @@ -2137,12 +2137,6 @@ void CharacterController::update(float duration, bool animationOnly) inJump = false; - // Do not play turning animation for player if rotation speed is very slow. - // Actual threshold should take framerate in account. - float rotationThreshold = 0; - if (isPlayer) - rotationThreshold = 0.015 * 60 * duration; - if(std::abs(vec.x()/2.0f) > std::abs(vec.y())) { if(vec.x() > 0.0f) @@ -2167,10 +2161,16 @@ void CharacterController::update(float duration, bool animationOnly) } else if(rot.z() != 0.0f) { + // Do not play turning animation for player if rotation speed is very slow. + // Actual threshold should take framerate in account. + float rotationThreshold = 0.f; + if (isPlayer) + rotationThreshold = 0.015 * 60 * duration; + // It seems only bipedal actors use turning animations. // Also do not use turning animations in the first-person view and when sneaking. bool isFirstPlayer = isPlayer && MWBase::Environment::get().getWorld()->isFirstPerson(); - if (!sneak && !isFirstPlayer && mPtr.getClass().isBipedal(mPtr)) + if (!sneak && jumpstate == JumpState_None && !isFirstPlayer && mPtr.getClass().isBipedal(mPtr)) { if(rot.z() > rotationThreshold) movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight; @@ -2183,12 +2183,15 @@ void CharacterController::update(float duration, bool animationOnly) if (playLandingSound) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - std::string sound = "DefaultLand"; + std::string sound; osg::Vec3f pos(mPtr.getRefData().getPosition().asVec3()); if (world->isUnderwater(mPtr.getCell(), pos) || world->isWalkingOnWater(mPtr)) sound = "DefaultLandWater"; + else if (onground) + sound = "DefaultLand"; - sndMgr->playSound3D(mPtr, sound, 1.f, 1.f, MWSound::Type::Foot, MWSound::PlayMode::NoPlayerLocal); + if (!sound.empty()) + sndMgr->playSound3D(mPtr, sound, 1.f, 1.f, MWSound::Type::Foot, MWSound::PlayMode::NoPlayerLocal); } // Player can not use smooth turning as NPCs, so we play turning animation a bit to avoid jittering @@ -2197,7 +2200,7 @@ void CharacterController::update(float duration, bool animationOnly) float threshold = mCurrentMovement.find("swim") == std::string::npos ? 0.4f : 0.8f; float complete; bool animPlaying = mAnimation->getInfo(mCurrentMovement, &complete); - if (movestate == CharState_None && isTurning()) + if (movestate == CharState_None && jumpstate == JumpState_None && isTurning()) { if (animPlaying && complete < threshold) movestate = mMovementState; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 7e6e82c07..f2b1f33a7 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -31,10 +31,8 @@ enum Priority { Priority_WeaponLowerBody, Priority_SneakIdleLowerBody, Priority_SwimIdle, - Priority_Movement, - // Note: in vanilla movement anims have higher priority than jump ones. - // It causes issues with landing animations during movement. Priority_Jump, + Priority_Movement, Priority_Hit, Priority_Weapon, Priority_Block, @@ -214,7 +212,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener void refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force=false); void refreshHitRecoilAnims(CharacterState& idle); - void refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, CharacterState& idle, CharacterState& movement, bool force=false); + void refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, CharacterState& idle, bool force=false); void refreshMovementAnims(const WeaponInfo* weap, CharacterState movement, CharacterState& idle, bool force=false); void refreshIdleAnims(const WeaponInfo* weap, CharacterState idle, bool force=false);