Give the brute a four-frame lumber

Last body still walking on two frames, and the slowest thing on court, so the
lurch was the most visible. Same treatment as the player: the whole cycle
regenerated in one pass, then fitted per channel onto the mean and sd of the
frames that stay — the four wound skins — so a healthy brute and a wounded one
are the same colour (mean error about 1 of 255).

Its cycle steps off DISTANCE WALKED, not time, the same rule its wound lurch
already used: at brute pace a time-driven cycle is pure foot-slide. Four frames
over the same metre, so the cadence is unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5 committed 2026-07-31 19:05:31 +02:00
1 parent 94136ddf8c
commit 85e08ab4b8
7 files changed
+9 -5

No files matched your search

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 49 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 52 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

+1 -1
View File
@@ -97,6 +97,6 @@
<p id="build"></p>
</div>
</div>
<script type="module" src="main.js?v=57"></script>
<script type="module" src="main.js?v=58"></script>
</body>
</html>
+8 -4
View File
@@ -155,7 +155,7 @@ export function proj(x, y, z) {
// ---------------------------------------------------------------- sprites ----
// assets/<name>.png; game falls back to code-drawn figures until sprites load.
const SPRV = 52; // asset cache-buster — bump with main.js?v=N (see the img.src note below)
const SPRV = 53; // asset cache-buster — bump with main.js?v=N (see the img.src note below)
const SPR = {};
for (const n of ['p_idle1','p_idle2','p_bounce','p_bounce2','p_toss','p_smash','p_run1','p_run2','p_run3','p_run4','p_swing1','p_swing2',
'o_idle1','o_idle2','o_bounce','o_bounce2','o_toss','o_smash','o_run1','o_run2','o_swing1','o_swing2',
@@ -170,7 +170,7 @@ for (const n of ['p_idle1','p_idle2','p_bounce','p_bounce2','p_toss','p_smash','
'z_chair1','z_chair2','z_chairw','z_chairt','z_chairwt', // boss design 3 (chapter 3, 6, ...)
'z_a1','z_a2','z_a3','z_a4','z_b1','z_b2','z_b3','z_b4','z_c1','z_c2',
'z_d1','z_d2','z_d3','z_d4', // the steward: bigger body, hi-vis vest, 4-frame walk
'z_f1','z_f2','z_f3','z_f4','z_g1','z_g2','z_gw','z_s1','z_s2','z_s3',
'z_f1','z_f2','z_f3','z_f4','z_g1','z_g2','z_g3','z_g4','z_gw','z_s1','z_s2','z_s3',
'z_cw1','z_cw2','z_aw','z_bw', // wounded skins for multi-hit enemies (racket boss, brute, and now the classic shamblers)
'w_ball','w_bomb','w_triple','w_fire','w_gun', // weapon-rack icons
'scoreboard']) {
@@ -258,7 +258,7 @@ function drawBoy(b) {
ctx.drawImage(img, -w / 2, -h, w, h);
ctx.restore();
}
const ZFRAMES = { a: 4, b: 4, f: 4, d: 4 }; // 4-frame walk cycles where sheets exist; the rest stay 2
const ZFRAMES = { a: 4, b: 4, f: 4, d: 4, g: 4 }; // 4-frame walk cycles where sheets exist; the rest stay 2
// The rogue ball machine, on its own generated sheet: a dented hopper cart on wheels with a barrel
// aimed down-court, and a second frame with the muzzle flashing. Oliver called the first, procedural
// version "naively painted" — it was four rects, which is fine for fire but not for furniture the
@@ -287,7 +287,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
let frame = rk && zb.pose === 'swing' ? 2 : Math.floor(zb.walkT * (zb.variant === 'f' ? 6 : 2.6) * N / 2) % N + 1;
let frame = rk && zb.pose === 'swing' ? 2
: zb.variant === 'g' ? Math.floor(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)
: Math.floor(zb.walkT * (zb.variant === 'f' ? 6 : 2.6) * N / 2) % N + 1;
if (zb.variant === 's' && zb.shieldT > 0) frame = 3; // chair dropped — hit it NOW
let h = zb.variant === 'g' ? 2.7 : zb.variant === 'd' ? 2.15 : rk ? 1.85 : 1.8; // the brute towers half again over the crowd; the steward stands between him and it
if (zb.variant === 'B') h = 1.8 * (zb.scale || 1.5); // ...and a chapter boss towers over the brute