Player Health and Damage - UQcsse3200/2026-studio-2 GitHub Wiki
Player Health and Damage
Introduction
The Player Health and Damage System controls health changes, the invulnerability window after a hit, and the transition from player death to the loss screen. It separates combat rules from hitbox detection, animation and HUD presentation.
Reviewed 15 September 2026 against main 4941dba, which merged PR #145. The player mechanics described below are merged unless explicitly labelled as branch-specific.
Architecture
flowchart LR
Damage["Damage source"] -->|takeDamage| Stats["CombatStatsComponent"]
Stats -->|updateHealth| HUD["PlayerStatsDisplay"]
Stats -->|hurt / death| Animation["PlayerAnimationController"]
Stats -->|death| Actions["Input and PlayerActions"]
Animation -->|deathAnimationFinished| Screen["Game screen"]
Screen -->|gameEnd LOSE| End["Game-end UI"]
CombatStatsComponent
Stores current/max health, attack damage and the invulnerability deadline. It receives damage events and publishes health, hurt and death events.
Collider, Hitbox and HUD
The physical ColliderComponent handles solid contact. The separate HitboxComponent creates a sensor fixture on PhysicsLayer.PLAYER for combat interactions. Changing the ordinary collider’s scale does not also resize that separate sensor via the collider helper.
The player’s rendered/entity width is scaled to 0.6 world units. The merged factory uses collider scale 1 × 1 with density 1.5.
The Player HUD listens to health updates and displays two HP per heart using rounding up: 10 HP shows five hearts and 9 HP still shows five. HUD artwork/display belongs to the UI collaboration; Team 5’s health system supplies the integration events. See inventory documentation for potion items; item use refuses a full-health potion and otherwise heals within the maximum.
Death Presentation
PlayerAnimationController handles the death clip; screen listeners handle removal and the loss screen. The combat component does not construct UI.
Damage and Death Lifecycle
Damage and Invulnerability
The combat component listens for takeDamage with the attacker’s combat stats. An accepted hit(...) subtracts base attack, clamps health to the entity’s own maximum/minimum, and advances the invulnerability deadline.
updateHealthnotifies dependent systems when health is set.hurtis emitted when an accepted hit actually reduces health.deathis emitted when health changes from positive to zero; setting zero again does not repeat that transition.- Hits before the invulnerability deadline are ignored; a hit exactly at expiry is accepted.
On a lethal hit, death occurs during the health update before hurt; the animation controller’s dead guard prevents the later hurt event replacing the death clip.
Invulnerability is damage filtering, not collision immunity or an implemented flashing effect. Contact knockback is handled separately and is not automatically suppressed by i-frames. Direct setHealth/addHealth operations bypass the hit timer; an accepted zero-damage hit still advances it.
Player Death
- Health crosses from positive to zero and emits
death. - Keyboard input rejects further player actions;
PlayerActionsstops walking and clears queued jumping. - The animation controller plays the one-shot death animation.
- On completion, it emits
deathAnimationFinishedonce. - Main/tutorial screen listeners schedule player removal and post
gameEndwith the loss state.
This describes input inhibition and the normal animation-to-loss transition, not a guarantee that all physics instantly freezes: vertical velocity is preserved, and the action component has active dash/recovery state. The bow also cancels a charge on death without refunding already-reserved ammunition.
Checkpoint Respawn Is Separate from Death
PlayerFactory also attaches the level team's RespawnComponent. Falling below y = -10 emits respawnAtCheckpoint; the active GameArea repositions the existing player at the last active checkpoint in configuration order, or the default spawn. This path is separate from health reaching zero and completing the loss animation. It does not create a new player or explicitly reset every movement/grapple state.
PR #145 playtesting reported the grapple remaining attached after this repositioning. This is a reviewer-reported issue, not a fix delivered by the regression tests.
Enemy Lifecycle Boundary
The same combat-stat events support damageable enemies, but the bow does not own enemy removal. Team 1’s EnemyDeathComponent listens to updateHealth and schedules removal at zero health. Skeleton factories using it support that lifecycle; legacy NPC factories must be checked separately. Player death waits for the player animation and screen transition rather than using this immediate enemy-removal path.
Tuning
PlayerFactory constructs CombatStatsComponent from configs/player.json:
| Setting | Current value |
|---|---|
| Initial / maximum player health | 10 HP |
| Player base attack (used by melee) | 2 |
| Post-hit invulnerability | 1000 ms |
Projectile damage is configured separately in ProjectileFactory; the player’s base attack of 2 does not mean arrows deal 2 damage. The legacy CombatStatsComponent.MAX_HEALTH = 100 constant is not the player’s configured per-instance maximum.
Testing
Relevant test classes:
CombatStatsComponentTest: clamping, per-instance health limits, direct/event damage, invulnerability and death transitions.PlayerAnimationControllerTest: death playback, selected blocked events and one-time completion.PlayerCombatIntegrationTest: charge cancellation on death alongside the inventory/weapon flow.
RespawnComponentTest covers threshold/event dispatch, not full player-state reset after respawn. Health/animation/combat tests were included in the 503-test run at c900c8d; see Player Attack System for the revision and verification limits.
The original regression-branch playtest reported damage, player loss and skeleton death working. Exact hurt timing, i-frame duration and integrated player state combinations were not independently measured.
Known Limitations
- Movement can interrupt hurt animation; see Animations.
- I-frames filter damage, not knockback, collisions or direct health setters.
- The death transition does not instantly freeze every physical state.
- Exact timing and integrated PR #145 state combinations remain unverified by this review.
Relevant Development Links
- Health ticket #24
- Damage/invulnerability/death ticket #32
- Hitbox ticket #33
- Merged health PR #69
- Reviewed combat-stat source
Contribution Attribution
Rohan Shirkhedkar implemented/integrated player damage, configurable i-frames and health/death hooks. Tristan Sheedy contributed player death animation/input handling and player sizing; Josiah Enns contributed hurt animation. Dhiren Malik contributed projectile-damage integration and combat regressions. UI/HUD work includes Ayooluwa Fadeyibi and the UI team; enemy lifecycle work includes Jordan Conis, Ernie Cheng and Team 1. Checkpoint/respawn and ledge integration belong to the level team. These collaborations are not reassigned wholesale to Team 5.