Thumb-scale draw meter, looser aim magnet, a bomb worth the tin
- The draw meter is a fixed bar across the bottom, ~90% of the width and 10px tall, with the kill notch on it. It was a 26x4 stub floating on the apron by the player's feet, which is nothing under a thumb at arm's length. The serve hint is suppressed while pulling since they share the slot. pullFull 95 -> 130: at 95 every pull maxed out by accident, so the meter never meant anything. - The aim magnet took the nearest body ALONG the lane, so a close shambler a little off-axis stole shots clearly aimed past it. It now picks the best ALIGNED body, with TUNE.aimTie of slack in which a nearer one still wins — a straight-ahead lane still eats the nearest body first, which is the settled feel. aimTie: 1 restores the old behaviour exactly, for A/B. - Bomb radius 2.5 -> 4.2 (2 kills -> 5 in a scattered ten-wave), a 120-particle eruption, a ring of thrown stains and a full-size pile. The blinding white frame is now a brief warm bloom — it was hiding the very gore it announced. - Rack tiles 22 -> 30 tall, and the touch band is padded above and runs to the screen edge below. At 22 logical px they were ~30 CSS px on a phone, well under the ~44 a thumb expects; now ~62. 26-game soak clean with heavy bomb use, arrays stay bounded. Serve returns 136/150 = 90.7% +/-2.4%, 30 human-tapped points = 50 hits / 0 whiffs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
55ddf5932e
commit
21b9dd53fa
7 files changed
+90
-35
No files matched your search
+18
-8
@@ -179,18 +179,28 @@ function tickHorde(dt) {
|
||||
export function explode(x, z) {
|
||||
for (let i = zombies.length - 1; i >= 0; i--) // backwards: splatter() splices (and can sweep) the array
|
||||
if (zombies[i] && Math.hypot(zombies[i].x - x, zombies[i].z - z) < TUNE.bombRadius) splatter(i);
|
||||
gore.push({ x, z, r: 1.6, a: 1, scorch: true }); if (gore.length > 40) gore.shift(); // the crater — near-permanent
|
||||
gore.push({ x, z, r: 1.4, a: 0.9 }); if (gore.length > 40) gore.shift();
|
||||
gore.push({ x, z, r: 2.2, a: 1, scorch: true }); if (gore.length > 40) gore.shift(); // the crater — near-permanent
|
||||
gore.push({ x, z, r: 2.0, a: 0.9 }); if (gore.length > 40) gore.shift();
|
||||
// a ring of splatter thrown outward, so the blast paints the lawn instead of leaving one puddle
|
||||
for (let k = 0; k < 6; k++) {
|
||||
const a = Math.random() * 6.2832, r = TUNE.bombRadius * (0.35 + Math.random() * 0.6);
|
||||
gore.push({ x: x + Math.cos(a) * r, z: z + Math.sin(a) * r, r: 0.7 + Math.random() * 0.7, a: 0.85 });
|
||||
if (gore.length > 40) gore.shift();
|
||||
}
|
||||
const pl = piles.find(p => Math.hypot(p.x - x, p.z - z) < 0.6);
|
||||
if (pl) pl.size = Math.min(4, pl.size + 3);
|
||||
else { piles.push({ x, z, size: 3, seed: Math.random() * 1e4, blobs: null, builtSize: 0 }); if (piles.length > 30) piles.shift(); }
|
||||
for (let k = 0; k < 40; k++) parts.push({
|
||||
x, y: 0.6, z, vx: (Math.random() * 2 - 1) * 6, vy: 1 + Math.random() * 5, vz: (Math.random() * 2 - 1) * 6,
|
||||
t: 0.5 + Math.random() * 0.7, dark: k % 2 === 0,
|
||||
else { piles.push({ x, z, size: 4, seed: Math.random() * 1e4, blobs: null, builtSize: 0 }); if (piles.length > 30) piles.shift(); }
|
||||
// the eruption itself: a fat, slow, high-arcing column of gore rather than a camera flash
|
||||
for (let k = 0; k < 120; k++) parts.push({
|
||||
x: x + (Math.random() * 2 - 1) * 0.4, y: 0.5, z: z + (Math.random() * 2 - 1) * 0.4,
|
||||
vx: (Math.random() * 2 - 1) * 11, vy: 2 + Math.random() * 9, vz: (Math.random() * 2 - 1) * 11,
|
||||
t: 0.7 + Math.random() * 1.1, dark: k % 3 === 0,
|
||||
});
|
||||
G.hitstop = 0.18; boom();
|
||||
G.shake = { t: 0.35, mag: 6 }; // camera kick
|
||||
G.boomFlash = 0.08; // one white frame
|
||||
G.shake = { t: 0.45, mag: 9 }; // camera kick
|
||||
// a warm, brief bloom instead of a white-out — the blinding frame was doing the work the gore
|
||||
// should be doing, and on a phone it just hurt (see render.js for the colour)
|
||||
G.boomFlash = 0.06;
|
||||
if (G.idleT - G.lastOrderT > 3) { voice('order', 0.35); G.lastOrderT = G.idleT; } // the umpire loses composure
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user