Player HUD Health - UQcsse3200/2026-studio-2 GitHub Wiki
Part of the Player HUD.
Shows the player's health as a row of hearts in the top-left corner, over a health-bar background. Hearts disappear with a flicker animation as the player takes damage, and the row grows automatically when maximum health increases (e.g. an earned extra life).

classDiagram
class UIComponent {
<<abstract>>
}
class PlayerStatsDisplay {
-Table root
-Group heartGroup
-List~Image~ heartImages
-Texture heartTexture
-CombatStatsComponent combatStats
+create()
+updatePlayerHealthUI(int health)
-growHeartsTo(int desiredCount)
-flickerAndHide(Image heart)
}
class CombatStatsComponent {
-int health
-int maxHealth
-int baseAttack
+getHealth() int
+getMaxHealth() int
+setHealth(int)
+addHealth(int)
+addMaxHealth(int)
+hit(CombatStatsComponent attacker)
}
UIComponent <|-- PlayerStatsDisplay
PlayerStatsDisplay --> CombatStatsComponent : reads
CombatStatsComponent ..> PlayerStatsDisplay : "updateHealth" event

-
PlayerStatsDisplayis aUIComponenton the player entity. It owns the heart row (heartImageactors in a positionedGroup, layered over the background with aStackinside the rootTable) and the gold counter (see the hub). -
CombatStatsComponentis the data model. It trackshealthandmaxHealthseparately; health is clamped to[0, maxHealth]. The HUD sizes itself againstmaxHealth.
Each heart is worth HP_PER_HEART (2) health. The number of hearts is derived with ceiling division:
int maximumHearts = Math.max(1, (combatStats.getMaxHealth() + HP_PER_HEART - 1) / HP_PER_HEART);10 HP shows five hearts, 9 HP still shows five, and 8 HP shows four.
updatePlayerHealthUI(int health) runs on every updateHealth event:
-
Grow the heart row (
growHeartsTo) ifmaxHealthhas increased since the last update. This is what makes an earned extra life appear with no separate "add a heart" call. -
Clamp the supplied health and compute the visible heart count with
(cappedHealth + HP_PER_HEART - 1) / HP_PER_HEART. -
Compare each heart's current visibility with what it should be:
- visible, should hide: flicker, then hide;
- hidden, should show: reappear instantly (health restored, new heart earned), no animation;
- no change: left alone. This stops the flicker re-triggering every time the event fires.
The flicker uses libGDX Actions: fade out and in a few times, then hide and reset the colour so the heart can reappear at full opacity.
heart.addAction(
Actions.sequence(
Actions.repeat(FLICKER_COUNT,
Actions.sequence(Actions.fadeOut(FLICKER_DURATION), Actions.fadeIn(FLICKER_DURATION))),
Actions.run(() -> {
heart.setVisible(false);
heart.setColor(1f, 1f, 1f, 1f);
})));| Method | Purpose |
|---|---|
combatStats.getMaxHealth() |
Read the player's current max health |
combatStats.addMaxHealth(amount) |
Increase max health and heal by amount; use this to grant an extra life/heart |
combatStats.addHealth(amount) |
Heal or damage without changing the heart count |
playerStatsDisplay.updatePlayerHealthUI(health) |
Normally driven by the updateHealth event; rarely called directly |
Granting an extra life:
CombatStatsComponent stats = player.getComponent(CombatStatsComponent.class);
stats.addMaxHealth(2); // one more heart's worth of max healthThe updateHealth event fired by addMaxHealth grows the row and shows the new heart as full.
In PlayerStatsDisplay:
| Constant | Value | Purpose |
|---|---|---|
HP_PER_HEART |
2 | Health represented by each visible heart |
FLICKER_COUNT |
3 | Repetitions when hiding a lost heart |
FLICKER_DURATION |
0.1 seconds | Duration of each fade-out/fade-in step |
HEART_SIDE_LENGTH / HEART_SIDE_HEIGHT
|
35px | Size of each heart |
HEART_SPACING |
43.4px | Distance between heart centres |
HEALTH_BAR_WIDTH / HEALTH_BAR_HEIGHT
|
400px / 150px | Size of the health-bar background |
These UI values are separate from player health and i-frame configuration in Player Health and Damage.
- Automated:
PlayerStatsDisplayTest(core/src/test/.../components/player/). - Manual: Health Bar section of the Player HUD Test Plan (HB-1 to HB-4).