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
@@ -232,12 +232,15 @@ function drawBall(x, y, z, glint = false, bomb = false, flame = false) {
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------- actors ----
|
||||
function drawStatic(name, x, z, hMeters, bob = 0) {
|
||||
function drawStatic(name, x, z, hMeters, bob = 0, flip = false) {
|
||||
const img = SPR[name]; if (!img) return;
|
||||
const p = proj(x, 0, z);
|
||||
const h = hMeters * p.s, w = h * img.width / img.height;
|
||||
drawShadow(p.x, p.y, w * 0.4, h * 0.04, 0.25);
|
||||
ctx.drawImage(img, p.x - w / 2, p.y - h - bob, w, h);
|
||||
if (!flip) return ctx.drawImage(img, p.x - w / 2, p.y - h - bob, w, h);
|
||||
ctx.save(); ctx.translate(p.x, 0); ctx.scale(-1, 1); // the art is drawn facing LEFT
|
||||
ctx.drawImage(img, -w / 2, p.y - h - bob, w, h);
|
||||
ctx.restore();
|
||||
}
|
||||
function drawBoy(b) {
|
||||
// mopping is not sprinting: its own sheet and a slower push cycle. Falls back to the run
|
||||
@@ -301,7 +304,11 @@ function drawZombie(zb) {
|
||||
let N = ZFRAMES[v] || 2;
|
||||
if (!SPR['z_' + v + N]) N = 2; // frames still loading (or sheet rejected): 2-frame fallback
|
||||
// same CYCLE frequency as before — more frames subdivide the stride, they don't speed it up
|
||||
// The racket zombie holds a position and only moves when the ball makes him, so a time-driven
|
||||
// cycle had him flicking between two frames on the spot. His stride steps off ground covered like
|
||||
// the brute's — standing still is standing still — and his swing keeps its own frame.
|
||||
let frame = rk && zb.pose === 'swing' ? 2
|
||||
: rk ? stepFrame((zb.dist || 0) / TUNE.racketStride, N) + 1
|
||||
: zb.variant === 'g' ? stepFrame(zb.z / (TUNE.bruteStride * 2 / N), N) + 1 // heaviest body: step off DISTANCE
|
||||
// WALKED, like its wound lurch below,
|
||||
// or the feet slide (same cycle length)
|
||||
@@ -376,7 +383,10 @@ function drawZombie(zb) {
|
||||
// feeding: a fast bob over the body instead of a stride. Same sprites, different rhythm.
|
||||
const bob = zb.feeding ? Math.abs(Math.sin(zb.walkT * 11)) * Math.max(1, p0(zb) * 0.05)
|
||||
: Math.floor(zb.walkT * 5.2) % 2;
|
||||
drawStatic(name, zb.x, zb.z, h, bob);
|
||||
// Every side-on body is DRAWN facing left, so one walking right was moonwalking — obvious the
|
||||
// moment they close on you across your own half. The front-facing ones (the turned CPU, the
|
||||
// runner, the machine, a chapter boss) have no left or right to turn and are left alone.
|
||||
drawStatic(name, zb.x, zb.z, h, bob, zb.face > 0 && !'cfmB'.includes(v));
|
||||
if (zb.burnT > 0) drawFlames(zb, h);
|
||||
if (zb.windT > 0 && zb.variant === 'B') { // the boss telegraphs too: it rears up, glowing, then throws
|
||||
const k = 1 - zb.windT / TUNE.bossWind, p = proj(zb.x, h * 0.62, zb.z); // bossWind, not machWind: the boss telegraphs faster
|
||||
|
||||
Reference in new issue
Block a user