Danro/Assets/Scripts/UI/GameEndUIController.cs
Danil Iarosh 78d7679e2b
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
feat(prizes, ui): complete Mar 24-Apr 2 sprint ahead of schedule
- завершен спринт 24 марта - 2 апреля с опережением плана и закрытием задач раньше срока
- расширена и стабилизирована система призов:
  добавлены и доработаны QR-tier конфиги, новые типы и модели данных,
  сохранение `qrCodes` в `prizes.json`, fallback-логика и синхронизация
  через `PrizeSystemManager`, `PrizeDatabase` и `LevelPrizeConfig`
- переработан flow настройки QR-призов:
  добавлены `QRCodeSettingsModal` и связанный UI-код,
  разнесены короткий текст приза и полный текст сообщения,
  добавлены шаблоны форматирования, корректная подстановка текста
  в QR и в UI-модалках, а также сохранение конфигурации между запусками
- доработан flow суперприза и текстовых настроек:
  добавлены fallback-правила показа, корректная обработка пустых строк
  и строк из одних пробелов, обновлены binders и показ текста в меню
- реализована и обновлена отдельная настройка витрины:
  добавлена `PrizeStandSettingsModal`, обновлена навигация строк,
  логика выбора ячейки и порогов очков, циклический выбор ячеек,
  ускорение изменения значений и исправления для keyboard/gamepad UX
- доработана игровая модалка витрины `PrizeStandModal`:
  добавлен вывод очков игрока, форматируемый текст счета,
  улучшено отображение ячеек и связанная логика выбора приза
- исправлен подсчет очков и интеграция с prize flow:
  `ScoreSystem` переведен на событийное обновление текущего счета,
  добавлены `CurrentScore`, `CurrentScoreChanged` и корректный display score,
  витрина и связанные UI-элементы теперь получают актуальные очки,
  а не нулевые или несвоевременные preview-значения
- переработаны модальные окна и навигация UI:
  улучшены `Modal`, `ModalManager`, `UIRowPointer`, `RulesModal`,
  `QRCodeModal`, `PrizeStandModal`, `LevelPrizeSettingsModal` и др.,
  чтобы фокус, указатель и submit работали консистентно без мыши
- обновлен win/prize UI:
  доработаны `WinBannerController`, `GameEndUIController`,
  `MainMenu`, `QRCodeUIController`, `TopPanelTextController` и настройки UI,
  улучшены тексты баннеров, отображение призов и итогового счета
- обновлены сцены и ассеты под новый flow:
  `MainMenu`, `Level UI`, prefab'ы строк настроек и кнопок,
  глобальные префабы, шрифты TMP, иконки, recovery-данные и ресурсы UI
- добавлены вспомогательные UI-компоненты и служебные скрипты:
  `ButtonTextFocusColor`, `SelectableDescriptionTarget`, `QRTier`
  и другие изменения, поддерживающие новый конфигурируемый prize UI
2026-04-01 12:47:17 +03:00

150 lines
4.6 KiB
C#

using System;
using UnityEngine;
using UnityEngine.UI;
using RR.Common.Managers;
using RR.Common.Prizes;
using RR.Game2D.Behaviour;
using RR.Game2D.Core.Managers;
namespace RR.Common.UI
{
/// <summary>
/// Контроллер панели завершения игры.
/// Управляет отображением баннеров выигрыша и проигрыша.
/// </summary>
public class GameEndUIController : MonoBehaviour
{
[Header("Баннеры")]
[SerializeField] private WinBannerController winBanner;
[SerializeField] private LoseBannerController loseBanner;
[Header("Фон")]
[SerializeField] private Image backgroundOverlay;
[SerializeField] private Color overlayColor = new Color(0, 0, 0, 100f/255f);
/// <summary>
/// Событие, вызываемое при показе баннера выигрыша.
/// </summary>
public event Action<float> WinBannerShown;
/// <summary>
/// Событие, вызываемое при показе баннера проигрыша.
/// </summary>
public event Action<float> LoseBannerShown;
/// <summary>
/// Событие, вызываемое при закрытии любого баннера.
/// </summary>
public event Action BannerDismissed;
private void OnEnable()
{
if (GameManager.Instance == null) return;
GameManager.Instance.GameWonEvent += OnGameWon;
GameManager.Instance.GameOverEvent += OnGameOver;
// Подписываемся на события закрытия баннеров
if (winBanner)
{
winBanner.WinBannerDismissed += OnBannerDismissed;
}
if (loseBanner)
{
loseBanner.ContinueClicked += OnBannerDismissed;
}
}
private void OnDisable()
{
if (GameManager.Instance == null) return;
GameManager.Instance.GameWonEvent -= OnGameWon;
GameManager.Instance.GameOverEvent -= OnGameOver;
// Отписываемся от событий закрытия баннеров
if (winBanner)
{
winBanner.WinBannerDismissed -= OnBannerDismissed;
}
if (loseBanner)
{
loseBanner.ContinueClicked -= OnBannerDismissed;
}
}
private void Awake()
{
// Изначально скрываем фон
if (backgroundOverlay)
{
backgroundOverlay.color = new Color(0, 0, 0, 0);
}
}
private void OnGameWon(float gameTime)
{
if (GameManager.Instance)
{
GameManager.Instance.SetPause(true);
}
ShowOverlay();
if (winBanner)
{
LevelPrizeConfig prizeConfig = PrizeSystemManager.Instance != null
? PrizeSystemManager.Instance.GetPrizeConfigForCurrentLevel()
: new LevelPrizeConfig();
bool showFinalScore = GameManager.Instance != null && GameManager.Instance.IsCurrentLevelFinal();
int finalScore = ScoreSystem.Instance != null ? ScoreSystem.Instance.FinalScore : 0;
winBanner.ShowWin(gameTime, prizeConfig, finalScore, showFinalScore);
}
WinBannerShown?.Invoke(gameTime);
}
private void OnGameOver(float gameTime)
{
if (GameManager.Instance)
{
GameManager.Instance.SetPause(true);
}
ShowOverlay();
if (loseBanner)
{
loseBanner.ShowLose(gameTime);
}
LoseBannerShown?.Invoke(gameTime);
}
private void ShowOverlay()
{
if (backgroundOverlay)
{
backgroundOverlay.color = overlayColor;
}
}
private void HideOverlay()
{
if (backgroundOverlay)
{
backgroundOverlay.color = new Color(0, 0, 0, 0);
}
}
private void OnBannerDismissed()
{
HideOverlay();
BannerDismissed?.Invoke();
}
}
}