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:
1 parent
7edd623372
commit
01498eddad
7 files changed
+82
-12
No files matched your search
+14
-2
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user