/ #mechanics 

Health

The health mechanic is a staple of many games because so many of them involve combat, death and destruction.

It’s a very simple mechanic, probably born from the earliest Dungeon & Dragons pen-and-paper roleplaying games.

Characters in the game have hit points which are an abstraction of how healthy they are - once their hit points reach zero they die (or fall unconscious in some variants).

Typically the hit points variable is also paired with a maximum hit points variable to facilitate healing mechanics in addition to damage mechanics.

This screenshot from Dota Underlords shows health bars above the heads of the hero and monsters in green and red respectively:

Dota Underlords was made in 2019 and it has the health mechanic.

ECS Design

Components

Health

  • current: Integer
  • maximum: Integer

Usually these are initialized to have current == maximum.

Damage

  • amount: Integer

Healing

  • amount: Integer

Entities

Each entity in the game that can die or be destroyed will have a Health component.

Other systems like the combat or spell casting systems will be responsible for creating Damage or Healing components on an entity to indicate that it has been damaged or healed.

Systems

HealthSystem

This system is responsible for applying damage and healing to Health. This is a simplified design that has damage and healing unified into a single system because they are very simple inverse operatiokns. If you have a game where they function less similarly it might make sense to split them into separate systems.

damaged = world.get_entities_with_components(Health, Damage)

for entity in damaged:
    entity.health.current -= entity.damage.amount

    world.remove_component(entity, entity.damage)

healed = world.get_entities_with_components(Health, Healing)
for entity in healed:
    if entity.health.current > 0:  # Can't heal the dead...
        entity.health.current = min(entity.health.maximum, entity.health.current + healing.amount)
    
    world.remove_component(entity, entity.healing)

DeathSystem

This system is responsible for removing dead entities from the game and is usually also responsible for enacting any game specific consequences for the entity dying or being destroyed. This system could potentially be rolled into the HealthSystem for simple games but games will often differentiate themselves in terms of what happens when something dies, so it probably makes sense to keep it separate as this will get much more complex than in my example.

living = world.get_entities_with_components(Health)

for entity in living:
    if entity.health.current <= 0:
        death_message(entity)

        world.remove_entity(entity)

Notes:

  • Perhaps a better way to do this would be to have the HealthSystem remove Health and add a Dead component, then this system could simply look for Dead entities which would save looping over all the living… This could also be handy if for example you want to have a death animation that should play for a while before actually removing the dead entity.
Author

Matt Van Der Westhuizen

Back-end service developer at Ubisoft Blue Byte by day - wannabe game designer & developer by night.