Turn the bodies around, calm the racket zombie, break up the pack

Three from the playtest, all code:

Every side-on sprite is DRAWN facing left, and nothing ever mirrored them, so a
zombie walking right moonwalked — obvious the moment they close on you across
your own half. They face where they last walked now. The front-facing ones (the
turned CPU, the machine, a chapter boss) have no left or right and are left alone.

The racket zombie holds a position and only moves when the ball makes him, so a
time-driven walk cycle flicked him between two frames on the spot. His stride
steps off ground covered, like the brute's — standing still is standing still.

And the pack no longer stands on the body twitching for as long as the summary is
up: once it appears they break up and shamble away up-court. Measured — feeding
at 3s, dispersed to 3m by 6.5s.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5 committed 2026-07-31 22:24:11 +02:00
1 parent 7edd623372
commit 01498eddad
7 files changed
+82 -12

No files matched your search

+14 -2
View File
@@ -3,7 +3,7 @@
// your baseline — one crossing it is a point for THEM.
// (zombies <-> gameplay is a runtime-only import cycle, same pattern as input.)
import { TUNE, UI, COURT, VOLLEY, CONTACT, BOSS_ART, EATEN_BURST, EATEN_FEED_R } from './config.js';
import { TUNE, UI, COURT, VOLLEY, CONTACT, BOSS_ART, EATEN_BURST, EATEN_SUMMARY, EATEN_FEED_R } from './config.js';
import { G, P, ball, sendBoy, setupPoint } from './state.js';
import { splat, moan, pock, voice, boom, swish, shriek, aww, sfx } from './audio.js';
import { splatPoint, cheer, spentBall, resolveInterlude, showModal, endBossFight, aside } from './gameplay.js';
@@ -542,6 +542,7 @@ export function updateZombies(dt) {
const zb = zombies[i];
if (!zb) continue; // a bomb detonation splices several out mid-loop and can gut the array under us
zb.walkT += dt;
const faceX0 = zb.x; // which way he is walking, for the sprite mirror in drawZombie
if (zb.burnT > 0 && burnTick(zb, i, dt)) continue; // the fire finished it — the array moved under us
if (!held) zb.z += zb.v * (zb.burnT > 0 ? TUNE.burnPanic : 1) * dt;
bleed(zb); // open wounds bleed every frame they're standing
@@ -570,7 +571,7 @@ export function updateZombies(dt) {
pock(0.3, 1500); // the tell: a mechanical click as it loads
}
}
if (G.mode === 'eaten' && G.eatenAt && zb.variant !== 'm') {
if (G.mode === 'eaten' && G.eatenAt && zb.variant !== 'm' && G.eatenT < EATEN_SUMMARY) {
// You are down. Nothing else matters to them: every body on court converges on the spot and
// packs into a ring around it, and the ones already there feed (the bob is in drawZombie).
// This is the whole point of the death — you go under a CROWD, not under a puff of gore.
@@ -591,6 +592,16 @@ export function updateZombies(dt) {
}
continue; // no shambling, no eating you twice, no crossing the baseline for a point
}
if (G.mode === 'eaten' && G.eatenAt) {
// The summary is up. They have finished with you: the pack breaks up and shambles away up-court
// instead of standing on the body twitching in a heap for as long as the screen is on.
zb.feeding = false;
const away = Math.sign(zb.x - G.eatenAt.x) || (zb.walkT % 2 < 1 ? 1 : -1);
zb.x += away * zb.v * 0.5 * dt;
zb.z -= zb.v * 0.7 * dt; // back the way they came
zb.face = away;
continue;
}
if (zb.variant === 'm') { // the machine wheels itself around instead of being bolted down
if (!held && G.mode === 'splatter' && !G.interlude) {
if (zb.rollTo !== undefined) {
@@ -679,6 +690,7 @@ export function updateZombies(dt) {
ball.vx *= 0.6; ball.vz *= 0.6; ball.lastHit = 'X'; // spent — one stagger per ball
}
}
if (Math.abs(zb.x - faceX0) > 0.004) zb.face = Math.sign(zb.x - faceX0); // sticky: a body standing still keeps facing where it last walked
if (zb.z >= COURT.L + 0.7) { aside('ump_unsportsmanlike', 0.5); zombies.splice(i, 1); if (G.mode !== 'eaten' && !G.horde && !G.clearing) splatPoint('O'); } // it reached your baseline (during a mop-up, a straggler that reaches the line just despawns — no point for them)
}