145 lines
4.2 KiB
C#
145 lines
4.2 KiB
C#
using System.Threading;
|
|
using KitsuneCafe.Extension;
|
|
using KitsuneCafe.Sys;
|
|
using R3;
|
|
using UnityEngine;
|
|
using UnityForge.PropertyDrawers;
|
|
|
|
namespace KitsuneCafe.Entities
|
|
{
|
|
public class MotorAnimator : MonoBehaviour
|
|
{
|
|
private const float epsilon = 0.05f;
|
|
|
|
[Header("Dependencies")]
|
|
[SerializeField]
|
|
private Animator animator;
|
|
|
|
[SerializeField]
|
|
private new Rigidbody rigidbody;
|
|
|
|
[SerializeField]
|
|
private Spring spring;
|
|
|
|
[SerializeField]
|
|
private Motor motor;
|
|
|
|
[SerializeField]
|
|
private AirMotor airMotor;
|
|
|
|
[SerializeField]
|
|
private SprintFeature sprint;
|
|
|
|
[Header("Movement")]
|
|
[SerializeField, AnimatorParameterName(AnimatorControllerParameterType.Float, "animator")]
|
|
private string movementSpeedParameter;
|
|
|
|
[SerializeField]
|
|
private float movementSmoothTime = 0.1f;
|
|
|
|
[SerializeField, AnimatorParameterName(AnimatorControllerParameterType.Bool, "animator")]
|
|
private string sprintingParameter;
|
|
|
|
[SerializeField, Range(0f, 1f)]
|
|
private float walkAnimationParamMax = 0.5f;
|
|
|
|
[SerializeField, Range(0f, 1f)]
|
|
private float sprintAnimationParamMax = 1.0f;
|
|
|
|
[SerializeField, AnimatorParameterName(AnimatorControllerParameterType.Bool, "animator")]
|
|
private string fallParam;
|
|
|
|
[SerializeField, AnimatorParameterName(AnimatorControllerParameterType.Bool, "animator")]
|
|
private string hardLandingParam;
|
|
|
|
private CancellationTokenSource disableCancellationTokenSource;
|
|
private CancellationToken disableCancellationToken => disableCancellationTokenSource.Token;
|
|
|
|
private void Reset()
|
|
{
|
|
TryGetComponent(out animator);
|
|
TryGetComponent(out rigidbody);
|
|
TryGetComponent(out spring);
|
|
TryGetComponent(out motor);
|
|
TryGetComponent(out airMotor);
|
|
TryGetComponent(out sprint);
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
disableCancellationTokenSource = new();
|
|
|
|
var d = Disposable.CreateBuilder();
|
|
|
|
CurrentSpeed()
|
|
.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);
|
|
|
|
|
|
Observable.FromEventHandler<LandingForce>(
|
|
e => airMotor.Landed += e,
|
|
e => airMotor.Landed -= e
|
|
)
|
|
.Select(eh => eh.e)
|
|
.Where(force => force == LandingForce.Hard)
|
|
.Subscribe(force => animator.SetTrigger(hardLandingParam))
|
|
.AddTo(ref d);
|
|
|
|
airMotor.ObservePropertyChanged(x => x.IsFalling)
|
|
.Subscribe(falling => animator.SetBool(fallParam, falling))
|
|
.AddTo(ref d);
|
|
|
|
d.RegisterTo(disableCancellationToken);
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
disableCancellationTokenSource.Cancel();
|
|
}
|
|
|
|
private Observable<float> CurrentSpeed() =>
|
|
CurrentVelocity()
|
|
.Select(vel => vel.sqrMagnitude)
|
|
.DistinctUntilChanged()
|
|
.Select(Mathf.Sqrt);
|
|
|
|
private Observable<Vector3> CurrentVelocity() =>
|
|
Observable.EveryUpdate(UnityFrameProvider.FixedUpdate)
|
|
.Select(_ => rigidbody.linearVelocity);
|
|
|
|
private Observable<float> CurrentAnimationSpeed(Observable<float> speedSource) =>
|
|
speedSource
|
|
.CombineLatest(motor.MaxSpeedSource, AnimationScaleFactor(), NormalizeSpeed)
|
|
.DistinctUntilChanged(FEqualityComparer<float>.Create(KMath.IsApproxEqual));
|
|
|
|
private Observable<float> AnimationScaleFactor() =>
|
|
motor.MaxSpeedSource.Select(
|
|
maxSpeed => NormalizationFactor(maxSpeed, motor.DefaultMaxSpeed)
|
|
);
|
|
|
|
private float NormalizationFactor(float maxSpeed, float defaultMaxSpeed) =>
|
|
maxSpeed > defaultMaxSpeed ? sprintAnimationParamMax : walkAnimationParamMax;
|
|
|
|
private float NormalizeSpeed(float currentSpeed, float maxSpeed, float factor) =>
|
|
currentSpeed > maxSpeed && maxSpeed > epsilon ?
|
|
factor :
|
|
Mathf.InverseLerp(0, maxSpeed, currentSpeed) * factor;
|
|
}
|
|
}
|