Two-stage serve aim: hold + drag shows the reticle, release fires
Flick-to-aim was aim-by-faith — you learned where you aimed after the ball was gone. Now, at a serveable pretoss, touching and dragging shows a LIVE reticle (same mapping: direction + length = landing point); release serves there. The magnet is finally visible: within zSnap the ring turns red and rides the locked zombie (plus a marker over its head) — you see the lock BEFORE you commit the tin. - Context locked at touchstart: a movement drag started mid-rally never morphs into a serve when the ball dies (sub-300ms releases still count as the rapid flick re-serve — the Phase 1 cadence survives) - Drag back home = cancel: no serve, the tin stays in stock - Aimed (drag) serves commit specials at fixed 0.62 quality; the tap-toss ritual keeps the PERFECT-timing power ceiling and the stock — placement vs power is now a real choice - Rally / horde / machine gun untouched: drag steers, flick swings - Serve prompt: 'TAP TO SERVE - HOLD + DRAG TO AIM' / 'AIMED SERVES FIRE THE BOMB - TAP KEEPS IT' Verified with synthetic touch sequences: drag arms the reticle without serving and it tracks the thumb; release serves at the marker with the bomb committed; cancel keeps the tin; rally-started drags never morph; locked reticle renders red on the zombie (screenshot); tennis 12/12; no console errors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2f1419b1f2
commit
8cfe9fdbcd
4 files changed
+46
-9
No files matched your search
@@ -3,7 +3,7 @@
|
||||
import { cv, ctx } from './dom.js';
|
||||
import { TUNE, COURT, PLAYER_H, BOY_H, UMP_H, BOUNCE_IDLE, SPRITE_H } from './config.js';
|
||||
import { P, O, ball, score, crowd, G } from './state.js';
|
||||
import { predictLanding } from './gameplay.js';
|
||||
import { predictLanding, flickTarget } from './gameplay.js';
|
||||
import { zombies, gore, piles, parts, pellets, extras } from './zombies.js';
|
||||
|
||||
// ---------------------------------------------------------------- palette ----
|
||||
@@ -295,6 +295,15 @@ export function render() {
|
||||
if (l) drawRing(l.x, l.z, 'rgba(255,255,255,0.85)');
|
||||
}
|
||||
if (G.outMarker) drawRing(G.outMarker.x, G.outMarker.z, G.outMarker.out ? '#ff5050' : '#f8e048');
|
||||
// two-stage serve aim: the reticle tracks the thumb; red = the magnet has a zombie locked
|
||||
if (G.aim && G.mode === 'splatter' && G.phase === 'pretoss') {
|
||||
const ft = flickTarget(P, G.aim);
|
||||
if (ft.zt) { // locked: the ring rides the zombie itself, plus a marker over its head
|
||||
drawRing(ft.zt.x, ft.zt.z, '#ff5050');
|
||||
const hp = proj(ft.zt.x, 2.2, ft.zt.z);
|
||||
ctx.fillStyle = '#ff5050'; ctx.fillRect(hp.x - 1, hp.y - 4, 3, 3);
|
||||
} else drawRing(ft.tx, ft.tz, '#f8e048');
|
||||
}
|
||||
|
||||
// far-side drawables in z order (far → near), then the net, then the near side
|
||||
const farSide = [
|
||||
@@ -392,8 +401,8 @@ export function render() {
|
||||
const touch = matchMedia('(pointer: coarse)').matches;
|
||||
const stock = G.bombs ? 'BOMB' : G.triples ? 'TRIPLE' : G.flames ? 'FIRE' : null;
|
||||
const txt = G.mode === 'splatter'
|
||||
? (stock ? `FLICK FIRES THE ${stock} · TAP KEEPS IT`
|
||||
: touch ? 'TAP TO SERVE · FLICK TO AIM · SWISH TO MELEE' : 'SPACE SERVES · ARROWS AIM')
|
||||
? (stock ? `AIMED SERVES FIRE THE ${stock} · TAP KEEPS IT`
|
||||
: touch ? 'TAP TO SERVE · HOLD + DRAG TO AIM' : 'SPACE SERVES · ARROWS AIM')
|
||||
: G.serveNum === 2 ? (touch ? 'SECOND SERVE — TAP' : 'SECOND SERVE — SPACE')
|
||||
: (touch ? 'TAP TO TOSS, TAP TO SERVE' : 'SPACE TO TOSS, SPACE TO SERVE');
|
||||
ctx.fillText(txt, W / 2, H - 16);
|
||||
|
||||
Reference in new issue
Block a user