136 lines
3.9 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|