doc 8 of 9

Stage 06 — The Juice

You will build: nothing mechanically new — and the game will feel twice as good when you're done. Hitstop, screenshake, flash: the three levers that make impacts land. You'll learn: game-feel engineering · restraint — and design decision 3 (cancel policy) gets finalized now that hits have weight. Warm-up — from memory:

  1. Every state in both machines (player + slime) — draw the two diagrams side by side.
  2. What happens, node by node, in the first 0.06 seconds of your sword swing?

Why this exists#

Fast-paced is a perception, and perception is manufactured: a few frames of frozen time on impact (hitstop), a camera that flinches (shake), a victim that blinks white (flash). Each is tiny; together they're the difference between "functional" and "crunchy." The craft here is restraint — juice is seasoning, and every lever below has an "amount" that tips from delicious into nauseating. You'll find each tipping point by crossing it on purpose.

Build it#

A — Flash (the shader shelf pays off)#

A white-out material on the victim for ~0.08s when damaged. The shaders shelf built exactly this muscle: a canvas_item shader with a flash_amount uniform mixing the sprite toward white, driven from the damaged signal. Put it on the Hurtbox owner's sprite via the component — so every future enemy flashes for free. (Write the five-line shader yourself; you know UV, COLOR, and mix.)

B — Hitstop#

On a connected hit: freeze both fighters for 40–80ms. Two honest techniques — pick one deliberately:

  • Engine.time_scale = 0.05 for a few real milliseconds (an unscaled await — engine timers scale too, so what do you wait on? solve that; it's the whole trick), then restore. Global, dramatic, affects everything including the camera.
  • Per-actor: both state machines get a micro-freeze (their processing suspended briefly). Surgical, more plumbing, nothing else in the world stutters.

Try 40ms, then 200ms — feel the tipping point, then set your number. Sword hits and taking hits deserve different amounts; decide both.

C — Screenshake, done the respectable way#

Trauma-based: a trauma: float on the camera that events add to (small hit +0.2, taking damage +0.5), decaying every frame; actual offset each frame = random within trauma² * max_offset. The squaring is the secret — small trauma barely whispers, big trauma bites, and everything decays smoothly. ~20 lines on your Camera2D. Then the restraint pass: half your first-draft numbers, play, decide.

D — Death deserves a moment#

The slime's died: a flash-white corpse pause (hitstop's cousin), then a shrink-and-pop tween, then queue_free. Death that takes 0.3 seconds reads as an event; instant deletion reads as a bug.

E — Decision 3, finalized#

Now that hits have weight, settle the cancel policy for good: dash-cancel on attack recovery? on active frames? attack-cancel out of dash? Play each combination against three slimes. Write the final ruling and its feel rationale in the architecture doc — this is the sentence that defines your combat.

git add . && git commit -m "stage 06: hitstop, trauma shake, flash, death moment; cancel policy final"

Checkpoint — definition of done#

  • Every landed hit: flash + hitstop + proportional shake, and it reads as impact
  • Taking damage feels distinctly worse than dealing it (numbers differ on purpose)
  • The overdone versions were witnessed (write one line: where was each tipping point?)
  • Deaths are moments; nothing vanishes frame-perfect
  • Decision 3 finalized in the architecture doc
  • Zero warnings; committed. Explain: why square the trauma? — with the alternative's failure described, not just "it's smoother."

Stretch (no instructions)#

Directional shake: impacts kick the camera along the hit direction before the random decay takes over. Subtle, and suddenly hits have a vector.

If you get stuck#

  • Hitstop freezes forever → your restore path awaited something that's also frozen; the section-B riddle again — what clock still ticks at time_scale 0.05?
  • Shake drifts the camera off-center → you're accumulating offset instead of setting it fresh from trauma each frame; the camera's rest position is sacred.
  • Flash sticks on → the reset lives in a timer/tween that died with a state change; who owns the flash lifecycle — the component or the state machine? Choose one owner.