using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using BaseGames.Core; using BaseGames.Core.Events; using BaseGames.Player; namespace BaseGames.UI { /// /// 能力解锁总览面板(数据驱动)。据 列出全部能力 + 已解锁/未解锁态。 /// 在场景中找 ; /// 订阅 (EVT_AbilityUnlocked) 实时刷新解锁态。 /// 策划改 UI_AbilityMeta 即增删/重排能力、改标签图标;美术改 UI_AbilityCell / 面板预制件改样式。 /// 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(true); // 游戏内有玩家;菜单态为 null(全部显示未解锁) BuildList(); } private void OnDisable() => _subs.Clear(); /// 据 AbilityMetaSO 重建能力格(public 以便编辑器/测试)。 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(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(); if (uiMgr != null) uiMgr.CloseTopPanel(); else gameObject.SetActive(false); } } }