Files
gold_dolphin/unity/Assets/UI/GameHUD.cs
T
2026-07-04 16:07:08 +08:00

179 lines
7.0 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 UnityEngine;
using UnityEngine.UI;
using IndianOceanAssets.Engine2_5D;
namespace GameFramework
{
/// <summary>
/// 游戏内 HUD —— 魂灵计数 + 生命图标 + 技能CD。
///
/// 布局:
/// - 左上角:收集到的魂灵(icon + 数字)
/// - 左下角:5个生命图标
/// - 右下角:3个技能图标(冲刺/摇铃/灵灯)+ CD遮罩
/// </summary>
public class GameHUD : MonoBehaviour
{
[Header("魂灵计数(左上角)")]
[SerializeField] private Image soulIcon;
[SerializeField] private Text soulCountText;
[Header("生命图标(左下角)")]
[SerializeField] private Image[] lifeIcons; // 5个生命图标
[Header("技能图标(右下角)")]
[SerializeField] private Image skillSprintIcon;
[SerializeField] private Image skillSprintCD; // CD 遮罩(Image.fillAmount
[SerializeField] private Image skillBellIcon;
[SerializeField] private Image skillBellCD;
[SerializeField] private Image skillLanternIcon;
[SerializeField] private Image skillLanternCD;
[Header("暂停")]
[SerializeField] private Button pauseButton;
private HealthSystem _playerHealth;
private SpiritLanternSystem _lanternSystem;
private EchoSystem _echoSystem;
private PlayerController _playerController;
private int _maxHealth = 5;
void Start()
{
var player = GameObject.FindWithTag("Player");
if (player != null)
{
_playerHealth = player.GetComponent<HealthSystem>();
_lanternSystem = player.GetComponent<SpiritLanternSystem>();
_echoSystem = player.GetComponent<EchoSystem>();
_playerController = player.GetComponent<PlayerController>();
}
if (pauseButton != null)
pauseButton.onClick.AddListener(OnPauseClick);
// 订阅分数事件(魂灵计数复用分数系统)
ScoreManager.onScoreChanged += UpdateSoulCount;
UpdateSoulCount(ScoreManager.Instance != null ? ScoreManager.Instance.CurrentScore : 0);
UpdateLifeIcons();
// 自动创建受击泛红特效(如果场景中没有)
if (FindObjectOfType<DamageFlashOverlay>() == null)
{
var overlayObj = new GameObject("DamageFlashOverlay");
overlayObj.AddComponent<DamageFlashOverlay>();
}
}
void OnDestroy()
{
ScoreManager.onScoreChanged -= UpdateSoulCount;
}
void Update()
{
UpdateLifeIcons();
UpdateSkillCooldowns();
}
/// <summary>
/// 更新魂灵计数(左上角)。
/// </summary>
private void UpdateSoulCount(int count)
{
if (soulCountText != null)
soulCountText.text = count.ToString();
}
/// <summary>
/// 更新生命图标(左下角)。
/// 根据当前血量显示/隐藏对应图标。
/// </summary>
private void UpdateLifeIcons()
{
if (_playerHealth == null || lifeIcons == null || lifeIcons.Length == 0) return;
// 获取当前血量
var healthField = typeof(HealthSystem).GetField("health",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
int currentHealth = healthField != null ? (int)healthField.GetValue(_playerHealth) : _maxHealth;
for (int i = 0; i < lifeIcons.Length; i++)
{
if (lifeIcons[i] != null)
lifeIcons[i].enabled = (i < currentHealth);
}
}
/// <summary>
/// 更新技能CD遮罩(右下角)。
/// 使用 Image.fillAmount 实现圆形CD效果。
/// </summary>
private void UpdateSkillCooldowns()
{
// 冲刺 CD(从 PlayerController 读取 rollCooldown + lastRollTime
if (_playerController != null)
{
var cdField = typeof(PlayerController).GetField("rollCooldown",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var lastField = typeof(PlayerController).GetField("lastRollTime",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
float sprintCD = cdField != null ? (float)cdField.GetValue(_playerController) : 1f;
float lastRoll = lastField != null ? (float)lastField.GetValue(_playerController) : -999f;
float remaining = Mathf.Max(0f, (lastRoll + sprintCD) - Time.time);
UpdateSkillCD(skillSprintCD, remaining, sprintCD);
}
// 摇铃 CD(从 EchoSystem 读取 cooldown + _lastEchoTime
if (_echoSystem != null)
{
var cdField = typeof(EchoSystem).GetField("cooldown",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
var lastField = typeof(EchoSystem).GetField("_lastEchoTime",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
float bellCD = cdField != null ? (float)cdField.GetValue(_echoSystem) : 2f;
float lastTime = lastField != null ? (float)lastField.GetValue(_echoSystem) : -999f;
float remaining = Mathf.Max(0f, (lastTime + bellCD) - Time.time);
UpdateSkillCD(skillBellCD, remaining, bellCD);
}
// 灵灯 CD(从 SpiritLanternSystem 读取)
if (_lanternSystem != null)
{
float remaining = _lanternSystem.CooldownRemaining;
var cdField = typeof(SpiritLanternSystem).GetField("cooldown",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
float maxCD = cdField != null ? (float)cdField.GetValue(_lanternSystem) : 3f;
UpdateSkillCD(skillLanternCD, remaining, maxCD);
}
}
/// <summary>
/// 更新单个技能CD遮罩。
/// fillAmount = 1 表示CD中(完全遮挡),0 表示就绪(无遮挡)。
/// </summary>
private void UpdateSkillCD(Image cdImage, float remaining, float total)
{
if (cdImage == null) return;
if (total <= 0f || remaining <= 0f)
{
cdImage.fillAmount = 0f;
cdImage.gameObject.SetActive(false);
}
else
{
cdImage.gameObject.SetActive(true);
cdImage.fillAmount = remaining / total;
}
}
private void OnPauseClick()
{
if (TimeController.Instance != null)
TimeController.Instance.Pause();
}
}
}