Files
zeling_v2/Assets/_Game/Scripts/UI/DataDrivenAbilityPanel.cs
2026-06-08 11:26:17 +08:00

88 lines
3.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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);
}
}
}