Files
aibis-dream/Assets/Scripts/FixSystem/Memory/MemorySlider.cs
T

136 lines
3.9 KiB
C#

using System;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Rendering;
using UnityEngine.Playables;
using UnityEngine.Timeline;
namespace AibisDream.FixSystem
{
[RequireComponent(typeof(Slider))]
public class MemorySlider : MonoBehaviour
{
[SerializeField] private float defaultValue = 0f;
[SerializeField] private float sliderMaxValue = 6f;
[SerializeField] private float lockThreshold = 0.06f;
[SerializeField] private TimelineAsset openAsset;
[SerializeField] private TimelineAsset closeAsset;
private Slider slider;
private PlayableDirector playableDirector;
private Volume _volume;
private bool isLocked;
public float TargetValue { get; set; }
public bool IsFound { get; private set; }
public event Action OnFound;
public event Action OnLost;
public void Init(Volume volume)
{
slider = GetComponent<Slider>();
playableDirector = GetComponent<PlayableDirector>();
_volume = volume;
IsFound = false;
slider.onValueChanged.RemoveAllListeners();
slider.onValueChanged.AddListener(HandleValueChanged);
slider.maxValue = sliderMaxValue;
slider.value = defaultValue;
UpdateVolumeWeight(slider.value);
isLocked = true;
slider.interactable = false;
}
public void SetInteractable(bool interactable) => slider.interactable = interactable;
public void UnlockSlider(Action onComplete = null)
{
if (!isLocked)
{
onComplete?.Invoke();
return;
}
PlayTimeline(openAsset, () =>
{
slider.interactable = true;
isLocked = false;
onComplete?.Invoke();
});
}
public void LockSlider(Action onComplete = null)
{
if (isLocked)
{
onComplete?.Invoke();
return;
}
slider.value = 0f;
UpdateVolumeWeight(0f);
PlayTimeline(closeAsset, () =>
{
slider.interactable = false;
isLocked = true;
onComplete?.Invoke();
});
}
private void HandleValueChanged(float value)
{
float t = UpdateVolumeWeight(value);
bool wasFound = IsFound;
IsFound = t < lockThreshold;
if (IsFound && !wasFound)
OnFound?.Invoke();
else if (!IsFound && wasFound)
OnLost?.Invoke();
}
private float UpdateVolumeWeight(float value)
{
float distance = Mathf.Abs(value - TargetValue);
float maxDistance = Mathf.Max(
Mathf.Abs(slider.maxValue - TargetValue),
Mathf.Abs(slider.minValue - TargetValue)
);
float t = Mathf.Clamp01(distance / maxDistance);
if (_volume != null)
_volume.weight = Mathf.Lerp(0, 1, t);
return t;
}
private void PlayTimeline(TimelineAsset asset, Action onComplete)
{
if (asset == null || playableDirector == null)
{
onComplete?.Invoke();
return;
}
playableDirector.Stop();
playableDirector.playableAsset = asset;
playableDirector.time = 0;
playableDirector.extrapolationMode = DirectorWrapMode.None;
Action<PlayableDirector> callback = null;
callback = pd =>
{
playableDirector.stopped -= callback;
onComplete?.Invoke();
};
playableDirector.stopped += callback;
playableDirector.Play();
}
}
}