Добавить таймеры и шкалы прогресса, расширить призовую систему и контроль остатков, восстановить настройки и обновить таблицу призов главного меню.
291 lines
9.7 KiB
C#
291 lines
9.7 KiB
C#
using System;
|
||
using DG.Tweening;
|
||
using PrizeSystem;
|
||
using TMPro;
|
||
using UnityEngine;
|
||
|
||
public sealed class PrizeStockPanel : MonoBehaviour, IControlable
|
||
{
|
||
public event Action OnClosed;
|
||
|
||
[SerializeField] private CanvasGroup _canvasGroup;
|
||
[SerializeField] private TextMeshProUGUI _count;
|
||
[SerializeField] private MToggle _controlToggle;
|
||
[SerializeField] private TextMeshProUGUI[] _options;
|
||
[SerializeField] private TextMeshProUGUI _description;
|
||
[SerializeField] private TextMeshProUGUI _hint;
|
||
[SerializeField] private float _fadeDuration = 0.25f;
|
||
[SerializeField] private Color _normalOptionColor = Color.white;
|
||
[SerializeField] private Color _selectedOptionColor = new Color(1f, 0.85f, 0.1f, 1f);
|
||
[Header("Ускорение числового ввода")]
|
||
[SerializeField] private float _accelerationTime = 0.8f;
|
||
[SerializeField] private int _maximumStepMultiplier = 10;
|
||
[SerializeField] private float _initialRepeatInterval = 0.5f;
|
||
[SerializeField] private float _minimumRepeatInterval = 0.03f;
|
||
[SerializeField] private AnimationCurve _accelerationCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
|
||
|
||
private const int ToggleOptionIndex = 0;
|
||
private const int AddOptionIndex = 1;
|
||
private const int SetOptionIndex = 2;
|
||
private const int BackOptionIndex = 3;
|
||
private const int DefaultAddAmount = 10;
|
||
private const int MaximumCount = 999999;
|
||
|
||
private Tween _fadeTween;
|
||
private int _selectedOptionIndex;
|
||
private int _addAmount;
|
||
private int _setAmount;
|
||
private bool _editingNumber;
|
||
private bool _actionReleased;
|
||
private bool _isClosing;
|
||
private bool _numberInputHeld;
|
||
private int _heldNumberDirection;
|
||
private int _heldNumberBaseStep;
|
||
private float _numberHoldTime;
|
||
private float _lastNumberChangeTime;
|
||
|
||
public bool ControlsEnabled { get; set; }
|
||
|
||
private void OnDisable()
|
||
{
|
||
PrizeStockService.StateChanged -= Refresh;
|
||
_fadeTween?.Kill();
|
||
_fadeTween = null;
|
||
ControlsEnabled = false;
|
||
ResetNumberInputRepeat();
|
||
}
|
||
|
||
public void Open()
|
||
{
|
||
_fadeTween?.Kill();
|
||
transform.SetAsLastSibling();
|
||
_canvasGroup.alpha = 0f;
|
||
_canvasGroup.blocksRaycasts = true;
|
||
_selectedOptionIndex = ToggleOptionIndex;
|
||
_addAmount = DefaultAddAmount;
|
||
_setAmount = PrizeStockService.Count;
|
||
_editingNumber = false;
|
||
_actionReleased = false;
|
||
_isClosing = false;
|
||
ResetNumberInputRepeat();
|
||
ControlsEnabled = true;
|
||
PrizeStockService.StateChanged -= Refresh;
|
||
PrizeStockService.StateChanged += Refresh;
|
||
_controlToggle.DisplayImmediate(PrizeStockService.Enabled);
|
||
Refresh();
|
||
|
||
_fadeTween = _canvasGroup.DOFade(1f, _fadeDuration).SetEase(Ease.OutCubic).SetUpdate(true);
|
||
_fadeTween.PlayForward();
|
||
}
|
||
|
||
public void UpdateControls()
|
||
{
|
||
if (_isClosing)
|
||
return;
|
||
|
||
Vector2Int axis = In.GetAxis(JoystickSide.Both, InteractMode.Discrete);
|
||
bool actionPressed = In.GetAction(JoystickSide.Both, InteractMode.Discrete);
|
||
bool actionHeld = In.GetAction(JoystickSide.Both, InteractMode.Continious);
|
||
|
||
if (actionHeld == false)
|
||
_actionReleased = true;
|
||
|
||
if (_editingNumber)
|
||
{
|
||
UpdateNumberEditing();
|
||
|
||
if (_actionReleased && actionPressed)
|
||
ApplyNumberChange();
|
||
|
||
return;
|
||
}
|
||
|
||
if (axis.y != 0)
|
||
{
|
||
int direction = axis.y > 0 ? -1 : 1;
|
||
_selectedOptionIndex = (_selectedOptionIndex + direction + _options.Length) % _options.Length;
|
||
RefreshSelection();
|
||
}
|
||
|
||
if (_selectedOptionIndex == ToggleOptionIndex && axis.x != 0)
|
||
SetControlEnabled(axis.x > 0);
|
||
|
||
if (_actionReleased && actionPressed)
|
||
ExecuteSelectedOption();
|
||
}
|
||
|
||
private void ExecuteSelectedOption()
|
||
{
|
||
_actionReleased = false;
|
||
|
||
if (_selectedOptionIndex == ToggleOptionIndex)
|
||
{
|
||
SetControlEnabled(PrizeStockService.Enabled == false);
|
||
return;
|
||
}
|
||
|
||
if (_selectedOptionIndex == AddOptionIndex || _selectedOptionIndex == SetOptionIndex)
|
||
{
|
||
_editingNumber = true;
|
||
ResetNumberInputRepeat();
|
||
RefreshSelection();
|
||
return;
|
||
}
|
||
|
||
Close();
|
||
}
|
||
|
||
private void UpdateNumberEditing()
|
||
{
|
||
Vector2Int axis = In.GetAxis(JoystickSide.Both, InteractMode.Continious);
|
||
UpdateNumberEditing(axis, Time.unscaledTime, Time.unscaledDeltaTime);
|
||
}
|
||
|
||
private void UpdateNumberEditing(Vector2Int axis, float currentTime, float deltaTime)
|
||
{
|
||
int direction = axis.y != 0 ? axis.y : axis.x;
|
||
int baseStep = axis.y != 0 ? 10 : 1;
|
||
|
||
if (direction == 0)
|
||
{
|
||
ResetNumberInputRepeat();
|
||
return;
|
||
}
|
||
|
||
if (_numberInputHeld == false
|
||
|| direction != _heldNumberDirection
|
||
|| baseStep != _heldNumberBaseStep)
|
||
{
|
||
_numberInputHeld = true;
|
||
_heldNumberDirection = direction;
|
||
_heldNumberBaseStep = baseStep;
|
||
_numberHoldTime = 0f;
|
||
_lastNumberChangeTime = currentTime;
|
||
ChangeEditedNumber(direction * baseStep);
|
||
return;
|
||
}
|
||
|
||
_numberHoldTime += deltaTime;
|
||
float progress = Mathf.Clamp01(_numberHoldTime / Mathf.Max(_accelerationTime, 0.01f));
|
||
float acceleration = _accelerationCurve.Evaluate(progress);
|
||
int maximumStepMultiplier = Mathf.Max(_maximumStepMultiplier, 1);
|
||
int stepMultiplier = 1 + Mathf.RoundToInt(acceleration * (maximumStepMultiplier - 1));
|
||
float initialRepeatInterval = Mathf.Max(_initialRepeatInterval, 0.01f);
|
||
float minimumRepeatInterval = Mathf.Clamp(_minimumRepeatInterval, 0.01f, initialRepeatInterval);
|
||
float repeatInterval = Mathf.Lerp(initialRepeatInterval, minimumRepeatInterval, acceleration);
|
||
|
||
if (currentTime - _lastNumberChangeTime < repeatInterval)
|
||
return;
|
||
|
||
_lastNumberChangeTime = currentTime;
|
||
ChangeEditedNumber(direction * baseStep * stepMultiplier);
|
||
}
|
||
|
||
private void ChangeEditedNumber(int delta)
|
||
{
|
||
if (delta == 0)
|
||
return;
|
||
|
||
if (_selectedOptionIndex == AddOptionIndex)
|
||
_addAmount = Mathf.Clamp(_addAmount + delta, 1, MaximumCount);
|
||
else
|
||
_setAmount = Mathf.Clamp(_setAmount + delta, 0, MaximumCount);
|
||
|
||
Refresh();
|
||
}
|
||
|
||
private void ApplyNumberChange()
|
||
{
|
||
_actionReleased = false;
|
||
ResetNumberInputRepeat();
|
||
|
||
if (_selectedOptionIndex == AddOptionIndex)
|
||
{
|
||
PrizeStockService.Add(_addAmount);
|
||
_setAmount = PrizeStockService.Count;
|
||
}
|
||
else
|
||
{
|
||
PrizeStockService.SetCount(_setAmount);
|
||
}
|
||
|
||
_editingNumber = false;
|
||
Refresh();
|
||
}
|
||
|
||
private void SetControlEnabled(bool enabled)
|
||
{
|
||
if (PrizeStockService.Enabled == enabled)
|
||
return;
|
||
|
||
PrizeStockService.SetEnabled(enabled);
|
||
_controlToggle.SetValue(enabled);
|
||
Refresh();
|
||
}
|
||
|
||
private void Refresh()
|
||
{
|
||
_count.text = PrizeStockService.Count.ToString();
|
||
_options[0].text = PrizeStockService.Enabled
|
||
? "КОНТРОЛЬ ОСТАТКОВ: ВКЛЮЧЁН"
|
||
: "КОНТРОЛЬ ОСТАТКОВ: ВЫКЛЮЧЕН";
|
||
_options[1].text = $"ДОБАВИТЬ ПРИЗЫ: +{_addAmount}";
|
||
_options[2].text = $"УСТАНОВИТЬ КОЛИЧЕСТВО: {_setAmount}";
|
||
RefreshSelection();
|
||
}
|
||
|
||
private void RefreshSelection()
|
||
{
|
||
for (int i = 0; i < _options.Length; i++)
|
||
{
|
||
bool selected = i == _selectedOptionIndex;
|
||
_options[i].color = selected ? _selectedOptionColor : _normalOptionColor;
|
||
_options[i].rectTransform.localScale = selected ? Vector3.one * 1.06f : Vector3.one;
|
||
}
|
||
|
||
if (_editingNumber)
|
||
{
|
||
_description.text = _selectedOptionIndex == AddOptionIndex
|
||
? "Добавляет выбранное число к текущему остатку."
|
||
: "Заменяет текущий остаток выбранным значением.";
|
||
_hint.text = "УДЕРЖИВАЙТЕ ДЖОЙСТИК ДЛЯ УСКОРЕНИЯ КНОПКА: ПРИМЕНИТЬ";
|
||
return;
|
||
}
|
||
|
||
_description.text = _selectedOptionIndex switch
|
||
{
|
||
ToggleOptionIndex => "При выключении остаток не списывается, а предупреждение в меню скрыто.",
|
||
AddOptionIndex => "Увеличивает текущий остаток на выбранное количество.",
|
||
SetOptionIndex => "Присваивает счётчику указанное количество призов.",
|
||
_ => "Вернуться к списку настроек."
|
||
};
|
||
_hint.text = "ВВЕРХ / ВНИЗ: ВЫБОР КНОПКА: ОТКРЫТЬ ВЛЕВО / ВПРАВО: ПЕРЕКЛЮЧИТЬ";
|
||
}
|
||
|
||
private void ResetNumberInputRepeat()
|
||
{
|
||
_numberInputHeld = false;
|
||
_heldNumberDirection = 0;
|
||
_heldNumberBaseStep = 0;
|
||
_numberHoldTime = 0f;
|
||
_lastNumberChangeTime = 0f;
|
||
}
|
||
|
||
private void Close()
|
||
{
|
||
if (_isClosing)
|
||
return;
|
||
|
||
_isClosing = true;
|
||
ControlsEnabled = false;
|
||
_fadeTween?.Kill();
|
||
_fadeTween = _canvasGroup.DOFade(0f, _fadeDuration).SetEase(Ease.InCubic).SetUpdate(true);
|
||
_fadeTween.OnComplete(() =>
|
||
{
|
||
_canvasGroup.blocksRaycasts = false;
|
||
OnClosed?.Invoke();
|
||
});
|
||
_fadeTween.PlayForward();
|
||
}
|
||
}
|