summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpsi29a <psi29a@gmail.com>2024-02-23 08:14:43 +0000
committerpsi29a <psi29a@gmail.com>2024-02-23 08:14:43 +0000
commit717f1c9870e1f1a05385f936dab762c50ba2a6be (patch)
treef58dc2d3f29bf6e1649c04b07459bb2bea31bbbe
parente4a9e83609b482afb85a1b3a36c8c8f75f83e717 (diff)
parent41d41780a836b5e7f7ec4ffd052c86c945d17f8c (diff)
Merge branch 'floatingpoint' into 'master'
CharacterController: rework movement queueing logic (#7835) Closes #7835 See merge request OpenMW/openmw!3875
-rw-r--r--apps/openmw/mwmechanics/character.cpp86
1 files changed, 48 insertions, 38 deletions
diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp
index d1f41ad514..c0f6111a79 100644
--- a/apps/openmw/mwmechanics/character.cpp
+++ b/apps/openmw/mwmechanics/character.cpp
@@ -2242,8 +2242,6 @@ namespace MWMechanics
if (mAnimation->isPlaying(mCurrentJump))
jumpstate = JumpState_Landing;
- vec.x() *= scale;
- vec.y() *= scale;
vec.z() = 0.0f;
if (movementSettings.mIsStrafing)
@@ -2376,7 +2374,8 @@ namespace MWMechanics
const float speedMult = speed / mMovementAnimSpeed;
mAnimation->adjustSpeedMult(mCurrentMovement, std::min(maxSpeedMult, speedMult));
// Make sure the actual speed is the "expected" speed even though the animation is slower
- scale *= std::max(1.f, speedMult / maxSpeedMult);
+ if (isMovementAnimationControlled())
+ scale *= std::max(1.f, speedMult / maxSpeedMult);
}
if (!mSkipAnim)
@@ -2395,20 +2394,17 @@ namespace MWMechanics
}
}
- if (!isMovementAnimationControlled() && !isScriptedAnimPlaying())
- world->queueMovement(mPtr, vec);
+ updateHeadTracking(duration);
}
movement = vec;
movementSettings.mPosition[0] = movementSettings.mPosition[1] = 0;
+
+ // Can't reset jump state (mPosition[2]) here in full; we don't know for sure whether the PhysicsSystem will
+ // actually handle it in this frame due to the fixed minimum timestep used for the physics update. It will
+ // be reset in PhysicsSystem::move once the jump is handled.
if (movement.z() == 0.f)
movementSettings.mPosition[2] = 0;
- // Can't reset jump state (mPosition[2]) here in full; we don't know for sure whether the PhysicSystem will
- // actually handle it in this frame due to the fixed minimum timestep used for the physics update. It will
- // be reset in PhysicSystem::move once the jump is handled.
-
- if (!mSkipAnim)
- updateHeadTracking(duration);
}
else if (cls.getCreatureStats(mPtr).isDead())
{
@@ -2425,35 +2421,42 @@ namespace MWMechanics
osg::Vec3f movementFromAnimation
= mAnimation->runAnimation(mSkipAnim && !isScriptedAnimPlaying() ? 0.f : duration);
- if (mPtr.getClass().isActor() && isMovementAnimationControlled() && !isScriptedAnimPlaying())
+ if (mPtr.getClass().isActor() && !isScriptedAnimPlaying())
{
- if (duration > 0.0f)
- movementFromAnimation /= duration;
- else
- movementFromAnimation = osg::Vec3f(0.f, 0.f, 0.f);
-
- movementFromAnimation.x() *= scale;
- movementFromAnimation.y() *= scale;
+ if (isMovementAnimationControlled())
+ {
+ if (duration != 0.f && movementFromAnimation != osg::Vec3f())
+ {
+ movementFromAnimation /= duration;
+
+ // Ensure we're moving in the right general direction.
+ // In vanilla, all horizontal movement is taken from animations, even when moving diagonally (which
+ // doesn't have a corresponding animation). So to achieve diagonal movement, we have to rotate the
+ // movement taken from the animation to the intended direction.
+ //
+ // Note that while a complete movement animation cycle will have a well defined direction, no
+ // individual frame will, and therefore we have to determine the direction based on the currently
+ // playing cycle instead.
+ if (speed > 0.f)
+ {
+ float animMovementAngle = getAnimationMovementDirection();
+ float targetMovementAngle = std::atan2(-movement.x(), movement.y());
+ float diff = targetMovementAngle - animMovementAngle;
+ movementFromAnimation = osg::Quat(diff, osg::Vec3f(0, 0, 1)) * movementFromAnimation;
+ }
- if (speed > 0.f && movementFromAnimation != osg::Vec3f())
+ movement = movementFromAnimation;
+ }
+ else
+ {
+ movement = osg::Vec3f();
+ }
+ }
+ else if (mSkipAnim)
{
- // Ensure we're moving in the right general direction. In vanilla, all horizontal movement is taken from
- // animations, even when moving diagonally (which doesn't have a corresponding animation). So to acheive
- // diagonal movement, we have to rotate the movement taken from the animation to the intended
- // direction.
- //
- // Note that while a complete movement animation cycle will have a well defined direction, no individual
- // frame will, and therefore we have to determine the direction based on the currently playing cycle
- // instead.
- float animMovementAngle = getAnimationMovementDirection();
- float targetMovementAngle = std::atan2(-movement.x(), movement.y());
- float diff = targetMovementAngle - animMovementAngle;
- movementFromAnimation = osg::Quat(diff, osg::Vec3f(0, 0, 1)) * movementFromAnimation;
+ movement = osg::Vec3f();
}
- if (!(isPlayer && Settings::game().mPlayerMovementIgnoresAnimation))
- movement = movementFromAnimation;
-
if (mFloatToSurface)
{
if (cls.getCreatureStats(mPtr).isDead()
@@ -2468,8 +2471,11 @@ namespace MWMechanics
}
}
+ movement.x() *= scale;
+ movement.y() *= scale;
// Update movement
- world->queueMovement(mPtr, movement);
+ if (movement != osg::Vec3f())
+ world->queueMovement(mPtr, movement);
}
mSkipAnim = false;
@@ -2686,11 +2692,15 @@ namespace MWMechanics
bool CharacterController::isMovementAnimationControlled() const
{
+ if (Settings::game().mPlayerMovementIgnoresAnimation && mPtr == getPlayer())
+ return false;
+
+ if (mInJump)
+ return false;
+
bool movementAnimationControlled = mIdleState != CharState_None;
if (mMovementState != CharState_None)
movementAnimationControlled = mMovementAnimationHasMovement;
- if (mInJump)
- movementAnimationControlled = false;
return movementAnimationControlled;
}