88 lines
3.4 KiB
C#
88 lines
3.4 KiB
C#
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);
|
||
}
|
||
}
|
||
}
|