1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-05-02 12:41:24 +00:00

CharacterController: rework movement queueing logic (#7835)

This commit is contained in:
Alexei Kotov 2024-02-18 13:16:47 +03:00
parent a297a0e742
commit 41d41780a8

View file

@ -2237,8 +2237,6 @@ namespace MWMechanics
if (mAnimation->isPlaying(mCurrentJump)) if (mAnimation->isPlaying(mCurrentJump))
jumpstate = JumpState_Landing; jumpstate = JumpState_Landing;
vec.x() *= scale;
vec.y() *= scale;
vec.z() = 0.0f; vec.z() = 0.0f;
if (movementSettings.mIsStrafing) if (movementSettings.mIsStrafing)
@ -2371,6 +2369,7 @@ namespace MWMechanics
const float speedMult = speed / mMovementAnimSpeed; const float speedMult = speed / mMovementAnimSpeed;
mAnimation->adjustSpeedMult(mCurrentMovement, std::min(maxSpeedMult, speedMult)); mAnimation->adjustSpeedMult(mCurrentMovement, std::min(maxSpeedMult, speedMult));
// Make sure the actual speed is the "expected" speed even though the animation is slower // Make sure the actual speed is the "expected" speed even though the animation is slower
if (isMovementAnimationControlled())
scale *= std::max(1.f, speedMult / maxSpeedMult); scale *= std::max(1.f, speedMult / maxSpeedMult);
} }
@ -2390,20 +2389,17 @@ namespace MWMechanics
} }
} }
if (!isMovementAnimationControlled() && !isScriptedAnimPlaying()) updateHeadTracking(duration);
world->queueMovement(mPtr, vec);
} }
movement = vec; movement = vec;
movementSettings.mPosition[0] = movementSettings.mPosition[1] = 0; 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) if (movement.z() == 0.f)
movementSettings.mPosition[2] = 0; 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()) else if (cls.getCreatureStats(mPtr).isDead())
{ {
@ -2420,34 +2416,41 @@ namespace MWMechanics
osg::Vec3f movementFromAnimation osg::Vec3f movementFromAnimation
= mAnimation->runAnimation(mSkipAnim && !isScriptedAnimPlaying() ? 0.f : duration); = mAnimation->runAnimation(mSkipAnim && !isScriptedAnimPlaying() ? 0.f : duration);
if (mPtr.getClass().isActor() && isMovementAnimationControlled() && !isScriptedAnimPlaying()) if (mPtr.getClass().isActor() && !isScriptedAnimPlaying())
{
if (isMovementAnimationControlled())
{
if (duration != 0.f && movementFromAnimation != osg::Vec3f())
{ {
if (duration > 0.0f)
movementFromAnimation /= duration; movementFromAnimation /= duration;
else
movementFromAnimation = osg::Vec3f(0.f, 0.f, 0.f);
movementFromAnimation.x() *= scale; // Ensure we're moving in the right general direction.
movementFromAnimation.y() *= scale; // 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
if (speed > 0.f && movementFromAnimation != osg::Vec3f()) // movement taken from the animation to the intended direction.
{
// 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 // Note that while a complete movement animation cycle will have a well defined direction, no
// frame will, and therefore we have to determine the direction based on the currently playing cycle // individual frame will, and therefore we have to determine the direction based on the currently
// instead. // playing cycle instead.
if (speed > 0.f)
{
float animMovementAngle = getAnimationMovementDirection(); float animMovementAngle = getAnimationMovementDirection();
float targetMovementAngle = std::atan2(-movement.x(), movement.y()); float targetMovementAngle = std::atan2(-movement.x(), movement.y());
float diff = targetMovementAngle - animMovementAngle; float diff = targetMovementAngle - animMovementAngle;
movementFromAnimation = osg::Quat(diff, osg::Vec3f(0, 0, 1)) * movementFromAnimation; movementFromAnimation = osg::Quat(diff, osg::Vec3f(0, 0, 1)) * movementFromAnimation;
} }
if (!(isPlayer && Settings::game().mPlayerMovementIgnoresAnimation))
movement = movementFromAnimation; movement = movementFromAnimation;
}
else
{
movement = osg::Vec3f();
}
}
else if (mSkipAnim)
{
movement = osg::Vec3f();
}
if (mFloatToSurface) if (mFloatToSurface)
{ {
@ -2463,7 +2466,10 @@ namespace MWMechanics
} }
} }
movement.x() *= scale;
movement.y() *= scale;
// Update movement // Update movement
if (movement != osg::Vec3f())
world->queueMovement(mPtr, movement); world->queueMovement(mPtr, movement);
} }
@ -2681,11 +2687,15 @@ namespace MWMechanics
bool CharacterController::isMovementAnimationControlled() const bool CharacterController::isMovementAnimationControlled() const
{ {
if (Settings::game().mPlayerMovementIgnoresAnimation && mPtr == getPlayer())
return false;
if (mInJump)
return false;
bool movementAnimationControlled = mIdleState != CharState_None; bool movementAnimationControlled = mIdleState != CharState_None;
if (mMovementState != CharState_None) if (mMovementState != CharState_None)
movementAnimationControlled = mMovementAnimationHasMovement; movementAnimationControlled = mMovementAnimationHasMovement;
if (mInJump)
movementAnimationControlled = false;
return movementAnimationControlled; return movementAnimationControlled;
} }