132 lines
5.4 KiB
C#
132 lines
5.4 KiB
C#
using System.Collections.Generic;
|
||
using Unity.Profiling;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
using TMPro;
|
||
using BaseGames.Core.Events;
|
||
|
||
namespace BaseGames.UI.HUD
|
||
{
|
||
/// <summary>
|
||
/// 游戏内 HUD 控制器(架构 10_UIModule §2)。
|
||
/// 订阅事件频道更新 HP 格子、魂魂力/灵力/灵珠/弹簧充能和形态图标。
|
||
/// HP/弹簧格子采用 SetActive 复用,避免运行期频繁 Instantiate/Destroy。
|
||
/// </summary>
|
||
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<GameObject> _hpCells = new();
|
||
private readonly List<GameObject> _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()
|
||
{
|
||
_onHPChanged?.Subscribe(UpdateHP).AddTo(_subs);
|
||
_onMaxHPChanged?.Subscribe(RebuildHPCells).AddTo(_subs);
|
||
_onSoulPowerChanged?.Subscribe(UpdateSoul).AddTo(_subs);
|
||
_onSpiritPowerChanged?.Subscribe(UpdateSpirit).AddTo(_subs);
|
||
_onLingZhuChanged?.Subscribe(UpdateLingZhu).AddTo(_subs);
|
||
_onSpringChargesChanged?.Subscribe(RebuildSpringIcons).AddTo(_subs);
|
||
_onFormChanged?.Subscribe(UpdateFormIcon).AddTo(_subs);
|
||
// 交互提示由独立的 InteractPromptWidget 组件处理,HUDController 不再直接订阅
|
||
}
|
||
|
||
private void OnDisable() => _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);
|
||
}
|
||
}
|
||
}
|