Weapons: a courtside rack you pick from + pixel-art HUD
Tins now accumulate on a courtside rack (cap 3) instead of replacing each other; a PLAIN slot banks specials for later, and GUN is a charge you pop for an auto-fire burst. Tap the rack or press 1-5 to choose what your serve throws. A fresh delivery auto-equips but never overrides a deliberate PLAIN, and the 1:1 sudden-death duel forces plain balls. HUD gets real art: generated pixel-art weapon icons, an ornate Wimbledon scoreboard PNG backing the live text (no more code-drawn boxes on top), and a bundled Silkscreen pixel font replacing the system serif. Rack tiles get padding, count-over-label alignment, and an infinity marker on the ball. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
148da4713c
commit
37e5bfd10f
17 files changed
+155
-68
No files matched your search
@@ -5,13 +5,15 @@
|
||||
import { cv } from './dom.js';
|
||||
import { audio } from './audio.js';
|
||||
import { G, score } from './state.js';
|
||||
import { keyPressed, dragServe } from './gameplay.js';
|
||||
import { keyPressed, dragServe, selectWeapon } from './gameplay.js';
|
||||
import { rackHit } from './render.js';
|
||||
import { togglePanel } from './panel.js';
|
||||
|
||||
const keys = {};
|
||||
addEventListener('keydown', e => {
|
||||
if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', ' '].includes(e.key)) e.preventDefault();
|
||||
if (e.key === 't' || e.key === 'T') togglePanel();
|
||||
if (e.key >= '1' && e.key <= '5') selectWeapon(+e.key - 1); // pick a rack slot
|
||||
if (!keys[e.code]) keyPressed(e.code);
|
||||
keys[e.code] = true;
|
||||
});
|
||||
@@ -40,7 +42,7 @@ export function takeFlickAim(maxAgeMs = 450) {
|
||||
// the two-stage serve: a drag that STARTS at a serveable pretoss aims a visible reticle
|
||||
// (G.aim, drawn by render); release fires the serve there, dragging back home cancels.
|
||||
const canAimServe = () =>
|
||||
G.mode === 'splatter' && G.phase === 'pretoss' && score.server === 'P'
|
||||
G.mode === 'splatter' && G.phase === 'pretoss' && score.server === 'P' && G.weapon !== 4 // GUN pops on tap, no reticle
|
||||
&& !G.horde && !(G.mgT > 0) && !G.changeover && !(G.interlude && G.interlude.introT > 0);
|
||||
|
||||
let steerPX = null; // live absolute finger x (-1..1 across the canvas) — machine-gun steering reads it
|
||||
@@ -48,13 +50,18 @@ export const touchPX = () => steerPX;
|
||||
|
||||
cv.addEventListener('touchstart', e => {
|
||||
e.preventDefault(); audio();
|
||||
const r = cv.getBoundingClientRect();
|
||||
for (const t of e.changedTouches) {
|
||||
if (!G.horde && !(G.mgT > 0)) { // rack tap selects a tin — but never during finger-steer modes
|
||||
const slot = rackHit((t.clientX - r.left) / r.width, (t.clientY - r.top) / r.height);
|
||||
if (slot >= 0) { selectWeapon(slot); continue; }
|
||||
}
|
||||
if (!stick) {
|
||||
stick = { id: t.identifier, x0: t.clientX, y0: t.clientY, t0: performance.now(),
|
||||
moved: false, aimable: canAimServe() }; // context locked at touch start — a movement drag never morphs into a serve
|
||||
// the reticle appears the moment the thumb lands: mag 0 = auto-target the most advanced
|
||||
if (stick.aimable) G.aim = { fx: 0, fy: 0, mag: 0 };
|
||||
else { const r = cv.getBoundingClientRect(); steerPX = (t.clientX - r.left) / r.width * 2 - 1; }
|
||||
else steerPX = (t.clientX - r.left) / r.width * 2 - 1;
|
||||
}
|
||||
else keyPressed('Space');
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user