Part of these game systems:
Health Bar UI
World-space or screen-space health bar with smooth fill, color gradient, and damage flash. Attach to enemies or use as HUD.
How to Use
1
Create a Canvas (World Space for enemies, Overlay for HUD)
2
Add a background Image and a child fill Image (set fill type to Horizontal)
3
Attach HealthBarUI, assign both images
4
Connect to HealthSystem: OnHealthChanged.AddListener(healthBar.SetHealth)
5
Enable Billboard for world-space bars to face camera
6
Customize the color gradient (red→yellow→green by default)
Source Code
C#
using UnityEngine;
using UnityEngine.UI;
/// <summary>
/// Health bar UI with smooth fill animation and color gradient.
/// Works as world-space (enemy) or overlay (HUD) health bar.
/// </summary>
public class HealthBarUI : MonoBehaviour
{
[Header("References")]
[SerializeField] private Image fillImage;
[SerializeField] private Image backgroundImage;
[Header("Fill Settings")]
[SerializeField] private float smoothSpeed = 5f;
[SerializeField] private Gradient colorGradient;
[Header("Damage Flash")]
[SerializeField] private bool enableDamageFlash = true;
[SerializeField] private Color flashColor = new Color(1f, 1f, 1f, 0.6f);
[SerializeField] private float flashDuration = 0.15f;
[Header("Billboard (World Space Only)")]
[SerializeField] private bool billboardToCamera = true;
private float targetFill = 1f;
private float currentFill = 1f;
private float flashTimer;
private Color originalBgColor;
private void Awake()
{
if (backgroundImage != null)
originalBgColor = backgroundImage.color;
// Set default gradient if none assigned
if (colorGradient.colorKeys.Length <= 1)
{
GradientColorKey[] keys = new GradientColorKey[3];
keys[0] = new GradientColorKey(new Color(0.9f, 0.2f, 0.2f), 0f); // Red at low
keys[1] = new GradientColorKey(new Color(0.9f, 0.7f, 0.1f), 0.5f); // Yellow at mid
keys[2] = new GradientColorKey(new Color(0.2f, 0.9f, 0.3f), 1f); // Green at full
GradientAlphaKey[] alpha = new GradientAlphaKey[2];
alpha[0] = new GradientAlphaKey(1f, 0f);
alpha[1] = new GradientAlphaKey(1f, 1f);
colorGradient.SetKeys(keys, alpha);
}
}
private void Update()
{
// Smooth fill
currentFill = Mathf.Lerp(currentFill, targetFill, Time.deltaTime * smoothSpeed);
if (fillImage != null)
{
fillImage.fillAmount = currentFill;
fillImage.color = colorGradient.Evaluate(currentFill);
}
// Damage flash
if (flashTimer > 0f)
{
flashTimer -= Time.deltaTime;
if (flashTimer <= 0f && backgroundImage != null)
backgroundImage.color = originalBgColor;
}
}
private void LateUpdate()
{
// Billboard: face camera
if (billboardToCamera && Camera.main != null)
transform.forward = Camera.main.transform.forward;
}
/// <summary>
/// Update the health bar. Call this from HealthSystem.OnHealthChanged.
/// </summary>
public void SetHealth(float current, float max)
{
float previous = targetFill;
targetFill = Mathf.Clamp01(current / max);
// Flash on damage
if (enableDamageFlash && targetFill < previous && backgroundImage != null)
{
backgroundImage.color = flashColor;
flashTimer = flashDuration;
}
}
/// <summary>
/// Set fill instantly without smoothing.
/// </summary>
public void SetHealthImmediate(float current, float max)
{
targetFill = Mathf.Clamp01(current / max);
currentFill = targetFill;
if (fillImage != null)
{
fillImage.fillAmount = currentFill;
fillImage.color = colorGradient.Evaluate(currentFill);
}
}
}