Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
Система выдачи призов хоппером: - PrizeSystemManager теперь читает enableHopper из настройки prizes.giveSmallPrize вместо захардкоженного SerializeField (реагирует на изменения в реальном времени) - LevelFinish: исправлен ключ настройки на prizes.giveSmallPrize - Добавлен HopperCheckController для тестирования выдачи приза кнопкой в настройках - Проверка датчика хоппера перенесена в ComDeviceClient (2-й бит INPUT) - PrizeGivenBuffer заменён с PlayerPrefs на потокобезопасный Interlocked-буфер (исправлен краш при вызове PlayerPrefs из фонового потока платы) - Добавлен PrizeSystem.OnPrizeResult (Action<bool>) — событие результата выдачи Отображение ошибки выдачи приза: - Добавлен PrizeErrorDisplay — UI-компонент, подписанный на OnPrizeResult - Зависит от настройки prizes.showPrizeError (реагирует на изменения в реальном времени) QR-коды: - PrizeSystemManager подписан на изменение prizes.phoneNumber — QR-коды перегенерируются автоматически при смене номера - WinBannerController показывает QR-коды только при включённой prizes.giveBigPrize Прочее: - Добавлен Levitator — компонент плавной левитации объекта (высота, скорость, плавность) - Настройки: группы поддержки/тестов реорганизованы, добавлена кнопка btn.hopper_test
154 lines
5.0 KiB
C#
154 lines
5.0 KiB
C#
using UnityEngine;
|
||
using TMPro;
|
||
using RR.Common.Controls;
|
||
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;
|
||
}
|
||
|
||
private void OnDisable()
|
||
{
|
||
if (SettingsManager.Instance != null)
|
||
SettingsManager.Instance.OnSettingChanged -= OnSettingChanged;
|
||
|
||
PrizeSystem.OnPrizeResult -= OnPrizeResult;
|
||
}
|
||
|
||
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();
|
||
}
|
||
}
|
||
|
||
/// <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;
|
||
}
|
||
}
|
||
}
|