using System.Collections.Generic; using Unity.Profiling; using UnityEngine; using UnityEngine.UI; using TMPro; using BaseGames.Core.Events; namespace BaseGames.UI.HUD { /// /// 游戏内 HUD 控制器(架构 10_UIModule §2)。 /// 订阅事件频道更新 HP 格子、魂魂力/灵力/灵珠/弹簧充能和形态图标。 /// HP/弹簧格子采用 SetActive 复用,避免运行期频繁 Instantiate/Destroy。 /// public class HUDController : MonoBehaviour { [Header("HP")] [SerializeField] private Transform _hpContainer; [SerializeField] private GameObject _hpCellPrefab; [Header("Gauges")] [SerializeField] private Image _soulGaugeFill; [SerializeField] private Image _spiritGaugeFill; [SerializeField] private TMP_Text _lingZhuText; [Header("Spring Charges")] [SerializeField] private Transform _springContainer; [SerializeField] private GameObject _springIconPrefab; [Header("Form")] [SerializeField] private Image[] _formIcons; [Header("Interact Prompt")] [Tooltip("独立 Widget 组件负责渲染图标+文本,HUDController 仅保留引用供编辑器配置检查")] [SerializeField] private InteractPromptWidget _interactPromptWidget; [Header("Event Channels - Subscribe")] [SerializeField] private IntEventChannelSO _onHPChanged; [SerializeField] private IntEventChannelSO _onMaxHPChanged; [SerializeField] private IntEventChannelSO _onSoulPowerChanged; [SerializeField] private IntEventChannelSO _onSpiritPowerChanged; [SerializeField] private IntEventChannelSO _onLingZhuChanged; [SerializeField] private IntEventChannelSO _onSpringChargesChanged; [SerializeField] private IntEventChannelSO _onFormChanged; private readonly List _hpCells = new(); private readonly List _springIcons = new(); private readonly CompositeDisposable _subs = new(); private int _lastLingZhu = int.MinValue; // ── 性能基线 (Profiler 窗口可在 "Scripts" 类别下看到) ── private static readonly ProfilerMarker s_RebuildHPMarker = new("HUD.RebuildHPCells"); private static readonly ProfilerMarker s_RebuildSpringMarker = new("HUD.RebuildSpringIcons"); private void OnEnable() { // MaxHP 必须先于 HP 订阅:粘性回放时先 RebuildHPCells 建满格子,再 UpdateHP 设激活数, // 否则受伤档(CurrentHP _subs.Clear(); private void UpdateHP(int current) { for (int i = 0; i < _hpCells.Count; i++) if (_hpCells[i] != null) _hpCells[i].SetActive(i < current); } private void RebuildHPCells(int max) { using var _ = s_RebuildHPMarker.Auto(); if (_hpContainer == null || _hpCellPrefab == null) return; // 复用现有 Cell,仅在数量不足时 Instantiate 补充,超出时 SetActive(false) 而非 Destroy for (int i = 0; i < max; i++) { if (i < _hpCells.Count) _hpCells[i].SetActive(true); else _hpCells.Add(Instantiate(_hpCellPrefab, _hpContainer)); } for (int i = max; i < _hpCells.Count; i++) if (_hpCells[i] != null) _hpCells[i].SetActive(false); } private void UpdateSoul(int val) { if (_soulGaugeFill != null) _soulGaugeFill.fillAmount = val / 100f; } private void UpdateSpirit(int val) { if (_spiritGaugeFill != null) _spiritGaugeFill.fillAmount = val / 100f; } private void UpdateLingZhu(int val) { if (_lingZhuText == null || val == _lastLingZhu) return; _lastLingZhu = val; _lingZhuText.text = val.ToString(); } private void RebuildSpringIcons(int charges) { using var _ = s_RebuildSpringMarker.Auto(); if (_springContainer == null || _springIconPrefab == null) return; // 复用已有图标,超出数量时 SetActive(false) for (int i = 0; i < charges; i++) { if (i < _springIcons.Count) _springIcons[i].SetActive(true); else _springIcons.Add(Instantiate(_springIconPrefab, _springContainer)); } for (int i = charges; i < _springIcons.Count; i++) if (_springIcons[i] != null) _springIcons[i].SetActive(false); } private void UpdateFormIcon(int formIndex) { if (_formIcons == null) return; for (int i = 0; i < _formIcons.Length; i++) if (_formIcons[i] != null) _formIcons[i].enabled = (i == formIndex); } } }