canto/Assets/Scripts/Entity/EntityAnimator.cs
2025-07-16 23:35:29 -04:00

113 lines
No EOL
3.4 KiB
C#

using R3;
using NaughtyAttributes;
using UnityEngine;
using KitsuneCafe.System;
using KitsuneCafe.Extension;
namespace KitsuneCafe.Entity
{
public class EntityAnimator : MonoBehaviour
{
private const float epsilon = 0.05f;
[SerializeField]
private Animator animator;
[SerializeField]
private new Rigidbody rigidbody;
[SerializeField]
private Motor motor;
[SerializeField]
private SprintFeature sprint;
[SerializeField, AnimatorParam("animator")]
private string movementSpeedParameter;
[SerializeField]
private float movementSmoothTime = 0.1f;
[SerializeField, AnimatorParam("animator")]
private string sprintingParameter;
[SerializeField, Range(0f, 1f)]
private float walkAnimationParamMax = 0.5f;
[SerializeField, Range(0f, 1f)]
private float sprintAnimationParamMax = 1.0f;
[SerializeField, AnimatorParam("animator")]
private string readyParam;
private void Reset()
{
animator = GetComponent<Animator>();
rigidbody = GetComponent<Rigidbody>();
motor = GetComponent<Motor>();
sprint = GetComponent<SprintFeature>();
}
private void Awake()
{
var d = Disposable.CreateBuilder();
CurrentVelocity()
.Compose(CurrentAnimationSpeed)
.SmoothDamp(
() => animator.GetFloat(movementSpeedParameter),
movementSmoothTime,
UnityTimeProvider.FixedUpdate
)
.Subscribe(speed =>
{
animator.SetFloat(movementSpeedParameter, speed);
})
.AddTo(ref d);
sprint.IsSprinting
.DistinctUntilChanged()
.Subscribe(isSprinting =>
{
animator.SetBool(sprintingParameter, isSprinting);
})
.AddTo(ref d);
d.RegisterTo(destroyCancellationToken);
}
private Observable<float> CurrentVelocity()
{
return Observable.EveryUpdate(UnityFrameProvider.FixedUpdate)
.Select(_ => rigidbody.linearVelocity.sqrMagnitude)
.DistinctUntilChanged()
.Select(Mathf.Sqrt);
}
private Observable<float> CurrentAnimationSpeed(Observable<float> speedSource)
{
var scaleFactor = motor.MaxSpeedSource.Select(maxSpeed => NormalizationFactor(maxSpeed, motor.DefaultMaxSpeed));
return speedSource
.CombineLatest(motor.MaxSpeedSource, scaleFactor, NormalizeSpeed)
.DistinctUntilChanged(FEqualityComparer<float>.Create(KMath.IsApproxEqual));
}
private float NormalizationFactor(float maxSpeed, float defaultMaxSpeed)
{
return maxSpeed > defaultMaxSpeed ? sprintAnimationParamMax : walkAnimationParamMax;
}
private float NormalizeSpeed(float currentSpeed, float maxSpeed, float factor)
{
if (currentSpeed > maxSpeed && maxSpeed > epsilon)
{
return factor;
}
else
{
return Mathf.InverseLerp(0, maxSpeed, currentSpeed) * factor;
}
}
}
}