The colour goes on the court, and the dead go off like everyone else
"the colored zombies should also explode like they did before and make the normal splash sound on destruction.. no bleeps please.. can we make the color as a color circle the walk on? the sign they're holding is not nice. also remove the ball slicing in this mode.. this leads to unwanted hits". The silent deaths were my bug: the hook in killZombie did drillKill(zb) and then RETURNED, and everything below that return is the death — decal, pile, 36-particle burst, splat, headshot crack. It resolves after the splice and without returning now. Both halves are load-bearing and each was a bug in turn: splice first or a freshly drawn combination names the corpse; don't return, or the body simply vanishes. The colour is a disc on the court the body walks on, drawn before the sprite. The bib was a flat quad pinned to a walking sprite — UI stuck onto a character, covering the art it sat on. On the ground it takes the court's own perspective, measures 12.4px across at the spawn line against a chest patch's few, and hides none of the sprite. A hard dark rim plus a bright inner line is what keeps it from reading as another gore decal. No slicing in the drill: a cut ball leaves the corpse and strikes whatever it finds next, which in a mode where the wrong body is the failure is the game choosing your target for you, badly. And the mode has no sound of its own now, deliberately. The umpire reading the list was vetoed, the arpeggio that replaced him was vetoed. blip() is deleted. A kill bursts and splats like every other kill in this game; the strip carries the list. 28 tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
abd6d4f789
commit
d775ac40ec
7 files changed
+96
-72
No files matched your search
+28
-23
@@ -662,8 +662,8 @@ function drawZombie(zb) {
|
||||
// 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.
|
||||
if (zb.bib !== undefined) drawColourRing(zb); // BEFORE the sprite: he stands ON it
|
||||
drawStatic(name, zb.x, zb.z, h, bob, zb.face > 0 && !'cfmB'.includes(v));
|
||||
if (zb.bib !== undefined) drawBib(zb, h, bob);
|
||||
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 = Math.max(0, 1 - zb.windT / (zb.windMax || TUNE.bossWind)), p = proj(zb.x, h * 0.62, zb.z); // fade over the design's own wind
|
||||
@@ -681,32 +681,37 @@ function drawZombie(zb) {
|
||||
if (v === 'B' && zb.hpMax) drawBossHp(zb, h);
|
||||
}
|
||||
|
||||
// THE TRAINING BIB — the drill's colour, worn. ponytail: this is a DRAWN OVERLAY, and it knowingly
|
||||
// breaks the house rule that says add sprite frames rather than fake them (see PROJECT.md). It is
|
||||
// here because the mode is a feel-test and six bib sheets x every walk frame is a week of art to
|
||||
// answer a question a rectangle answers today. If the drill survives its playtest, this function is
|
||||
// the thing to delete: the shipping version is a real bib sprite per colour, drawn like a wound skin.
|
||||
// THE COLOUR IS A DISC ON THE COURT, and the body walks on it. It was a bib worn on the chest and
|
||||
// Oliver's verdict was "the sign they're holding is not nice" — which it was: a flat quad pinned to
|
||||
// a walking sprite reads as UI stuck onto a character rather than as part of the world, and it fought
|
||||
// the artwork it was covering.
|
||||
//
|
||||
// It is a TRAPEZOID, not a rectangle — a flat bar over a walking body reads as a UI element stuck to
|
||||
// the screen; narrowing at the shoulders reads as cloth on a torso. And it carries PIPS as well as a
|
||||
// hue: about 8% of men cannot separate the red from the green, and a mode whose entire input is
|
||||
// "which colour is that" owes them a second channel.
|
||||
function drawBib(zb, hMeters, bob) {
|
||||
// On the ground it is better on every count. It sits in the court's own perspective, so it shrinks
|
||||
// and squashes with distance like everything else; it is far LARGER in pixels than a chest patch at
|
||||
// the same depth, which is what fixes the far-baseline readability the die-face dots could never
|
||||
// solve; and it hides none of the sprite. The obvious risk — a coloured disc reading as another gore
|
||||
// decal — is answered by the ring: gore is a soft flat blob, this has a hard bright rim and a lit
|
||||
// centre, so it reads as painted court marking rather than as something spilled.
|
||||
//
|
||||
// ponytail: still procedural rather than art, and that is right here — this is a court MARKING, the
|
||||
// same family as the tramlines, not a character. It is not the sprite rule being bent twice.
|
||||
function drawColourRing(zb) {
|
||||
const C = DRILL_COLS[zb.bib]; if (!C) return;
|
||||
const p = proj(zb.x, 0, zb.z); if (p.s <= 0) return;
|
||||
const h = hMeters * p.s;
|
||||
const y0 = p.y - h * 0.68 - bob, y1 = p.y - h * 0.42 - bob; // chest to waist
|
||||
// SHOULDERS WIDER THAN WAIST. The first cut flared the other way and every body was wearing a
|
||||
// sandwich board — a shape that widens as it goes down is furniture, not cloth on a torso.
|
||||
const wTop = h * 0.185, wBot = h * 0.155;
|
||||
const cx = Math.round(p.x);
|
||||
const rx = p.s * TUNE.drillRingR, ry = rx * 0.34; // squashed by the camera, like every ground oval
|
||||
ctx.save();
|
||||
ctx.globalAlpha = 0.92;
|
||||
ctx.fillStyle = C.col;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(cx - wTop, y0); ctx.lineTo(cx + wTop, y0);
|
||||
ctx.lineTo(cx + wBot, y1); ctx.lineTo(cx - wBot, y1);
|
||||
ctx.closePath(); ctx.fill();
|
||||
ctx.fillStyle = 'rgba(0,0,0,0.30)'; // a seam, so it sits ON the body
|
||||
ctx.fillRect(cx - wTop, Math.round(y0), wTop * 2, Math.max(1, h * 0.012));
|
||||
ctx.beginPath(); ctx.ellipse(p.x, p.y, rx, ry, 0, 0, 7); ctx.fill();
|
||||
// a dark rim, then a bright inner line: two edges are what stop it reading as a puddle, and they
|
||||
// survive being drawn over clay, grass and blood alike
|
||||
ctx.globalAlpha = 0.75;
|
||||
ctx.lineWidth = Math.max(1, p.s * 0.012);
|
||||
ctx.strokeStyle = 'rgba(0,0,0,0.55)';
|
||||
ctx.beginPath(); ctx.ellipse(p.x, p.y, rx, ry, 0, 0, 7); ctx.stroke();
|
||||
ctx.strokeStyle = 'rgba(255,255,255,0.5)';
|
||||
ctx.beginPath(); ctx.ellipse(p.x, p.y, rx * 0.72, ry * 0.72, 0, 0, 7); ctx.stroke();
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
// THE CALLED LIST, on screen. Oliver's call: the umpire reads it aloud AND it shows as a pattern —
|
||||
|
||||
Reference in new issue
Block a user