Aesthetics: 3x render res, flatter lens, 4-frame walk cycles, tiered gore
- RES 2 -> 3: phone screens now DOWNSCALE the canvas (crisp pixels) instead of upscaling it (soft). Umpire-tap coords un-hardcoded from RES=2. - Flatter lens: camZ 36 -> 42 with camF scaled per orientation (406/580) so the PLAYER stays the same size — far-court zombies render ~25% bigger and finally read as individuals from the baseline. - Smoother animation: 4-frame walk cycles for both classic shamblers and the runner's sprint (new sheets, same style anchor; z_a1-4, z_b1-4, z_f1-4). Same cycle frequency — frames subdivide the stride. Render falls back to 2 frames per variant until its sheet loads. - Tiered gore (GORE_MUL): the more advanced the zombie, the more absurd the mess — classics 1x (base bumped 24 -> 30 particles), runner 1.8x, shield 2.5x, racket boss 3x, brute 4x (120 particles, a scatter of stains, an instant size-3 mound). Verified: fresh origin, canvas 1440px, umpire triple-tap works at RES 3, all 4 anim frames cycle at the old stride rate, brute kill = 120 parts / 2 stains / size-3 pile, far-court lineup screenshot clearly readable, portrait layout numbers correct (810x1440, camF 580), tennis 11/12, no console errors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e75b3888de
commit
e948e8b36e
19 files changed
+28
-15
No files matched your search
+13
-6
@@ -39,18 +39,25 @@ function pickVariant() {
|
||||
|
||||
// core kill: remove the zombie, spawn its gore/pile/particles, score. No ball coupling —
|
||||
// shared by ball hits, machine-gun pellets, melee swipes, and extra (multi-serve) balls.
|
||||
// how absurdly a variant dies: classics splash, the advanced roster DETONATES
|
||||
const GORE_MUL = { a: 1, b: 1, f: 1.8, s: 2.5, g: 4, r: 3 };
|
||||
|
||||
function killZombie(i, quiet) {
|
||||
const zb = zombies[i];
|
||||
const big = zb.variant === 'g'; // a brute goes down like a building — twice the gore
|
||||
const mul = GORE_MUL[zb.variant] || 1;
|
||||
zombies.splice(i, 1);
|
||||
if (G.interlude && zb.variant === 'r') resolveInterlude('P'); // regicide ends the duel your way — any weapon counts
|
||||
gore.push({ x: zb.x, z: zb.z, r: (big ? 0.8 : 0.45) + Math.random() * 0.35, a: 0.85 });
|
||||
if (gore.length > 40) gore.shift();
|
||||
const stains = Math.round(Math.sqrt(mul)); // advanced kills splash a scatter of stains, not one puddle
|
||||
for (let k = 0; k < stains; k++) {
|
||||
gore.push({ x: zb.x + (k ? (Math.random() * 2 - 1) * 0.9 : 0), z: zb.z + (k ? (Math.random() * 2 - 1) * 0.9 : 0),
|
||||
r: (0.45 + Math.random() * 0.35) * Math.sqrt(mul), a: 0.85 });
|
||||
if (gore.length > 40) gore.shift();
|
||||
}
|
||||
const pl = piles.find(p => Math.hypot(p.x - zb.x, p.z - zb.z) < 0.6); // stack up where kills cluster
|
||||
if (pl) pl.size = Math.min(4, pl.size + (big ? 2 : 1));
|
||||
else { piles.push({ x: zb.x, z: zb.z, size: big ? 2 : 1, seed: Math.random() * 1e4, blobs: null, builtSize: 0 });
|
||||
if (pl) pl.size = Math.min(4, pl.size + Math.round(mul / 2 + 0.5));
|
||||
else { piles.push({ x: zb.x, z: zb.z, size: Math.min(4, Math.round(mul / 2 + 0.5)), seed: Math.random() * 1e4, blobs: null, builtSize: 0 });
|
||||
if (piles.length > 30) piles.shift(); }
|
||||
const n = big ? 48 : 24;
|
||||
const n = Math.round(30 * mul); // base bumped 24 -> 30, then the multiplier goes to work
|
||||
for (let k = 0; k < n; k++) { const dark = k >= n * 2 / 3; parts.push({ // ~1/3 dark & long-lived: settling gore
|
||||
x: zb.x, y: 0.9, z: zb.z,
|
||||
vx: (Math.random() * 2 - 1) * 3.5, vy: 1 + Math.random() * 3.5, vz: (Math.random() * 2 - 1) * 3.5,
|
||||
|
||||
Reference in new issue
Block a user