feat(ui, gameplay): update lose banner button flow and score display
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled

- доработана плашка проигрыша `LoseBannerController`:
  добавлены отдельные поля `Menu Button` и `Menu Button Text`
  для кнопки возврата в главное меню
- добавлена логика переключения кнопок по настройке
  `gameplay.canContinueGame`:
  при включенной настройке показывается только кнопка продолжения,
  при выключенной — только кнопка возврата в меню
- добавлены отдельные форматы текста для обеих кнопок:
  `Continue Button Text Format` и `Menu Button Text Format`
  с подстановкой таймера автоматического действия
- реализован единый таймер автодействия для активной кнопки:
  обратный отсчет отображается либо на кнопке продолжения,
  либо на кнопке возврата в меню — в зависимости от текущего режима
- улучшено управление фокусом в плашке проигрыша:
  баннер автоматически назначает `firstSelected` и переводит
  `EventSystem` только на активную видимую кнопку
- обновлен показ очков в игровой витрине:
  подготовлены поля и связанный UI для отображения счета игрока
  в `Level UI` и связанных настройках
- синхронизированы изменения сцены и настроек:
  обновлены `Level UI.unity`, `MainSettingsDatabase.asset`
  и связанные TMP/font assets после правок интерфейса
This commit is contained in:
Данил Ярош 2026-04-01 16:56:25 +03:00
parent 78d7679e2b
commit 63898f9713
6 changed files with 160 additions and 3015 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -3446,7 +3446,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
m_IsActive: 1
--- !u!224 &593492477
RectTransform:
m_ObjectHideFlags: 0
@ -3462,10 +3462,10 @@ RectTransform:
- {fileID: 1312755044}
m_Father: {fileID: 1508457605}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 300, y: -267.50003}
m_SizeDelta: {x: 300, y: 75}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &593492478
MonoBehaviour:
@ -5000,9 +5000,14 @@ MonoBehaviour:
creditText: {fileID: 322757144}
continueButton: {fileID: 1871409157}
continueButtonText: {fileID: 1670382382}
menuButton: {fileID: 593492478}
menuButtonText: {fileID: 1312755045}
continueButtonCountdown: 30
creditTextFormat: "\u0423 \u0432\u0430\u0441 \u043E\u0441\u0442\u0430\u043B\u043E\u0441\u044C:
{0}"
continueButtonTextFormat: "\u041F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u044C?
({0})"
menuButtonTextFormat: "\u0412 \u043C\u0435\u043D\u044E ({0})"
--- !u!225 &1069927042
CanvasGroup:
m_ObjectHideFlags: 0
@ -6070,7 +6075,7 @@ MonoBehaviour:
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: "\u0412 \u043C\u0435\u043D\u044E"
m_text: "\u0412 \u043C\u0435\u043D\u044E (10)"
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 4ef792f79e96f814cac2dd9b8734773d, type: 2}
m_sharedMaterial: {fileID: 2036267684637915601, guid: 4ef792f79e96f814cac2dd9b8734773d, type: 2}
@ -7874,8 +7879,8 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 200, y: -122.5}
m_SizeDelta: {x: 130, y: 130}
m_AnchoredPosition: {x: 200, y: -200}
m_SizeDelta: {x: 250, y: 250}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1745391857
MonoBehaviour:
@ -8716,7 +8721,7 @@ RectTransform:
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 175, y: 5}
m_AnchoredPosition: {x: 200, y: 20}
m_SizeDelta: {x: 400, y: 400}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1909283208
@ -8739,7 +8744,7 @@ MonoBehaviour:
m_ChildAlignment: 4
m_StartCorner: 0
m_StartAxis: 1
m_CellSize: {x: 130, y: 130}
m_CellSize: {x: 250, y: 250}
m_Spacing: {x: 25, y: 25}
m_Constraint: 0
m_ConstraintCount: 2

View File

@ -573,6 +573,41 @@ MonoBehaviour:
buttonSprite: {fileID: 0}
options: []
defaultOptionIndex: 0
- key: gameplay.canContinueGame
displayName: "\u041F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u0442\u044C \u0438\u0433\u0440\u0443"
description: "\u0412\u043A\u043B\u044E\u0447\u0430\u0435\u0442 \u0438\u043B\u0438
\u043E\u0442\u043A\u043B\u044E\u0447\u0430\u0435\u0442 \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0435\u043D\u0438\u0435
\u0438\u0433\u0440\u044B \u0437\u0430 \u0434\u043E\u043F\u043B\u0430\u0442\u0443
\u0438\u0433\u0440\u043E\u043A\u0430. \u0415\u0441\u043B\u0438 \u043E\u0442\u043A\u043B\u044E\u0447\u0438\u0442\u044C,
\u0442\u043E \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u044C \u0438\u0433\u0440\u0443
\u0431\u0443\u0434\u0435\u0442 \u043D\u0435\u043B\u044C\u0437\u044F, \u0431\u0443\u0434\u0435\u0442
\u0442\u043E\u043B\u044C\u043A\u043E \u0432\u043E\u0437\u0440\u0430\u0442 \u0432
\u0433\u043B\u0430\u0432\u043D\u043E\u0435 \u043C\u0435\u043D\u044E"
group: "\u0418\u0433\u0440\u043E\u0432\u043E\u0439 \u043F\u0440\u043E\u0446\u0435\u0441\u0441"
shownInSettings: 1
exposed: 0
valueType: 0
defaultBool: 1
defaultInt: 300
defaultFloat: 300
defaultString:
minInt: 0
maxInt: 3000
intDisplayFormat: 1
intStep: 1
minFloat: 10
maxFloat: 3000
displayAsPercentage: 0
floatDisplayFormat: 0
floatStep: 0.1
applyTarget: 0
audioTargetType: 0
buttonText:
buttonData:
buttonColor: {r: 0, g: 0, b: 0, a: 0}
buttonSprite: {fileID: 0}
options: []
defaultOptionIndex: 0
- key: gameplay.inactivityTimeout
displayName: "\u041C\u0430\u043A\u0441. \u0432\u0440\u0435\u043C\u044F \u0431\u0435\u0437
\u0432\u0432\u043E\u0434\u0430"

View File

@ -2,8 +2,10 @@
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using TMPro;
using RR.Common.Settings;
using RR.Game2D.Core.Managers;
namespace RR.Common.UI
@ -19,10 +21,14 @@ namespace RR.Common.UI
[SerializeField] private TextMeshProUGUI creditText;
[SerializeField] private Button continueButton;
[SerializeField] private TextMeshProUGUI continueButtonText;
[SerializeField] private Button menuButton;
[SerializeField] private TextMeshProUGUI menuButtonText;
[SerializeField] private float continueButtonCountdown = 30f;
[Header("Тексты")]
[SerializeField] private string creditTextFormat = "У вас осталось: {0}";
[SerializeField] private string continueButtonTextFormat = "Продолжить? ({0})";
[SerializeField] private string menuButtonTextFormat = "В меню ({0})";
private RR.Common.Managers.BalanceManager _balanceManager;
private Coroutine _continueCountdownCoroutine;
@ -41,6 +47,10 @@ namespace RR.Common.UI
{
continueButton.onClick.AddListener(OnContinueButtonClicked);
}
if (menuButton)
{
menuButton.onClick.AddListener(OnMenuButtonClicked);
}
}
protected override void OnEnable()
@ -116,21 +126,18 @@ namespace RR.Common.UI
if (continueButtonCountdown <= 0f)
{
ContinueClicked?.Invoke();
GameManager.Instance?.SetPause(false);
GameManager.Instance?.LoadScene("MainMenu", false);
ReturnToMainMenu();
return;
}
if (continueButton)
Button activeButton = ConfigureVisibleButtons();
if (activeButton != null)
{
continueButton.gameObject.SetActive(true);
// Проверяем возможность продолжить игру через BalanceManager
bool canContinue = _balanceManager != null && _balanceManager.CanContinueGame();
continueButton.interactable = canContinue;
SetFirstSelected(activeButton);
}
Open();
FocusActiveButton(activeButton);
// Остановим предыдущую корутину, если есть
if (_continueCountdownCoroutine != null)
@ -177,9 +184,14 @@ namespace RR.Common.UI
private void UpdateContinueText(int secondsRemaining)
{
if (continueButtonText)
if (continueButton != null && continueButton.gameObject.activeSelf && continueButtonText)
{
continueButtonText.text = $"Продолжить? ({secondsRemaining})";
continueButtonText.text = string.Format(continueButtonTextFormat, secondsRemaining);
}
if (menuButton != null && menuButton.gameObject.activeSelf && menuButtonText)
{
menuButtonText.text = string.Format(menuButtonTextFormat, secondsRemaining);
}
}
@ -218,5 +230,62 @@ namespace RR.Common.UI
GameManager.Instance.ContinueGame();
}
}
private void OnMenuButtonClicked()
{
if (_continueCountdownCoroutine != null)
{
StopCoroutine(_continueCountdownCoroutine);
_continueCountdownCoroutine = null;
}
ReturnToMainMenu();
}
private Button ConfigureVisibleButtons()
{
bool canContinueGameSetting = SettingsManager.Instance != null
&& SettingsManager.Instance.GetBool("gameplay.canContinueGame");
if (continueButton != null)
{
continueButton.gameObject.SetActive(canContinueGameSetting);
continueButton.interactable = canContinueGameSetting
&& _balanceManager != null
&& _balanceManager.CanContinueGame();
}
if (menuButton != null)
{
menuButton.gameObject.SetActive(!canContinueGameSetting);
menuButton.interactable = true;
}
return canContinueGameSetting ? continueButton : menuButton;
}
private void FocusActiveButton(Button activeButton)
{
if (activeButton == null || !activeButton.gameObject.activeInHierarchy || EventSystem.current == null)
{
return;
}
EventSystem.current.SetSelectedGameObject(null);
EventSystem.current.SetSelectedGameObject(activeButton.gameObject);
activeButton.Select();
}
private void ReturnToMainMenu()
{
Close();
ContinueClicked?.Invoke();
if (GameManager.Instance)
{
GameManager.Instance.SetPause(false);
GameManager.Instance.LoadScene("MainMenu", false);
}
}
}
}
}