AppleyAppley Docs
Docs/API Reference

Health Systems

Build robust health, damage, and death systems with regeneration.

26 min read Intermediate Updated 2026-07-01 v2.0 ~91 min to complete

Introduction

Health systems are fundamental to most games. This guide covers health management, damage types, regeneration, shields, and death handling with event-driven architecture.

Guide 15 of 25

This is part of the Intermediate Guides collection. Category: Gameplay Systems. Estimated completion: 91 minutes. Difficulty: Intermediate.

Screenshot

Health Systems
Health Systems

Step-by-Step Guide

1

Create a health component

Add health properties: currentHealth, maxHealth, shield, invulnerability timer.

2

Implement damage types

Define damage types (normal, fire, poison, fall, drowning) with different resistances and effects.

3

Add health regeneration

Regenerate health after 5 seconds without damage. Use a regen rate (5 HP/sec), cancel on hit.

4

Implement shields

Shields absorb damage before health. Shields regenerate faster but delay before regenerating (3s).

5

Handle death

On health reaching 0, trigger death event, play animation, disable input, invoke respawn.

6

Use events for damage

Emit tookDamage events with amount and type. UI, effects, and audio subscribe.

FluxScript Example

Here is a complete FluxScript implementation for this guide:

Health Systems — FluxScript
on start {
  player.maxHealth = 100
  player.health = 100
  player.maxShield = 50
  player.shield = 50
  player.invulnerable = false
  player.invulnTimer = 0
  player.regenDelay = 0
  player.isDead = false
}

on update(dt) {
  if player.isDead return
  if player.invulnTimer > 0 {
    player.invulnTimer -= dt
    if player.invulnTimer <= 0 player.invulnerable = false
  }
  if player.regenDelay > 0 {
    player.regenDelay -= dt
  } else if player.health < player.maxHealth {
    player.health = math.min(player.health + 5 * dt, player.maxHealth)
    emit("healthChanged", { health: player.health })
  }
}

func takeDamage(target, amount, type) {
  if target.invulnerable || target.isDead return
  resistance = target.getResistance(type)
  actualDamage = amount * (1 - resistance)
  if target.shield > 0 {
    shieldDamage = math.min(target.shield, actualDamage)
    target.shield -= shieldDamage
    actualDamage -= shieldDamage
  }
  if actualDamage > 0 {
    target.health -= actualDamage
    target.regenDelay = 5.0
    emit("tookDamage", { target: target, amount: actualDamage, type: type })
    ui.flash("damage", 0.3)
  }
  if target.health <= 0 {
    target.health = 0
    target.isDead = true
    emit("playerDied", { target: target })
  }
}

Node Graph Example

Prefer visual programming? Here is the equivalent Node Graph:

Health Systems — Node Graph
[On Update] --> [Branch: !isDead]
   --> [Update: invulnTimer]
   --> [Branch: regenDelay > 0]
        +-- True --> [Countdown]
        +-- False --> [Regen: +5*dt] --> [Emit: healthChanged]

[Function: takeDamage] --> [Check: invulnerable/isDead]
   --> [Apply: resistance] --> [Shield absorbs first]
   --> [Remaining -> health] --> [Emit: tookDamage]
   --> [Branch: health <= 0] --> [Emit: playerDied]

Optimization Tips

Keep your implementation fast and efficient with these optimization tips:

  • Use events for damage communication. Emit tookDamage events — UI, effects, and audio subscribe decoupled.
  • Clamp health between 0 and maxHealth. Negative or excess health causes UI bugs and death check failures.
  • Use damage type resistances. Creates varied gameplay (fire armor, poison immunity) without complex logic.
  • Separate shield and health regen timings. Shields regen faster (15/s after 3s), health slower (5/s after 5s).

Common Mistakes

Directly modifying health from multiple sources

Use a centralized takeDamage() function. Direct modifications bypass resistances and death checks.

No invulnerability frames after damage

Add 0.5-1s invulnerability after a hit. Without it, rapid-fire enemies drain health instantly.