Skip to content

Animations

dhirenmalik edited this page Oct 7, 2026 · 10 revisions

Player Animation

Introduction

The Player Animation System selects sprite clips in response to movement, combat and input events. PlayerAnimationController drives AnimationRenderComponent; combat damage stays in the combat components. Death-animation completion also signals the screen to finish the player-loss transition.

This page describes the Sprint 3 player animation implementation in PR #229, together with the regression coverage in PR #196 and bow-charge fixes in PR #211.

Architecture

flowchart LR
    Input["Input / ItemUseComponent"] --> Controller["PlayerAnimationController"]
    Actions["PlayerActions"] --> Controller
    Stats["CombatStatsComponent"] --> Controller
    Controller -->|select clip and facing| Renderer["AnimationRenderComponent"]
    Factory["PlayerFactory / atlas"] -->|register clips| Renderer
    Controller -->|deathAnimationFinished| Screen["Game screen"]
Loading

PlayerAnimationController

The factory registers idle, walk and sprint loops; takeoff, fall and landing clips; hurt and death clips; and a sleep loop. Horizontal movement flips the sprite. The controller resolves ordinary locomotion using:

String desired = moving ? (sprinting ? "sprint" : "walk") : "idle";

The merged factory also registers melee, dash, air_dash, bow_draw, bow_hold and bow_shoot. Its actual state flags include moving, sprinting, jumping, dashing, hurt, attacking, dead, charging, drawingIn and bowActive; the older drawingBow/holdingBow/releasingBow API on this page belongs to a different branch.

AnimationRenderComponent and Sprite Alignment

The older PR #84 design described an entity-wide 1.15× bow scale pulse. That is not the reviewed PR #145 implementation. Instead, the renderer supports per-animation pixel anchors so larger melee/dash/bow canvases align with the player. Left-facing rendering mirrors the horizontal anchor.

Shared pixel scaling, UV-based flipping and per-animation anchors are merged. The renderer also makes isFinished() return false for looping playback modes, preventing a hold loop from being mistaken for a completed one-shot. Playback time advances only while the entity service is unpaused.

Animation Lifecycle

Jump presentation follows the physics state supplied by PlayerActions.

Gameplay transition Clip Behaviour
Accepted ground jump jump_takeoff Play takeoff and hold the ascent pose
Descent begins jump_fall Loop while falling
Landing jump_land Play landing recovery

Walking off a ledge enters falling without takeoff. After an airborne hurt or dash animation, the controller returns to the appropriate airborne presentation rather than always returning to idle.

Q requests the instrument animation. An accepted request plays instrument_draw, followed by instrument_hold. Instrument audio starts in step with the draw animation and pauses gameplay music. Another action or pausing puts the instrument away and coordinates audio cleanup.

GrappleHoldRenderComponent draws the hanging pose along the rope while attached. Hurt feedback can still appear while swinging.

Bow charges started during other animations are preserved so the draw, hold and release sequence can continue correctly.

Animation Priority

Death starts the death clip and suppresses normal action presentation. Completion emits deathAnimationFinished, allowing the screen to complete the player-loss transition.

Airborne recovery follows the movement state after hurt or dash. Bow charging retains its state across other animations. Instrument presentation is interrupted by other actions or pausing. Animation selection does not itself grant damage immunity or determine whether an attack hits.

Bow Draw / Hold / Release

  1. chargeStart starts one-shot bow_draw, records the aimed facing and enters the bow state.
  2. Draw completion enters looping bow_hold.
  3. chargeRelease starts one-shot bow_shoot, including release before the draw clip finishes.
  4. Shoot completion clears the attack/bow state and returns to locomotion.
  5. Death overrides the sequence and the bow component cancels its pending projectile.

The current implementation uses chargeStart and chargeRelease, not the former page's attackChargeStart and attackCancelled. The bow still emits attackAnimation on firing, but that event does not drive this current draw/hold/shoot controller path. E fires instantly and should not be described as automatically playing the full charged sequence.

Events

Event Source Animation response
walk / walkStop Keyboard input Locomotion state/facing
sprint / sprintStop Keyboard input Sprint state
jumpStart PlayerActions Takeoff and ascent pose
fallStart PlayerActions Looping fall
landed PlayerActions Landing recovery
instrumentStart Keyboard input Instrument draw and hold
hurt Accepted combat damage Hurt clip, subject to priority guards
death Health reaches zero Death clip
deathAnimationFinished Animation controller Screen handles player removal/loss
meleeSwing MeleeComponent Accepted swing animation, with facing direction
dashStart / airDashStart PlayerActions Both currently select air_dash
chargeStart / chargeRelease ItemUseComponent Bow draw/hold/shoot
sprintEnd PlayerActions End sprint animation state after grace period

Tuning

Clip timing is registered in PlayerFactory. Frame duration is not total clip length; total length also depends on the number of atlas frames.

Sprint 3 retunes melee playback and slows the instrument draw/hold clips, keeping the instrument audio start aligned with its draw animation. The merged implementation retains the previous idle, walk, sprint, hurt, death, sleep, dash and bow timings; it does not apply a blanket slowdown to all player animations. When changing instrument timing, keep the controller’s audio-start timing consistent with the registered draw frame duration. Melee presentation also follows the timing constants in MeleeComponent.

These are presentation values, not damage or invulnerability timings.

Testing

PlayerAnimationControllerTest and PlayerAtlasTest cover animation states and required atlas regions. GrappleHoldRenderComponentTest checks hanging-pose rendering.

Manual check Expected result
Jump, fall and land Consistent sprite alignment throughout the sequence
Take damage or air-dash while falling Falling presentation resumes afterwards
Start and interrupt the instrument Audio starts with the draw and stops on interruption
Pause during instrument playback Instrument stops without incorrectly resuming gameplay music
Attach and release the grapple Hanging pose follows the rope and clears on release
Begin charging during another animation Charge state is retained

Known Limitations

Component tests verify selected transitions and rendering behaviour rather than every visual combination. Sprite alignment, interruption timing and readability during overlapping actions require gameplay checks.

Relevant Development Links

PR Work
#196 Regression coverage, collision fixes, maintainability and Sonar coverage reporting
#211 Charged grapple, rope physics, flight wrapping and corner climbing
#229 Movement, melee and animation overhaul

Contribution Attribution

The instrument sprite sheet player_instrument.png was generated using GPT Image 2, as confirmed by Team 5 for the Sprint 3 AI declaration. It is used by the instrument draw/hold animations introduced in PR #229.

Tristan Sheedy (TristanUniCoding) developed/refined the base player sprites, movement/death animation integration and newer charged-bow sequence. Josiah Enns (Jjmenns) contributed hurt and earlier bow animation work, then melee/dash/air-dash assets and anchor integration. PR #84 remains credited as historical work, not silently presented as PR #145's API.

Darcy Franklin implemented the movement/grapple systems that supply related gameplay behaviour. The earlier blanket attribution of the original player sprite/controller work to Darcy is corrected here to reflect commit authorship. Shared renderer and cross-team contributions retain their repository history.

Sprint 3 adds Tristan Sheedy and Josiah Enns’s movement, melee and presentation overhaul, Rohan Shirkhedkar’s bow-charge transition fix, and Dhiren Malik’s animation-transition regression coverage.

Clone this wiki locally