111 lines
4.9 KiB
C#
111 lines
4.9 KiB
C#
using System.Collections.Generic;
|
||
using System.Threading;
|
||
using System.Threading.Tasks;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
using UnityEngine.EventSystems;
|
||
using TMPro;
|
||
using BaseGames.Core.Events;
|
||
using BaseGames.Localization;
|
||
|
||
namespace BaseGames.UI.MainMenu
|
||
{
|
||
/// <summary>
|
||
/// 新游戏模式(难度)选择面板,<b>数据驱动</b>:据 <see cref="NewGameModeConfigSO"/> 生成难度按钮,
|
||
/// 经 <see cref="IUINavigator"/> 模态压栈,返回 <see cref="DifficultyLevel"/>;
|
||
/// 点返回 / 按 ESC 取消则返回 null(由 <see cref="UIResultPanel{T}"/> 兜底)。
|
||
/// 选中某项时在共享说明区显示其 descKey(手柄/鼠标导航通用)。
|
||
/// 策划改 UI_NewGameModeConfig 即可增删/重排难度、改标签/说明;样式改 UI_NewGameModePanel / UI_MainMenu_Button 预制件。
|
||
/// </summary>
|
||
public class NewGameModeController : UIResultPanel<DifficultyLevel?>
|
||
{
|
||
[Header("数据表 / 选项列表")]
|
||
[SerializeField] private NewGameModeConfigSO _config;
|
||
[Tooltip("难度按钮的父节点(通常挂 VerticalLayoutGroup)。")]
|
||
[SerializeField] private Transform _container;
|
||
[SerializeField] private MainMenuButtonView _buttonPrefab;
|
||
|
||
[Header("引用")]
|
||
[SerializeField] private LocalizedText _titleText;
|
||
[Tooltip("当前选中难度的说明文本(随选中项切换)。")]
|
||
[SerializeField] private TMP_Text _descText;
|
||
[SerializeField] private Button _btnBack;
|
||
|
||
// 取消 / ESC / 返回默认结果:未选择。
|
||
protected override DifficultyLevel? CancelResult => null;
|
||
|
||
private readonly List<(MainMenuButtonView view, string descKey)> _options = new();
|
||
private MainMenuButtonView _firstButton;
|
||
private GameObject _lastSelected;
|
||
|
||
private void Awake() => _btnBack?.onClick.AddListener(() => Complete(null));
|
||
|
||
protected override void OnPanelOpen() => BuildMenu();
|
||
|
||
/// <summary>默认焦点:第一项(通常普通难度),避免误选高难项。</summary>
|
||
protected override GameObject ResolveFirstSelected()
|
||
=> _firstButton != null ? _firstButton.Button.gameObject
|
||
: _btnBack != null ? _btnBack.gameObject : null;
|
||
|
||
/// <summary>据配置重建难度按钮(public 以便编辑器预览/测试)。</summary>
|
||
public void BuildMenu()
|
||
{
|
||
ClearMenu();
|
||
if (_titleText != null && _config != null) _titleText.SetKey(_config.TitleKey);
|
||
if (_config == null || _container == null || _buttonPrefab == null) return;
|
||
|
||
foreach (var item in _config.Items)
|
||
{
|
||
var view = Instantiate(_buttonPrefab, _container);
|
||
view.gameObject.SetActive(true);
|
||
var level = item.level;
|
||
view.Bind(item.labelKey, item.icon, () => Complete(level));
|
||
_options.Add((view, item.descKey));
|
||
if (_firstButton == null) _firstButton = view;
|
||
}
|
||
if (_descText != null) _descText.text = string.Empty;
|
||
_lastSelected = null;
|
||
}
|
||
|
||
private void ClearMenu()
|
||
{
|
||
_options.Clear();
|
||
_firstButton = null;
|
||
if (_container == null) return;
|
||
for (int i = _container.childCount - 1; i >= 0; i--)
|
||
{
|
||
var c = _container.GetChild(i).gameObject;
|
||
if (Application.isPlaying) Destroy(c); else DestroyImmediate(c);
|
||
}
|
||
}
|
||
|
||
// 显示当前选中难度的说明(轮询 EventSystem 选中项;手柄/鼠标导航通用,按钮无需额外组件)。
|
||
private void Update()
|
||
{
|
||
if (_descText == null || EventSystem.current == null) return;
|
||
var sel = EventSystem.current.currentSelectedGameObject;
|
||
if (sel == _lastSelected) return;
|
||
_lastSelected = sel;
|
||
|
||
string descKey = null;
|
||
foreach (var (view, dk) in _options)
|
||
if (view != null && view.Button != null && view.Button.gameObject == sel) { descKey = dk; break; }
|
||
_descText.text = string.IsNullOrEmpty(descKey)
|
||
? string.Empty
|
||
: LocalizationManager.Get(descKey, LocalizationTable.UI);
|
||
}
|
||
|
||
/// <summary>弹出难度选择并等待结果(DifficultyLevel / null=取消)。由导航器压栈管理。</summary>
|
||
public Task<DifficultyLevel?> ShowAsync(CancellationToken ct = default)
|
||
{
|
||
var nav = GetService<IUINavigator>();
|
||
if (nav == null)
|
||
{
|
||
Debug.LogError("[NewGameMode] 未找到 IUINavigator 服务,无法弹出模式选择。", this);
|
||
return Task.FromResult<DifficultyLevel?>(null);
|
||
}
|
||
return nav.PushForResultAsync<DifficultyLevel?>(this, ct);
|
||
}
|
||
}
|
||
}
|