Revert "Aim by dragging at them, so the thumb stops walking into the iOS edge"

This reverts commit d4bbcfc080.
This commit is contained in:
wuwi committed 2026-08-02 14:10:12 +02:00
1 parent d4bbcfc080
commit 1337c1f47d
5 files changed
+22 -29

No files matched your search

+2 -2
View File
@@ -33,7 +33,7 @@ export const pullQuality = mag => TUNE.pullQMin + pullFrac(mag) * (1 - TUNE.pull
export function flickTarget(ch, aim) { // exported: render draws the live reticle with it
const q = pullQuality(aim.mag), f = pullFrac(aim.mag);
if (aim.mag < TUNE.pullMin) return { q, f }; // barely drawn: no lane yet, so no target
const ax = aim.fx, az = aim.fy; // unit vector, already in SHOT direction. screen up = -z
const ax = aim.fx, az = aim.fy; // unit vector; input already inverted the pull. screen up = -z
let zt = null, near = 1e9, bestErr = 1e9;
for (const zb of zombies) {
const dx = zb.x - ch.x, dz = zb.z - ch.z;
@@ -588,7 +588,7 @@ function transition(dt) {
// the mechanic changed under you — the one popup that gets an illustration, because it has
// to TEACH the gesture, not just announce it
showModal({ title: 'THE MATCH HAS CHANGED', color: UI.hot, icon: 'x_howto', iconH: 120,
body: ['DRAG AT THEM TO AIM — THEN LET GO', 'THE FURTHER YOU DRAG, THE HARDER IT HITS',
body: ['PULL BACK TO AIM — THEN LET GO', 'THE FURTHER YOU PULL, THE HARDER IT HITS',
'A WEAK SHOT ONLY STAGGERS THEM'] });
});
}
+4 -10
View File
@@ -42,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 home again cancels.
// (G.aim, drawn by render); release fires the serve there, dragging back home cancels.
// EVERY phase of splatter play, so the drag never silently turns into something else. The old
// "drag walks the player" mode between shots was invisible state and read as a bug.
const canAimServe = () =>
@@ -90,16 +90,10 @@ cv.addEventListener('touchmove', e => {
if (t.identifier !== stick.id) continue;
const dx = t.clientX - stick.x0, dy = t.clientY - stick.y0, dist = Math.hypot(dx, dy);
if (dist > DEAD) stick.moved = true;
// Drag TOWARD the target, not back from it. It used to be a slingshot (pull back, launch
// forward) and that felt better — but every shot then ended with the thumb LOWER than it
// started, and the next touch begins where the last one ended. Over a horde the thumb walks
// itself into the iOS bottom edge and a pull becomes Reachability. Dragging at them walks it
// UP-screen instead, away from the edge. It also matches the flick-swing below, which always
// aimed this way.
if (stick.aimable) {
if (stick.aimable) { // slingshot: PULL BACK, launch forward — the shot is the inverse of the drag
if (dist > DEAD) {
if (!stick.tossed) { serveToss(); stick.tossed = true; } // the drag kicks off the toss animation
G.aim = { fx: dx / dist, fy: dy / dist, mag: dist };
if (!stick.tossed) { serveToss(); stick.tossed = true; } // the pull kicks off the toss animation
G.aim = { fx: -dx / dist, fy: -dy / dist, mag: dist };
// the moment the pull is strong enough to actually splatter, it clicks — you can feel
// where the threshold is without watching the reticle
const hot = pullQuality(dist) >= TUNE.zSplatQ;
+2 -2
View File
@@ -89,8 +89,8 @@ const TUT = [
"stops being the other fellow.",
"Nobody stops the match. Nobody ever does."] },
{ pose: 2, shot: 'tut_aim', say: ["Now you do not rally. You <em>AIM</em>.",
"<em>DRAG AT THEM</em> from your man and let go.",
"The further you drag, the harder it lands.",
"<em>PULL BACK</em> from your man and let go.",
"The further you pull, the harder it lands.",
"A soft one only makes them cross."] },
{ pose: 2, shot: 'tut_rack', say: ["I bring tins out to the rack down there.",
"<em>BOMBS</em>, <em>TRIPLES</em>, <em>FIRE</em>, and the <em>GUN</em>.",
+13 -14
View File
@@ -647,27 +647,26 @@ function drawCard(title, sub1, sub2, color) {
}
// Sit in the serve stance doing nothing and the gesture demonstrates itself: a ghost thumb slides
// UP-court away from the player while chevrons run out ahead of it, then it releases and repeats.
// The drag is the whole game in splatter mode, and a line of text was carrying that alone.
// BACK from the player while chevrons grow FORWARD up the court, then it releases and repeats.
// Pulling is the whole game in splatter mode, and a line of text was carrying that alone.
function drawPullHint() {
const cyc = 1.9, t = (G.idleHintT - TUNE.pullHintAfter) % cyc;
const draw = Math.min(1, t / 1.15); // the drag itself, then a beat held at full
const draw = Math.min(1, t / 1.15); // the pull itself, then a beat held at full
const gone = t > 1.45; // released — the thumb lifts off
const anchor = proj(P.x, 0, P.z + 0.6);
const ax = Math.round(anchor.x), ay = Math.round(Math.min(anchor.y + 6, METER_Y() - 6));
const ax = Math.round(anchor.x), ay = Math.round(Math.min(anchor.y + 6, METER_Y() - 26));
const len = 30 * draw;
ctx.save();
ctx.globalAlpha = gone ? 0 : 0.85;
// the dotted track the thumb travels, straight up-screen = "drag at them"
// the dotted track the thumb travels, straight down-screen = "pull back"
ctx.fillStyle = UI.dim;
for (let d = 6; d < 34; d += 6) ctx.fillRect(ax - 1, ay - d, 2, 2);
// chevrons running out beyond the thumb as the drag grows — same direction as the shot, which
// is now the whole lesson: you point at what you want hit
for (let d = 6; d < 34; d += 6) ctx.fillRect(ax - 1, ay + d, 2, 2);
// chevrons growing UP-court as the pull grows — the inverse relationship is the whole lesson
ctx.fillStyle = UI.warm;
for (let i = 0; i < 3; i++) {
const u = (i + 1) / 4;
if (draw < u * 0.9) continue;
const cy = ay - 40 - i * 7, s = 4;
const cy = ay - 8 - i * 7, s = 4;
ctx.beginPath();
ctx.moveTo(ax, cy - s); ctx.lineTo(ax + s, cy + s * 0.7); ctx.lineTo(ax - s, cy + s * 0.7);
ctx.fill();
@@ -675,9 +674,9 @@ function drawPullHint() {
// the ghost thumb
ctx.globalAlpha = gone ? 0 : 0.9;
ctx.fillStyle = UI.cream;
ctx.beginPath(); ctx.arc(ax, ay - len, 5, 0, 7); ctx.fill();
ctx.beginPath(); ctx.arc(ax, ay + len, 5, 0, 7); ctx.fill();
ctx.fillStyle = 'rgba(0,0,0,0.45)';
ctx.beginPath(); ctx.arc(ax, ay - len, 2, 0, 7); ctx.fill();
ctx.beginPath(); ctx.arc(ax, ay + len, 2, 0, 7); ctx.fill();
ctx.restore();
}
@@ -1091,13 +1090,13 @@ export function render() {
const touch = IS_TOUCH, switchHint = touch ? 'TAP THE RACK TO SWITCH' : '1-5 TO SWITCH';
const sel = ['PLAIN', 'BOMB', 'TRIPLE', 'FIRE', 'GUN'][G.weapon];
// The DUEL is played under tennis rules — no slingshot, no rack, serve to the box (see the
// !G.interlude guards in solveShot and the aim reticle). It was still being told to drag
// !G.interlude guards in solveShot and the aim reticle). It was still being told to pull back
// to aim, which is the one thing that does nothing there.
const txt = G.mode === 'splatter' && !G.interlude
? (G.weapon === 4 ? (touch ? 'TAP TO UNLOAD THE GUN' : 'SPACE UNLOADS THE GUN')
: G.aim ? 'FURTHER = HARDER'
: G.aim ? 'PULL BACK: FURTHER = HARDER'
: G.weapon > 0 ? `SERVE FIRES: ${sel} · ${switchHint}`
: touch ? 'DRAG AT THEM · RELEASE TO FIRE' : 'DRAG AT THEM · SPACE SERVES')
: touch ? 'PULL BACK TO AIM · RELEASE TO FIRE' : 'DRAG BACK TO AIM · SPACE SERVES')
: 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, METER_Y()); // same slot the draw meter uses
+1 -1
View File
@@ -403,7 +403,7 @@ export function spawnRacketZombie() { // one takes up residence on the far court
if (!G.seen.racket) { // it is not a shambler and it does not behave like one — say so, once
G.seen.racket = true;
showModal({ title: 'IT HAS A RACKET', color: UI.hot,
body: ['IT RETURNS YOUR WEAK SHOTS', 'ONLY A FULL-LENGTH DRAG WOUNDS IT'] });
body: ['IT RETURNS YOUR WEAK SHOTS', 'ONLY A FULL PULL WOUNDS IT'] });
}
}
function endHorde() {