Files
2026-07-07 03:34:56 +08:00

95 lines
3.6 KiB
C#
Raw Permalink 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 IndianOceanAssets.Engine2_5D;
namespace IndianOceanAssets.Engine2_5D
{
/// <summary>
/// 敌人头顶血条 —— 挂在敌人 Prefab 上。
/// 血条可视化物体(BG、Fill)已在 Prefab 中预建,运行时直接引用,无需动态创建。
///
/// 解耦改造:直接引用同物体上的 HealthSystemRequireComponent 保证存在),
/// 订阅其 OnHealthChanged 事件刷新,彻底移除对私有字段的反射读取。
/// 注意:不使用"全局共享 IntVariable"承载敌人血量——否则所有敌人血条会显示同一份血量,
/// 正确的解法是"每个敌人读自己的 HealthSystem"(同物体组件引用,非 Find / 反射 / 跨对象)。
/// </summary>
[RequireComponent(typeof(HealthSystem))]
public class EnemyHealthBar : MonoBehaviour
{
[Header("血条引用(Prefab 中预建)")]
[SerializeField] private Transform barRoot;
[SerializeField] private SpriteRenderer bgRenderer;
[SerializeField] private SpriteRenderer fillRenderer;
[Header("血条参数")]
[Tooltip("血条宽度(世界单位)")]
[SerializeField] private float barWidth = 1f;
[Tooltip("血条高度(世界单位)")]
[SerializeField] private float barHeight = 0.1f;
[Header("颜色")]
[SerializeField] private Color fillColor = new Color(0.8f, 0.1f, 0.1f, 0.9f);
[SerializeField] private Color lowHealthColor = new Color(1f, 0.3f, 0f, 0.9f);
[Tooltip("低于此比例时切换为低血量颜色")]
[SerializeField] private float lowHealthThreshold = 0.3f;
[Header("显示控制")]
[Tooltip("满血时是否隐藏血条")]
[SerializeField] private bool hideWhenFull = false;
// 同物体上的 HealthSystemRequireComponent 保证存在;非 Find / 反射 / 跨对象引用)
private HealthSystem _healthSource;
private void Start()
{
if (fillRenderer == null || bgRenderer == null)
{
enabled = false;
return;
}
_healthSource = GetComponent<HealthSystem>();
if (_healthSource != null)
{
_healthSource.OnHealthChanged += UpdateBar;
UpdateBar(_healthSource.CurrentHealth, _healthSource.MaxHealth);
}
else
{
UpdateBar(1, 1);
}
}
private void OnDestroy()
{
if (_healthSource != null)
_healthSource.OnHealthChanged -= UpdateBar;
}
/// <summary>
/// 根据当前血量更新血条显示(事件驱动,无反射、无每帧 LateUpdate)。
/// </summary>
private void UpdateBar(int currentHealth, int maxHealth)
{
if (fillRenderer == null || bgRenderer == null) return;
if (maxHealth <= 0) maxHealth = 1;
float ratio = Mathf.Clamp01((float)currentHealth / maxHealth);
// 更新填充条缩放(居中对齐)
fillRenderer.transform.localScale = new Vector3(barWidth * ratio, barHeight, 1f);
fillRenderer.transform.localPosition = new Vector3(
-(barWidth * (1f - ratio)) * 0.5f, 0f, 0f);
// 低血量变色
fillRenderer.color = ratio <= lowHealthThreshold ? lowHealthColor : fillColor;
// 满血隐藏
bool visible = !(hideWhenFull && ratio >= 1f);
bgRenderer.enabled = visible;
fillRenderer.enabled = visible;
}
}
}