Health System
Reusable health component with damage, healing, invincibility frames, and events.
How to Use
Attach to any GameObject that needs health (player, enemies, destructibles)
Configure max health and invincibility duration
Hook up events in the inspector or via code
Call TakeDamage() and Heal() from other scripts
Features
- Damage and healing with clamped health values
- Invincibility frames with configurable duration after taking damage
- UnityEvent callbacks for health changed, damaged, healed, and death
- Public properties for HealthPercent, IsAlive, and IsInvincible checks
- SetMaxHealth with optional heal-to-full for level-up scenarios
- ResetHealth method for respawn or checkpoint restoration
When to Use This
Essential for virtually any game with damageable entities — platformers, shooters, RPGs, tower defense, and survival games. Use this on players, enemies, destructible objects, or even bosses. It is the universal building block that other combat scripts (damage popups, health bars, weapon systems) connect to via events.
Common Mistakes
Calling TakeDamage() with a negative value does nothing because the script guards against it — use Heal() instead. If OnDeath doesn't seem to fire, check that invincibilityDuration isn't set too high, preventing subsequent hits from registering. Remember that events set in the Inspector are per-instance, so prefab overrides may not carry your event wiring to spawned copies.
Source Code
using UnityEngine;
using UnityEngine.Events;
public class HealthSystem : MonoBehaviour
{
[Header("Health")]
[SerializeField] private float maxHealth = 100f;
[SerializeField] private float currentHealth;
[Header("Invincibility")]
[SerializeField] private float invincibilityDuration = 0.5f;
private float invincibilityTimer;
[Header("Events")]
public UnityEvent<float, float> OnHealthChanged; // current, max
public UnityEvent OnDeath;
public UnityEvent OnDamaged;
public UnityEvent OnHealed;
public float CurrentHealth => currentHealth;
public float MaxHealth => maxHealth;
public float HealthPercent => currentHealth / maxHealth;
public bool IsAlive => currentHealth > 0f;
public bool IsInvincible => invincibilityTimer > 0f;
private void Awake()
{
currentHealth = maxHealth;
}
private void Update()
{
if (invincibilityTimer > 0f)
invincibilityTimer -= Time.deltaTime;
}
public void TakeDamage(float damage)
{
if (!IsAlive || IsInvincible || damage <= 0f) return;
currentHealth = Mathf.Max(0f, currentHealth - damage);
invincibilityTimer = invincibilityDuration;
OnHealthChanged?.Invoke(currentHealth, maxHealth);
OnDamaged?.Invoke();
if (!IsAlive)
OnDeath?.Invoke();
}
public void Heal(float amount)
{
if (!IsAlive || amount <= 0f) return;
currentHealth = Mathf.Min(maxHealth, currentHealth + amount);
OnHealthChanged?.Invoke(currentHealth, maxHealth);
OnHealed?.Invoke();
}
public void SetMaxHealth(float newMax, bool healToFull = false)
{
maxHealth = newMax;
if (healToFull)
currentHealth = maxHealth;
else
currentHealth = Mathf.Min(currentHealth, maxHealth);
OnHealthChanged?.Invoke(currentHealth, maxHealth);
}
public void ResetHealth()
{
currentHealth = maxHealth;
invincibilityTimer = 0f;
OnHealthChanged?.Invoke(currentHealth, maxHealth);
}
}