161 lines
4.5 KiB
C#
161 lines
4.5 KiB
C#
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
|
|
// Screen-space HP bar for the player HUD.
|
|
// Enemy HP bars can keep using the SpriteRenderer-based HpBar.
|
|
public class PlayerHpBarUI : MonoBehaviour
|
|
{
|
|
[SerializeField] private Health _health;
|
|
[SerializeField] private Image _fillImage;
|
|
[SerializeField] private bool _autoFindPlayerHealth = true;
|
|
[SerializeField] private bool _autoFindFillImageInChildren = true;
|
|
[SerializeField] private bool _configureAsFilledImage = true;
|
|
[SerializeField] private float _smoothSpeed = 0f;
|
|
|
|
[Header("Color Thresholds")]
|
|
[SerializeField] private Color _highColor = new Color(0.2f, 0.9f, 0.3f, 1f);
|
|
[SerializeField] private Color _midColor = new Color(1f, 0.85f, 0.2f, 1f);
|
|
[SerializeField] private Color _lowColor = new Color(0.95f, 0.25f, 0.25f, 1f);
|
|
[SerializeField, Range(0f, 1f)] private float _midThreshold = 0.5f;
|
|
[SerializeField, Range(0f, 1f)] private float _lowThreshold = 0.2f;
|
|
|
|
private float _currentRatio = 1f;
|
|
private float _targetRatio = 1f;
|
|
|
|
private void Awake()
|
|
{
|
|
ResolveFillImage();
|
|
ResolveHealth();
|
|
ConfigureFillImage();
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
ResolveFillImage();
|
|
ResolveHealth();
|
|
ConfigureFillImage();
|
|
|
|
if (_health == null) return;
|
|
|
|
_health.OnHealthChanged += HandleHealthChanged;
|
|
HandleHealthChanged(_health.CurrentHealth, _health.MaxHealth);
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
if (_health != null)
|
|
_health.OnHealthChanged -= HandleHealthChanged;
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
ResolveFillImage();
|
|
ResolveHealth();
|
|
ConfigureFillImage();
|
|
|
|
if (_health != null)
|
|
HandleHealthChanged(_health.CurrentHealth, _health.MaxHealth);
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (_fillImage == null || _smoothSpeed <= 0f) return;
|
|
if (Mathf.Approximately(_currentRatio, _targetRatio)) return;
|
|
|
|
_currentRatio = Mathf.MoveTowards(_currentRatio, _targetRatio, _smoothSpeed * Time.deltaTime);
|
|
ApplyFill();
|
|
}
|
|
|
|
public void Bind(Health health)
|
|
{
|
|
if (_health == health) return;
|
|
|
|
if (isActiveAndEnabled && _health != null)
|
|
_health.OnHealthChanged -= HandleHealthChanged;
|
|
|
|
_health = health;
|
|
|
|
if (isActiveAndEnabled && _health != null)
|
|
{
|
|
_health.OnHealthChanged += HandleHealthChanged;
|
|
HandleHealthChanged(_health.CurrentHealth, _health.MaxHealth);
|
|
}
|
|
}
|
|
|
|
private void HandleHealthChanged(int current, int max)
|
|
{
|
|
_targetRatio = max > 0 ? Mathf.Clamp01((float)current / max) : 0f;
|
|
|
|
if (_smoothSpeed <= 0f)
|
|
{
|
|
_currentRatio = _targetRatio;
|
|
ApplyFill();
|
|
}
|
|
|
|
ApplyColor(_targetRatio);
|
|
}
|
|
|
|
private void ApplyFill()
|
|
{
|
|
if (_fillImage == null) return;
|
|
_fillImage.fillAmount = Mathf.Clamp01(_currentRatio);
|
|
}
|
|
|
|
private void ApplyColor(float ratio)
|
|
{
|
|
if (_fillImage == null) return;
|
|
|
|
if (ratio <= _lowThreshold)
|
|
_fillImage.color = _lowColor;
|
|
else if (ratio <= _midThreshold)
|
|
_fillImage.color = _midColor;
|
|
else
|
|
_fillImage.color = _highColor;
|
|
}
|
|
|
|
private void ResolveHealth()
|
|
{
|
|
if (_health != null || !_autoFindPlayerHealth) return;
|
|
|
|
PlayerController player = FindFirstObjectByType<PlayerController>();
|
|
if (player != null)
|
|
_health = player.GetComponent<Health>();
|
|
}
|
|
|
|
private void ResolveFillImage()
|
|
{
|
|
if (_fillImage != null || !_autoFindFillImageInChildren) return;
|
|
|
|
Transform fill = FindChildByName(transform, "Fill");
|
|
if (fill != null)
|
|
_fillImage = fill.GetComponent<Image>();
|
|
}
|
|
|
|
private Transform FindChildByName(Transform parent, string childName)
|
|
{
|
|
if (parent == null) return null;
|
|
|
|
for (int i = 0; i < parent.childCount; i++)
|
|
{
|
|
Transform child = parent.GetChild(i);
|
|
if (child.name == childName)
|
|
return child;
|
|
|
|
Transform nested = FindChildByName(child, childName);
|
|
if (nested != null)
|
|
return nested;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private void ConfigureFillImage()
|
|
{
|
|
if (_fillImage == null || !_configureAsFilledImage) return;
|
|
|
|
_fillImage.type = Image.Type.Filled;
|
|
_fillImage.fillMethod = Image.FillMethod.Horizontal;
|
|
_fillImage.fillOrigin = (int)Image.OriginHorizontal.Left;
|
|
}
|
|
}
|