using UnityEngine; using TMPro; using RR.Common.Controls; using RR.Common.Managers; using RR.Common.Prizes; using RR.Common.Settings; namespace RR.Common.UI { /// /// UI-компонент для отображения ошибки выдачи приза хоппером. /// Подписывается на PrizeSystem.OnPrizeResult и показывает сообщение об ошибке, /// если выдача приза завершилась неудачно (таймаут датчика). /// /// Зависит от настройки prizes.showPrizeError. /// public class PrizeErrorDisplay : MonoBehaviour { [Header("UI")] [Tooltip("Текст сообщения об ошибке. Если не задан, ищется на этом же объекте.")] [SerializeField] private TextMeshProUGUI errorText; [Tooltip("Объект-контейнер ошибки (для скрытия/показа). Если не задан, используется gameObject.")] [SerializeField] private GameObject errorContainer; [Header("Настройки")] [Tooltip("Текст ошибки, который отображается игроку.")] [SerializeField] private string errorMessage = "Ошибка выдачи приза!"; [Header("Анимация")] [Tooltip("CanvasGroup для плавного появления/исчезновения.")] [SerializeField] private CanvasGroup canvasGroup; [Tooltip("Длительность анимации появления/исчезновения.")] [SerializeField] private float fadeDuration = 0.3f; private bool _enabled; private bool _isShowing; private Coroutine _fadeCoroutine; private void OnEnable() { if (errorContainer == null) errorContainer = gameObject; if (errorText == null) errorText = GetComponentInChildren(); Hide(instant: true); _enabled = SettingsManager.Instance != null && SettingsManager.Instance.GetBool("prizes.showPrizeError"); if (SettingsManager.Instance != null) SettingsManager.Instance.OnSettingChanged += OnSettingChanged; PrizeSystem.OnPrizeResult += OnPrizeResult; // Подписываемся на новую систему призов (если доступна) if (PrizeSystemManager.Instance != null) PrizeSystemManager.Instance.OnAnyPrizeResult += OnAnyPrizeResult; } private void OnDisable() { if (SettingsManager.Instance != null) SettingsManager.Instance.OnSettingChanged -= OnSettingChanged; PrizeSystem.OnPrizeResult -= OnPrizeResult; if (PrizeSystemManager.Instance != null) PrizeSystemManager.Instance.OnAnyPrizeResult -= OnAnyPrizeResult; } private void OnSettingChanged(string key, SettingValue value) { if (key != "prizes.showPrizeError") return; _enabled = value.b; if (!_enabled) Hide(instant: true); } private void OnPrizeResult(bool success) { if (success) { if (_isShowing) Hide(); } else { Show(); } } private void OnAnyPrizeResult(PrizeType type, bool success) { // Показываем ошибку только для хоппера и витрины if (type == PrizeType.QRCode) return; if (success) { if (_isShowing) Hide(); } else { Show(); } } /// /// Показывает сообщение об ошибке выдачи приза. /// public void Show() { if (!_enabled) return; _isShowing = true; if (errorText) errorText.text = errorMessage; errorContainer.SetActive(true); if (canvasGroup) { if (_fadeCoroutine != null) StopCoroutine(_fadeCoroutine); _fadeCoroutine = StartCoroutine(Fade(0f, 1f, fadeDuration)); } Debug.LogWarning("[PrizeErrorDisplay] Ошибка выдачи приза отображена."); } /// /// Скрывает сообщение об ошибке. /// public void Hide(bool instant = false) { _isShowing = false; if (_fadeCoroutine != null) { StopCoroutine(_fadeCoroutine); _fadeCoroutine = null; } if (instant || !canvasGroup) { if (canvasGroup) canvasGroup.alpha = 0f; errorContainer.SetActive(false); } else { _fadeCoroutine = StartCoroutine(FadeAndDisable()); } } private System.Collections.IEnumerator FadeAndDisable() { yield return Fade(canvasGroup.alpha, 0f, fadeDuration); errorContainer.SetActive(false); _fadeCoroutine = null; } private System.Collections.IEnumerator Fade(float from, float to, float duration) { if (!canvasGroup) yield break; float elapsed = 0f; canvasGroup.alpha = from; while (elapsed < duration) { elapsed += Time.unscaledDeltaTime; canvasGroup.alpha = Mathf.Lerp(from, to, elapsed / duration); yield return null; } canvasGroup.alpha = to; } } }