using UnityEngine;
namespace IndianOceanAssets.Engine2_5D
{
///
/// 敌人头顶血条 —— 挂在敌人 Prefab 上。
/// 血条可视化物体(BG、Fill)已在 Prefab 中预建,
/// 运行时直接引用,无需动态创建。
///
[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;
private HealthSystem _healthSystem;
private int _lastHealth = -1;
private int _maxHealth;
private void Start()
{
_healthSystem = GetComponent();
if (_healthSystem == null)
{
enabled = false;
return;
}
// 获取 maxHealth(通过反射读取私有字段)
var field = typeof(HealthSystem).GetField("maxHealth",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (field != null)
_maxHealth = (int)field.GetValue(_healthSystem);
else
_maxHealth = 3;
UpdateBar();
}
private void LateUpdate()
{
UpdateBar();
}
///
/// 根据当前血量更新血条显示。
///
private void UpdateBar()
{
if (_healthSystem == null || fillRenderer == null || bgRenderer == null) return;
// 获取当前血量(反射)
var healthField = typeof(HealthSystem).GetField("health",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
int currentHealth = healthField != null ? (int)healthField.GetValue(_healthSystem) : _maxHealth;
// 血量没变化则跳过(性能优化)
if (currentHealth == _lastHealth) return;
_lastHealth = currentHealth;
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;
}
}
}