UI 系统
This commit is contained in:
87
Assets/_Game/Scripts/UI/DataDrivenAbilityPanel.cs
Normal file
87
Assets/_Game/Scripts/UI/DataDrivenAbilityPanel.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using BaseGames.Core;
|
||||
using BaseGames.Core.Events;
|
||||
using BaseGames.Player;
|
||||
|
||||
namespace BaseGames.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 能力解锁总览面板(数据驱动)。据 <see cref="AbilityMetaSO"/> 列出全部能力 + 已解锁/未解锁态。
|
||||
/// 在场景中找 <see cref="PlayerStats"/> 读 <see cref="PlayerStats.UnlockedAbilities"/>;
|
||||
/// 订阅 <see cref="AbilityTypeEventChannelSO"/>(EVT_AbilityUnlocked) 实时刷新解锁态。
|
||||
/// 策划改 UI_AbilityMeta 即增删/重排能力、改标签图标;美术改 UI_AbilityCell / 面板预制件改样式。
|
||||
/// </summary>
|
||||
public class DataDrivenAbilityPanel : MonoBehaviour
|
||||
{
|
||||
[Header("数据 / 单元格")]
|
||||
[SerializeField] private AbilityMetaSO _meta;
|
||||
[Tooltip("能力格的父节点(通常挂 GridLayoutGroup)。")]
|
||||
[SerializeField] private Transform _container;
|
||||
[SerializeField] private AbilityCellView _cellPrefab;
|
||||
|
||||
[Header("引用")]
|
||||
[SerializeField] private Button _btnClose;
|
||||
|
||||
[Header("Event Channels")]
|
||||
[Tooltip("能力解锁广播(AbilityType payload),用于实时刷新。对应 EVT_AbilityUnlocked。")]
|
||||
[SerializeField] private AbilityTypeEventChannelSO _onAbilityUnlocked;
|
||||
|
||||
private readonly List<(AbilityCellView view, AbilityType type)> _cells = new();
|
||||
private readonly CompositeDisposable _subs = new();
|
||||
private PlayerStats _stats;
|
||||
|
||||
private void Awake() => _btnClose?.onClick.AddListener(OnClose);
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_onAbilityUnlocked?.Subscribe(_ => RefreshStates()).AddTo(_subs);
|
||||
_stats = FindObjectOfType<PlayerStats>(true); // 游戏内有玩家;菜单态为 null(全部显示未解锁)
|
||||
BuildList();
|
||||
}
|
||||
|
||||
private void OnDisable() => _subs.Clear();
|
||||
|
||||
/// <summary>据 AbilityMetaSO 重建能力格(public 以便编辑器/测试)。</summary>
|
||||
public void BuildList()
|
||||
{
|
||||
ClearList();
|
||||
if (_meta == null || _container == null || _cellPrefab == null) return;
|
||||
foreach (var item in _meta.Items)
|
||||
{
|
||||
var cell = Instantiate(_cellPrefab, _container);
|
||||
cell.gameObject.SetActive(true);
|
||||
cell.Bind(item.labelKey, item.icon, IsUnlocked(item.type));
|
||||
_cells.Add((cell, item.type));
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshStates()
|
||||
{
|
||||
if (_stats == null) _stats = FindObjectOfType<PlayerStats>(true);
|
||||
foreach (var (view, type) in _cells)
|
||||
if (view != null) view.SetUnlocked(IsUnlocked(type));
|
||||
}
|
||||
|
||||
private bool IsUnlocked(AbilityType type) => _stats != null && _stats.HasAbility(type);
|
||||
|
||||
private void ClearList()
|
||||
{
|
||||
_cells.Clear();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnClose()
|
||||
{
|
||||
var uiMgr = ServiceLocator.GetOrDefault<UIManager>();
|
||||
if (uiMgr != null) uiMgr.CloseTopPanel();
|
||||
else gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user