The flick fires the moment it is a flick: the swing launches at the crossing, and the aim rides the thumb to contact
Oliver's service-line report: flicking the incoming ball LEFT was near impossible mid-court at the service line while RIGHT worked, easing toward the baseline. The lane math was symmetric to the centimetre — the defect was latency. The swing waited for the RELEASE, so the whole gesture ran as dead time on top of the windup: ~120 ms of lateness drops contact quality 1.0 -> 0.08, where flickReach halves the width and aimError drowns the rest. A left swipe is a right thumb's slowest direction, the service line leaves ~700-870 ms of budget (measured), and any swipe over FLICK_MS was silently dead. Left + service line was the slowest gesture meeting the shortest budget. Now, in rally modes: crossing flickMin fires the swing (once per gesture, rally phase only) and the vector stays LIVE — trySwing reads G.swipe at contact, with the released flickAim carrying the aim only when the ball arrives after the finger lifts. The FLICK_MS deadline goes with it where the crossing can fire; it survives where it cannot (gore free-aim, the serve strike). Serve gesture, duel, gore and keys untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
532dd3b83e
commit
6f9dea4ffc
5 files changed
+82
-15
No files matched your search
@@ -852,6 +852,34 @@ test('a gentle flick cannot be played out — only a committed one can', () => {
|
||||
assert.ok(safe > 0.4 && safe < 1, 'the ring turns hot inside the swipe range, not at either end');
|
||||
});
|
||||
|
||||
test('the flick aims from the LIVE swipe: contact reads G.swipe, no release needed', () => {
|
||||
// The swing fires the moment the drag crosses flickMin now (input.js), so at contact the finger
|
||||
// is usually still down and no released flickAim exists yet. The aim has to come from the live
|
||||
// vector — without this, every crossing-fired flick would land flat and the latency fix (a left
|
||||
// flick at the service line released too late to aim anything) would have swung at nothing.
|
||||
startMatch();
|
||||
G.modal = null; G.modalQ.length = 0;
|
||||
const arm = () => { // one rally ball, contact at the window's centre
|
||||
G.interlude.introT = 0; G.phase = 'rally';
|
||||
P.x = 0; P.z = 22.8; P.swingT = -1; G.placeMark = null;
|
||||
ball.active = true; ball.lastHit = 'O'; ball.bounces = 1;
|
||||
ball.x = 0; ball.y = 0.7; ball.z = P.z - 4.15;
|
||||
ball.vx = 0; ball.vy = 2.0; ball.vz = 14; ball.g = TUNE.gravity;
|
||||
keyPressed('Space'); // what the flickMin crossing fires mid-gesture
|
||||
for (let i = 0; i < 30 && ball.lastHit !== 'P'; i++) update(DT);
|
||||
assert.equal(ball.lastHit, 'P', 'contact happened');
|
||||
return G.placeMark;
|
||||
};
|
||||
G.swipe = { ax: -1, az: 0, fx: -1, fy: 0, mag: TUNE.flickFull }; // held LEFT, finger still down
|
||||
const left = arm();
|
||||
assert.ok(left && left.x < -2, 'the live swipe aimed it left: x=' + (left ? left.x.toFixed(2) : 'none'));
|
||||
G.swipe = { ax: 1, az: 0, fx: 1, fy: 0, mag: TUNE.flickFull };
|
||||
const right = arm();
|
||||
assert.ok(right && right.x > 2, '...and mirrored right: x=' + (right ? right.x.toFixed(2) : 'none'));
|
||||
G.swipe = null; // bare tap, no gesture at all
|
||||
assert.equal(arm(), null, 'no swipe and no released flick: a flat return stamps no mark');
|
||||
});
|
||||
|
||||
test('a wounding point knocks the body down and it gets up MINUS the limb', () => {
|
||||
// The beat exists because the wound stage used to POP between points — an arm stopped being there
|
||||
// and nothing said why. The contract: the collapse wears the stage it STILL WAS, the rise wears
|
||||
|
||||
Reference in new issue
Block a user