Danro/Assets/Scripts/UI/PrizeErrorDisplay.cs
Danil Iarosh a40b761c81
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
feat(prizes, ui): add configurable level prize flow and launcher assets
- добавлена новая система призов:
  PrizeBase, PrizeType, PrizeDatabase, LevelPrizeConfig и реализации
  для hopper, QR-кода, отсутствия приза и стойки с призом
- добавлена конфигурация призов уровней через `prizes.json`
  и связанная логика загрузки/обработки в менеджерах игры
- расширен UI главного меню и настроек уровней:
  добавлены LevelSettingsModal, LevelPrizeSettingsModal,
  QRCodeModal и PrizeStandModal
- обновлена навигация модальных окон и связанный UI-код:
  ModalManager, MainMenu, RulesModal, PauseMenu,
  PrizeErrorDisplay, UIRowPointer и WinBannerController
- доработаны настройки и генерация UI-элементов:
  обновлены SettingsDatabase, SettingsUIGenerator,
  SettingUIItem, ValueSelectorRow и editor drawer для настроек
- обновлены и добавлены UI-prefab'ы для кнопок, строк настроек,
  панели групп и кнопки настроек уровня
- обновлены сцены `MainMenu` и `Level UI` под новый флоу
  настройки уровней, выбора призов и отображения модалок
- добавлены файлы лаунчера в `StreamingAssets`,
  включая `RRLauncher.exe`, служебные meta-файлы и документацию
- улучшено логирование через FileLogger
  и удален устаревший код лицензирования
- удалены больше неиспользуемые файлы:
  `Licensing.cs`, `SteppedSlider.cs` и recovery-сцены
2026-03-16 08:15:36 +03:00

178 lines
5.9 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using UnityEngine;
using TMPro;
using RR.Common.Controls;
using RR.Common.Managers;
using RR.Common.Prizes;
using RR.Common.Settings;
namespace RR.Common.UI
{
/// <summary>
/// UI-компонент для отображения ошибки выдачи приза хоппером.
/// Подписывается на PrizeSystem.OnPrizeResult и показывает сообщение об ошибке,
/// если выдача приза завершилась неудачно (таймаут датчика).
///
/// Зависит от настройки prizes.showPrizeError.
/// </summary>
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<TextMeshProUGUI>();
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();
}
}
/// <summary>
/// Показывает сообщение об ошибке выдачи приза.
/// </summary>
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] Ошибка выдачи приза отображена.");
}
/// <summary>
/// Скрывает сообщение об ошибке.
/// </summary>
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;
}
}
}