Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
- добавлена новая система призов: 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-сцены
146 lines
5.6 KiB
C#
146 lines
5.6 KiB
C#
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
using UnityEngine.InputSystem;
|
||
|
||
using RR.Game2D.Core.Managers;
|
||
|
||
namespace RR.Common.UI
|
||
{
|
||
/// <summary>
|
||
/// Меню паузы. Наследуется от Modal для автоматического управления фокусом.
|
||
/// Открывается/закрывается через GameManager.PauseStateChanged.
|
||
/// </summary>
|
||
public class PauseMenu : Modal
|
||
{
|
||
[Header("Управление паузой")]
|
||
[SerializeField] private InputActionReference pauseToggle;
|
||
|
||
[Header("Кнопки меню")]
|
||
[SerializeField] private Button resumeButton;
|
||
[SerializeField] private Button quitButton;
|
||
|
||
[Header("Связь с другими элементами")]
|
||
[SerializeField] private GameEndUIController bannerController;
|
||
|
||
/// <summary>
|
||
/// Флаг активности меню. Деактивируется когда показан баннер проигрыша/победы.
|
||
/// </summary>
|
||
public bool IsActive { get; private set; } = true;
|
||
|
||
protected override void Awake()
|
||
{
|
||
// Настраиваем обработчики кнопок
|
||
if (resumeButton) resumeButton.onClick.AddListener(OnResumeClicked);
|
||
if (quitButton) quitButton.onClick.AddListener(OnQuitClicked);
|
||
|
||
if (pauseToggle) pauseToggle.action.performed += OnPauseToggle;
|
||
|
||
// Устанавливаем первый выбранный элемент
|
||
SetFirstSelected(resumeButton);
|
||
|
||
|
||
if (GameManager.Instance != null)
|
||
GameManager.Instance.PauseStateChanged += HandlePauseChanged;
|
||
|
||
if (bannerController)
|
||
{
|
||
bannerController.WinBannerShown += _ => { IsActive = false; };
|
||
bannerController.LoseBannerShown += _ => { IsActive = false; };
|
||
bannerController.BannerDismissed += () => { IsActive = true; };
|
||
}
|
||
|
||
// Изначально скрыто - не вызываем base.Awake(), делаем это вручную
|
||
gameObject.SetActive(false);
|
||
}
|
||
|
||
private void OnPauseToggle(InputAction.CallbackContext ctx)
|
||
{
|
||
// Блокируем паузу если меню неактивно (например, показан баннер проигрыша/победы)
|
||
if (!IsActive) return;
|
||
|
||
// Блокируем паузу если открыто любое другое модальное окно
|
||
if (!_isOpen && IsAnyOtherModalOpen()) return;
|
||
|
||
GameManager.Instance.TogglePause();
|
||
}
|
||
|
||
private void OnDestroy()
|
||
{
|
||
if (pauseToggle) pauseToggle.action.performed -= OnPauseToggle;
|
||
|
||
if (GameManager.Instance != null)
|
||
GameManager.Instance.PauseStateChanged -= HandlePauseChanged;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Обработка события паузы от GameManager.
|
||
/// </summary>
|
||
private void HandlePauseChanged(bool paused)
|
||
{
|
||
if (!IsActive) return;
|
||
|
||
// Не показываем меню паузы, если открыто другое модальное окно
|
||
if (paused && IsAnyOtherModalOpen()) return;
|
||
|
||
if (paused)
|
||
Open();
|
||
else
|
||
Close();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Проверяет, открыто ли какое-либо модальное окно, кроме самого PauseMenu.
|
||
/// </summary>
|
||
private bool IsAnyOtherModalOpen()
|
||
{
|
||
var mm = ModalManager.Instance;
|
||
if (mm == null) return false;
|
||
|
||
// Если открытых окон нет — точно нет других
|
||
if (!mm.HasOpenModals) return false;
|
||
|
||
// Если текущее окно — мы сами, значит других нет
|
||
if (mm.CurrentModal == this) return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Переопределяем Close, чтобы при закрытии также снимать паузу.
|
||
/// </summary>
|
||
public override void Close()
|
||
{
|
||
// Блокируем закрытие если меню неактивно (показан баннер)
|
||
if (!IsActive) return;
|
||
|
||
base.Close();
|
||
|
||
// Если игра ещё на паузе, снимаем её
|
||
if (GameManager.Instance != null && GameManager.Instance.IsPaused)
|
||
{
|
||
GameManager.Instance.SetPause(false);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Метод для возобновления игры.
|
||
/// </summary>
|
||
public static void OnResumeClicked()
|
||
{
|
||
// Блокируем если меню неактивно (показан баннер)
|
||
var pauseMenu = FindFirstObjectByType<PauseMenu>();
|
||
if (pauseMenu != null && !pauseMenu.IsActive) return;
|
||
|
||
GameManager.Instance.TogglePause();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Метод для выхода в главное меню.
|
||
/// </summary>
|
||
public void OnQuitClicked()
|
||
{
|
||
GameManager.Instance.SetPause(false);
|
||
GameManager.Instance.LoadScene("MainMenu", false);
|
||
}
|
||
}
|
||
} |