public void AnimateWalk(Vector3D velocity) { if (PlayerLeftLeg == null || PlayerRightLeg == null) { return; } double speed = WMath.Clamp(velocity.XZ.Length, 0, Player.WalkSpeed); CurrentWalkAnimationTime += Time.Delta * speed * WalkAnimationSpeedCoef; double t = WMath.Remap(Math.Cos(CurrentWalkAnimationTime), -1, 1, 0, 1); double speedCoef = speed <= 0.05D ? 0.0D : speed / Player.WalkSpeed; double currentAngle = WMath.Lerp(-WalkAnimationMaxAngle * speedCoef, WalkAnimationMaxAngle * speedCoef, t);//WMath.Remap(CurrentWalkAnimationTime, 0, 1, -WalkAnimationMaxAngle * speedCoef, WalkAnimationMaxAngle * speedCoef); Quaternion leftRotLeg = new Quaternion(-currentAngle * WalkAnimationLegCoef, 0, 0); Quaternion rightRotLeg = new Quaternion(currentAngle * WalkAnimationLegCoef, 0, 0); Quaternion rightRotArm = new Quaternion(-currentAngle, 0, 0); Quaternion leftRotArm = new Quaternion(currentAngle, 0, 0); PlayerLeftLeg.LocalRotation = leftRotLeg; PlayerRightLeg.LocalRotation = rightRotLeg; PlayerRightArm.LocalRotation *= rightRotArm; PlayerLeftArm.LocalRotation *= leftRotArm; Vector3D flattenVel = new Vector3D(velocity.X, 0, velocity.Z); Vector3D flattenDir = flattenVel.Normalized; double flattenSpeed = flattenVel.Length; if (flattenSpeed >= 0.1D) { double currentTorsoAngle = Quaternion.AngleY(PlayerTorso.Rotation, Quaternion.Identity); double rawNewAngle = (Math.Atan2(flattenDir.X, flattenDir.Z) * WMath.RadToDeg) * -1; double deltaAngle = WMath.DeltaAngle(currentTorsoAngle, rawNewAngle); deltaAngle = WMath.Clamp(deltaAngle, -HeadMaxAngleToBody, HeadMaxAngleToBody); PlayerTorso.LocalRotation *= new Quaternion(0, -deltaAngle * WalkAnimationTorsoOrientCoef * Time.Delta, 0); } }