Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
- Добавлена система баланса игры (BalanceManager) для управления внутриигровой валютой - Баланс начисляется за импульсы оплаты и списывается за начало/продолжение игры - При старте игры весь внесенный баланс списывается, а жизни начисляются в соответствии с количеством оплат - Добавлены проверки достаточности баланса для начала и продолжения игры - Интегрирован BalanceManager с PaymentManager и GameManager - Исправлен баг с возможностью снятия паузы при показе баннера проигрыша/победы - Добавлена блокировка переключения паузы через IsActive флаг в PauseMenu - Жизни больше не могут уйти в минус при повторной смерти во время показа баннера - Настройки стоимости импульса, начала и продолжения игры берутся из SettingsManager
222 lines
7.8 KiB
C#
222 lines
7.8 KiB
C#
using System;
|
||
using System.Collections;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
using TMPro;
|
||
|
||
using RR.Game2D.Core.Managers;
|
||
|
||
namespace RR.Common.UI
|
||
{
|
||
/// <summary>
|
||
/// Контроллер баннера проигрыша.
|
||
/// Модальное окно, которое отображается при поражении игрока.
|
||
/// </summary>
|
||
public class LoseBannerController : Modal
|
||
{
|
||
[Header("Элементы баннера проигрыша")]
|
||
[SerializeField] private TextMeshProUGUI loseText;
|
||
[SerializeField] private TextMeshProUGUI creditText;
|
||
[SerializeField] private Button continueButton;
|
||
[SerializeField] private TextMeshProUGUI continueButtonText;
|
||
[SerializeField] private float continueButtonCountdown = 30f;
|
||
|
||
[Header("Тексты")]
|
||
[SerializeField] private string creditTextFormat = "У вас осталось: {0}";
|
||
|
||
private RR.Common.Managers.BalanceManager _balanceManager;
|
||
private Coroutine _continueCountdownCoroutine;
|
||
private bool _isSubscribedToBalance = false;
|
||
|
||
/// <summary>
|
||
/// Событие, вызываемое при нажатии "Продолжить" или закрытии баннера.
|
||
/// </summary>
|
||
public event Action ContinueClicked;
|
||
|
||
protected override void Awake()
|
||
{
|
||
base.Awake();
|
||
|
||
if (continueButton)
|
||
{
|
||
continueButton.onClick.AddListener(OnContinueButtonClicked);
|
||
}
|
||
}
|
||
|
||
protected override void OnEnable()
|
||
{
|
||
base.OnEnable();
|
||
|
||
// Инициализируем BalanceManager
|
||
if (_balanceManager == null)
|
||
{
|
||
_balanceManager = GameManager.Instance?.Balance;
|
||
}
|
||
|
||
// Подписываемся на событие только если еще не подписаны
|
||
if (_balanceManager != null && !_isSubscribedToBalance)
|
||
{
|
||
int balance = _balanceManager.CurrentBalance;
|
||
if (creditText)
|
||
{
|
||
creditText.text = string.Format(creditTextFormat, balance);
|
||
}
|
||
_balanceManager.OnBalanceChanged.AddListener(UnlockContinueButton);
|
||
_isSubscribedToBalance = true;
|
||
}
|
||
}
|
||
|
||
protected override void OnDisable()
|
||
{
|
||
// Остановим корутину, если объект деактивируется
|
||
if (_continueCountdownCoroutine != null)
|
||
{
|
||
StopCoroutine(_continueCountdownCoroutine);
|
||
_continueCountdownCoroutine = null;
|
||
}
|
||
|
||
// Безопасная отписка от события
|
||
if (_balanceManager != null && _isSubscribedToBalance)
|
||
{
|
||
_balanceManager.OnBalanceChanged.RemoveListener(UnlockContinueButton);
|
||
_isSubscribedToBalance = false;
|
||
}
|
||
|
||
base.OnDisable();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Показывает баннер проигрыша с указанным временем игры.
|
||
/// </summary>
|
||
/// <param name="gameTime">Время игры в секундах</param>
|
||
public void ShowLose(float gameTime)
|
||
{
|
||
// Инициализируем BalanceManager до открытия окна
|
||
if (_balanceManager == null)
|
||
{
|
||
_balanceManager = GameManager.Instance?.Balance;
|
||
}
|
||
|
||
// Подписываемся на событие изменения баланса, если еще не подписаны
|
||
if (_balanceManager != null && !_isSubscribedToBalance)
|
||
{
|
||
_balanceManager.OnBalanceChanged.AddListener(UnlockContinueButton);
|
||
_isSubscribedToBalance = true;
|
||
}
|
||
|
||
if (loseText)
|
||
{
|
||
loseText.text = $"Время игры: {TimeFormatHelper.FormatTime(gameTime)}";
|
||
}
|
||
|
||
if (creditText && _balanceManager != null)
|
||
{
|
||
creditText.text = string.Format(creditTextFormat, (object)_balanceManager.CurrentBalance);
|
||
}
|
||
|
||
if (continueButtonCountdown <= 0f)
|
||
{
|
||
ContinueClicked?.Invoke();
|
||
GameManager.Instance?.SetPause(false);
|
||
GameManager.Instance?.LoadScene("MainMenu", false);
|
||
return;
|
||
}
|
||
|
||
if (continueButton)
|
||
{
|
||
continueButton.gameObject.SetActive(true);
|
||
// Проверяем возможность продолжить игру через BalanceManager
|
||
bool canContinue = _balanceManager != null && _balanceManager.CanContinueGame();
|
||
continueButton.interactable = canContinue;
|
||
}
|
||
|
||
Open();
|
||
|
||
// Остановим предыдущую корутину, если есть
|
||
if (_continueCountdownCoroutine != null)
|
||
{
|
||
StopCoroutine(_continueCountdownCoroutine);
|
||
}
|
||
|
||
_continueCountdownCoroutine = StartCoroutine(ContinueCountdownCoroutine(continueButtonCountdown));
|
||
}
|
||
|
||
private IEnumerator ContinueCountdownCoroutine(float duration)
|
||
{
|
||
float elapsed = 0f;
|
||
int initialSeconds = Mathf.RoundToInt(duration);
|
||
UpdateContinueText(initialSeconds);
|
||
|
||
while (elapsed < duration)
|
||
{
|
||
float startTime = Time.unscaledTime;
|
||
yield return null;
|
||
|
||
while (Time.unscaledTime - startTime < 1.0f)
|
||
{
|
||
yield return null;
|
||
}
|
||
|
||
elapsed += 1f;
|
||
int remaining = Mathf.Max(0, Mathf.RoundToInt(duration - elapsed));
|
||
UpdateContinueText(remaining);
|
||
}
|
||
|
||
// Таймер истёк — закрываем баннер и выходим в меню
|
||
Close();
|
||
ContinueClicked?.Invoke();
|
||
|
||
if (GameManager.Instance)
|
||
{
|
||
GameManager.Instance.SetPause(false);
|
||
GameManager.Instance.LoadScene("MainMenu", false);
|
||
}
|
||
|
||
_continueCountdownCoroutine = null;
|
||
}
|
||
|
||
private void UpdateContinueText(int secondsRemaining)
|
||
{
|
||
if (continueButtonText)
|
||
{
|
||
continueButtonText.text = $"Продолжить? ({secondsRemaining})";
|
||
}
|
||
}
|
||
|
||
private void UnlockContinueButton(int newBalance)
|
||
{
|
||
if (_balanceManager == null) return;
|
||
|
||
// Проверяем возможность продолжить через BalanceManager
|
||
if (continueButton)
|
||
{
|
||
continueButton.interactable = _balanceManager.CanContinueGame();
|
||
}
|
||
|
||
// Обновляем текст баланса
|
||
if (creditText)
|
||
{
|
||
creditText.text = string.Format(creditTextFormat, newBalance);
|
||
}
|
||
}
|
||
|
||
private void OnContinueButtonClicked()
|
||
{
|
||
// При клике на "Продолжить" — остановим таймер и продолжим игру
|
||
if (_continueCountdownCoroutine != null)
|
||
{
|
||
StopCoroutine(_continueCountdownCoroutine);
|
||
_continueCountdownCoroutine = null;
|
||
}
|
||
|
||
Close();
|
||
ContinueClicked?.Invoke();
|
||
|
||
if (GameManager.Instance)
|
||
{
|
||
GameManager.Instance.SetPause(false);
|
||
GameManager.Instance.ContinueGame();
|
||
}
|
||
}
|
||
}
|
||
} |