更新game HUD 界面

This commit is contained in:
2026-07-04 12:15:13 +08:00
parent 58d1f54e0d
commit 0b6dc2653f
21 changed files with 5347 additions and 597 deletions
+101 -60
View File
@@ -1,124 +1,165 @@
using UnityEngine;
using UnityEngine.UI;
using IndianOceanAssets.Engine2_5D;
using GameFramework;
namespace GameFramework
{
/// <summary>
/// 游戏内 HUD —— 显示血量、灵灯数量/CD、分数、暂停按钮
/// 挂在 Gameplay 场景的 HUD Canvas 上。
/// 游戏内 HUD —— 魂灵计数 + 生命图标 + 技能CD
///
/// 布局:
/// - 左上角:收集到的魂灵(icon + 数字)
/// - 左下角:5个生命图标
/// - 右下角:3个技能图标(冲刺/摇铃/灵灯)+ CD遮罩
/// </summary>
public class GameHUD : MonoBehaviour
{
[Header("血量")]
[SerializeField] private Slider healthSlider;
[SerializeField] private Text healthText;
[Header("魂灵计数(左上角)")]
[SerializeField] private Image soulIcon;
[SerializeField] private Text soulCountText;
[Header("灵灯")]
[SerializeField] private Text lanternCountText;
[SerializeField] private Text lanternCDText;
[SerializeField] private Image lanternCDFill; // 可选:CD 圆形填充
[Header("生命图标(左下角)")]
[SerializeField] private Image[] lifeIcons; // 5个生命图标
[Header("分数")]
[SerializeField] private Text scoreText;
[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 int _maxHealth;
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>();
// 获取 maxHealth
if (_playerHealth != null)
{
var field = typeof(HealthSystem).GetField("maxHealth",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (field != null)
_maxHealth = (int)field.GetValue(_playerHealth);
else
_maxHealth = 100;
}
_echoSystem = player.GetComponent<EchoSystem>();
_playerController = player.GetComponent<PlayerController>();
}
// 绑定暂停按钮
if (pauseButton != null)
pauseButton.onClick.AddListener(OnPauseClick);
// 订阅分数事件
ScoreManager.onScoreChanged += UpdateScore;
// 订阅分数事件(魂灵计数复用分数系统)
ScoreManager.onScoreChanged += UpdateSoulCount;
UpdateSoulCount(ScoreManager.Instance != null ? ScoreManager.Instance.CurrentScore : 0);
// 初始更新
UpdateScore(ScoreManager.Instance != null ? ScoreManager.Instance.CurrentScore : 0);
UpdateLifeIcons();
}
void OnDestroy()
{
ScoreManager.onScoreChanged -= UpdateScore;
ScoreManager.onScoreChanged -= UpdateSoulCount;
}
void Update()
{
UpdateHealth();
UpdateLantern();
UpdateLifeIcons();
UpdateSkillCooldowns();
}
private void UpdateHealth()
/// <summary>
/// 更新魂灵计数(左上角)。
/// </summary>
private void UpdateSoulCount(int count)
{
if (_playerHealth == null) return;
if (soulCountText != null)
soulCountText.text = count.ToString();
}
/// <summary>
/// 更新生命图标(左下角)。
/// 根据当前血量显示/隐藏对应图标。
/// </summary>
private void UpdateLifeIcons()
{
if (_playerHealth == null || lifeIcons == null || lifeIcons.Length == 0) return;
// 获取当前血量
var field = typeof(HealthSystem).GetField("health",
var healthField = typeof(HealthSystem).GetField("health",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
int currentHealth = field != null ? (int)field.GetValue(_playerHealth) : _maxHealth;
int currentHealth = healthField != null ? (int)healthField.GetValue(_playerHealth) : _maxHealth;
if (healthSlider != null)
healthSlider.value = (float)currentHealth / _maxHealth;
if (healthText != null)
healthText.text = $"{currentHealth}/{_maxHealth}";
for (int i = 0; i < lifeIcons.Length; i++)
{
if (lifeIcons[i] != null)
lifeIcons[i].enabled = (i < currentHealth);
}
}
private void UpdateLantern()
/// <summary>
/// 更新技能CD遮罩(右下角)。
/// 使用 Image.fillAmount 实现圆形CD效果。
/// </summary>
private void UpdateSkillCooldowns()
{
if (_lanternSystem == null) return;
if (lanternCountText != null)
lanternCountText.text = $"灵灯: {_lanternSystem.RemainingLanterns}";
if (lanternCDText != null)
// 冲刺 CD(从 PlayerController 读取 rollCooldown + lastRollTime
if (_playerController != null)
{
if (_lanternSystem.IsCooldownReady)
lanternCDText.text = "就绪";
else
lanternCDText.text = $"{_lanternSystem.CooldownRemaining:F1}s";
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);
}
if (lanternCDFill != null)
// 摇铃 CD(从 EchoSystem 读取 cooldown + _lastEchoTime
if (_echoSystem != null)
{
// CD 填充:就绪时满,冷却中递减
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;
lanternCDFill.fillAmount = _lanternSystem.IsCooldownReady ? 1f :
1f - (_lanternSystem.CooldownRemaining / maxCD);
UpdateSkillCD(skillLanternCD, remaining, maxCD);
}
}
private void UpdateScore(int score)
/// <summary>
/// 更新单个技能CD遮罩。
/// fillAmount = 1 表示CD中(完全遮挡),0 表示就绪(无遮挡)。
/// </summary>
private void UpdateSkillCD(Image cdImage, float remaining, float total)
{
if (scoreText != null)
scoreText.text = $"分数: {score}";
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()