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
+11
-1
@@ -24,7 +24,7 @@ export function predictLanding() { // first-bounce point, closed form — exact,
|
||||
// splatter FREE-AIM: the flick vector maps to a landing point from where you stand — a short
|
||||
// flick drops it close, a long one reaches the far baseline. A zombie within zSnap of that
|
||||
// point magnets the shot (with walk-lead); otherwise the ball lands exactly where you flicked.
|
||||
function flickTarget(ch, aim) {
|
||||
export function flickTarget(ch, aim) { // exported: render draws the live reticle with it
|
||||
const R = Math.min(1, Math.max(0.12, aim.mag / 160)) * 22; // px flick length -> meters of reach
|
||||
const tx = Math.max(-6.5, Math.min(6.5, ch.x + aim.fx * R));
|
||||
const tz = Math.max(1, Math.min(24.5, ch.z + aim.fy * R)); // screen up = up-court (-z)
|
||||
@@ -513,6 +513,16 @@ function racketAI(rz, dt) {
|
||||
}
|
||||
}
|
||||
|
||||
// release of the two-stage aim: an instant serve to the reticle (quality fixed — placement
|
||||
// is this serve's power; the toss ritual keeps the PERFECT-timing power ceiling)
|
||||
export function dragServe(aim) {
|
||||
if (G.mode !== 'splatter' || G.phase !== 'pretoss' || score.server !== 'P') return;
|
||||
if (G.horde || G.mgT > 0 || G.changeover) return;
|
||||
ball.active = true; ball.collected = false; ball.bounces = 0; ball.firstLand = null;
|
||||
ball.x = P.x + 0.35; ball.z = P.z; ball.y = 2.2; ball.g = TUNE.gravity;
|
||||
hitServe(P, 0.62, aim);
|
||||
}
|
||||
|
||||
export function keyPressed(code) {
|
||||
if (code !== 'Space') return;
|
||||
audio(); // unlock on first gesture
|
||||
|
||||
Reference in new issue
Block a user