Enemy Stat Display - UQcsse3200/2026-studio-4 GitHub Wiki
EnemyStatDisplay
Current implementation: checked against
mainat 78c7cd4 on 21 October 2026. Values below are defaults before room difficulty scaling unless stated otherwise.
EnemyStatDisplay is a UIComponent that renders a floating health bar above an enemy entity's head. It tracks the enemy as it moves through the world (converting world-space coordinates into screen-space via the registered world camera) and updates in real time as the enemy takes damage, heals, or has its max health changed.
Package: com.csse3200.game.components.npc
What it does
- Creates a small
ProgressBar(styledenemy-health-barfrom the HUD skin) inside aTable, added directly to the UIStage. - Every frame, repositions itself above the owning entity by projecting the entity's world position through the registered world camera into screen coordinates.
- Listens for combat and visibility events on its own entity and updates the bar/table accordingly.
- Supports a per-instance visual scale, so different enemy tiers (mini enemy, normal enemy, boss) can render at different sizes without needing separate component classes.
Usage
Adding it to an enemy
Attach EnemyStatDisplay alongside CombatStatsComponent when building the enemy entity in a factory (e.g. NPCFactory):
Entity enemy =
new Entity()
.addComponent(new CombatStatsComponent(health, baseAttack))
.addComponent(new PhysicsComponent())
.addComponent(new PhysicsMovementComponent())
.addComponent(new EnemyStatDisplay(scale));
CombatStatsComponent must be on the same entity. EnemyStatDisplay.create() reads getMaxHealth()/getHealth() from it immediately to initialise the bar, and will throw a NullPointerException at creation time if it's missing.
Choosing a scale
EnemyStatDisplay has two constructors:
new EnemyStatDisplay(); // defaults to scale 1.5f
new EnemyStatDisplay(2.5f); // explicit scale
Recommended scale by enemy tier:
| Enemy tier | Scale |
|---|---|
| Mini enemy (spawned alongside a boss) | 1f |
| Normal enemy | 1.5f |
| Boss enemy | 3f |
Scale is applied via Table.setTransform(true) + Table.setScale(scale) on the internal table, so it visually enlarges the whole bar without needing separate larger atlas art per tier.
Difficulty scaling and boss visibility
Room scaling changes both current and maximum health before publishing updateMaxHealth, followed by updateHealth. The bar therefore starts full at the scaled maximum. This also prevents half-health phase listeners from observing a new maximum paired with an old current value during scaling.
The Snake explicitly toggles enemyHealthBarVisible during burrowing and emergence. This event controls display visibility; it does not itself apply invulnerability. Enemy death/disposal removes the UI table so it cannot remain on screen after the entity is gone.
Testing
Automated (JUnit)
EnemyStatDisplayTest (package com.csse3200.game.components.npc) covers:
- Health bar initialises correctly from
CombatStatsComponent's starting health/max health. "updateHealth"/"updateMaxHealth"events correctly update the bar's value/range."enemyHealthBarVisible"toggles the table's visibility.- Custom scale passed via the constructor is applied to the table.
updateHealthBar(...)'s three branches: no table (early return), table present but no world camera registered (early return), and the full happy path with a real camera registered (position actually computed).dispose()'s both branches: table never created, and table present and removed.- Component creation doesn't throw when no
Stageis available (headless/test environment). Widget state (the privatehealthBar/tablefields) is read back via reflection in tests, since the component intentionally exposes no public getters for its internal actors.
Manual
- Start the game and enter any dungeon room containing enemies.
- Confirm a health bar appears above each enemy's head, correctly centred and sized according to its tier (mini/normal/boss).
- Move around the room and confirm each bar continues to track its enemy smoothly as both the enemy and the camera move.
- Deal damage to an enemy and confirm its bar updates immediately to reflect the new health value.
- If any mechanic changes an enemy's max health mid-fight, confirm the bar's range updates and the fill percentage recalculates correctly rather than just clamping visually.
- If a concealment/stealth or cutscene mechanic exists that should hide enemy health bars, trigger it and confirm bars disappear/reappear correctly via the
enemyHealthBarVisibleevent.
Related
CombatStatsComponent—> source of the health/max-health values and theupdateHealth/updateMaxHealthevents this component listens for.CameraComponent—> registers the world camera viaServiceLocator.registerWorldCamera(...), required for correct positioning.PlayerStatsDisplay—> the player-facing equivalent HUD element (fixed screen-corner panel rather than a floating world-tracked bar).UIComponent—> base class providing the sharedhud/skinandstagefields.
Current sources: EnemyStatDisplay.java, EnemyStatDisplayTest.java, CombatStatsComponent.java. See also the Team 1 Test Plan.