127 lines
4.1 KiB
C#
127 lines
4.1 KiB
C#
using System;
|
|
using TMPro;
|
|
using UnityEngine;
|
|
|
|
public class MNumberStepper : MonoBehaviour
|
|
{
|
|
public event Action<int> OnValueChanged;
|
|
|
|
[SerializeField] private TextMeshProUGUI _valueLabel;
|
|
[SerializeField] private CanvasGroup _leftArrow;
|
|
[SerializeField] private CanvasGroup _rightArrow;
|
|
|
|
[Header("Настройки ускорения")]
|
|
[SerializeField] private float _accelerationTime = 0.8f; // Время до максимальной скорости
|
|
[SerializeField] private int _maxStep = 10; // Максимальный шаг
|
|
[SerializeField] private float _minInterval = 0.5f; // Начальный интервал (сек)
|
|
[SerializeField] private float _maxInterval = 0.03f; // Минимальный интервал (сек)
|
|
[SerializeField] private AnimationCurve _accelerationCurve = AnimationCurve.EaseInOut(0, 0, 1, 1);
|
|
|
|
private float _holdTime;
|
|
private int _lastDirection;
|
|
private bool _isHolding;
|
|
private float _lastChangeTime;
|
|
|
|
public int Value { get; private set; }
|
|
private int _min;
|
|
private int _max;
|
|
|
|
public void Initialize(int value, int min, int max)
|
|
{
|
|
Value = value;
|
|
_min = min;
|
|
_max = max;
|
|
ResetState();
|
|
UpdateView();
|
|
}
|
|
|
|
public void SetDirection(int direction)
|
|
{
|
|
if (direction == 0)
|
|
{
|
|
// Отпустили кнопку
|
|
_isHolding = false;
|
|
_lastDirection = 0;
|
|
_holdTime = 0f;
|
|
return;
|
|
}
|
|
|
|
if (!_isHolding)
|
|
{
|
|
// Первое нажатие - мгновенно меняем значение
|
|
_isHolding = true;
|
|
_lastDirection = direction;
|
|
_holdTime = 0f;
|
|
_lastChangeTime = Time.unscaledTime;
|
|
|
|
// Мгновенное изменение при первом клике
|
|
ChangeValue(direction, 1);
|
|
return;
|
|
}
|
|
|
|
// Если направление изменилось - сбрасываем ускорение
|
|
if (_lastDirection != direction)
|
|
{
|
|
_lastDirection = direction;
|
|
_holdTime = 0f;
|
|
_lastChangeTime = Time.unscaledTime;
|
|
return;
|
|
}
|
|
|
|
// Увеличиваем время удержания
|
|
_holdTime += Time.unscaledDeltaTime;
|
|
|
|
// Вычисляем прогресс ускорения (0 -> 1)
|
|
float progress = Mathf.Clamp01(_holdTime / _accelerationTime);
|
|
float curveValue = _accelerationCurve.Evaluate(progress);
|
|
|
|
// 1. РАССЧИТЫВАЕМ ШАГ (увеличивается от 1 до _maxStep)
|
|
int step = 1 + Mathf.RoundToInt(curveValue * (_maxStep - 1));
|
|
step = Mathf.Max(1, step); // Шаг не может быть меньше 1
|
|
|
|
// 2. РАССЧИТЫВАЕМ ИНТЕРВАЛ (уменьшается от _minInterval до _maxInterval)
|
|
float currentInterval = Mathf.Lerp(_minInterval, _maxInterval, curveValue);
|
|
|
|
// Проверяем, пора ли менять значение
|
|
float timeSinceLastChange = Time.unscaledTime - _lastChangeTime;
|
|
|
|
if (timeSinceLastChange >= currentInterval)
|
|
{
|
|
_lastChangeTime = Time.unscaledTime;
|
|
ChangeValue(_lastDirection, step);
|
|
}
|
|
}
|
|
|
|
private void ChangeValue(int direction, int step)
|
|
{
|
|
int newValue = Value + direction * step;
|
|
newValue = Mathf.Clamp(newValue, _min, _max);
|
|
|
|
if (newValue != Value)
|
|
{
|
|
Value = newValue;
|
|
OnValueChanged?.Invoke(Value);
|
|
UpdateView();
|
|
}
|
|
else
|
|
{
|
|
// Если уперлись в границу - сбрасываем ускорение
|
|
ResetState();
|
|
}
|
|
}
|
|
|
|
private void UpdateView()
|
|
{
|
|
_valueLabel.text = Value.ToString();
|
|
_leftArrow.alpha = Value == _min ? 0 : 1;
|
|
_rightArrow.alpha = Value == _max ? 0 : 1;
|
|
}
|
|
|
|
public void ResetState()
|
|
{
|
|
_isHolding = false;
|
|
_lastDirection = 0;
|
|
_holdTime = 0f;
|
|
_lastChangeTime = 0f;
|
|
}
|
|
} |