The relative lane is vetoed; an aimed ball never lands on the wrong side of you
'No that's way too difficult now - I am dying constantly of out. revert it.' aimAnchor is gone — the lane is absolute again, every out invariant back exactly as tuned. What survives is the answer to his follow-up: the ball sometimes flew a LITTLE RIGHT out of a left flick, because a mistimed left flick's target sits only slightly left of CENTRE — which is right of a player standing in the left service box. The absolute lane's blind spot, stated the other way round. The aimed target is now clamped to the player's own x on the flicked side, bounded at flickWidth so a body parked in the alley clamps to the corner rather than conjuring an out. From the left box a left flick goes at least down your own line, from centre it can no longer cross centre, a perfect corner flick and the crosscourt sweep are untouched, and the outward scatter tail keeps the whole tuned out-risk. Verified in his scene: ten rushed weak left flicks land -2.0..-2.7 where the same case used to target -0.7..-1.3 (a visibly rightward flight); the clean full flick still lands -3.92. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
7e5c3ab399
commit
4052ab1404
5 files changed
+54
-54
No files matched your search
@@ -876,38 +876,30 @@ test('an aimed shot keeps its DIRECTION: scatter may push it wider, never back p
|
||||
'aimTrust*aimError must stay under a committed swipe\'s worst-case aim');
|
||||
});
|
||||
|
||||
test('the flick aims RELATIVE TO THE PLAYER: a full sweep from where you stand, not from centre', () => {
|
||||
// Third round of the service-line report: the lane was absolute, so standing near a sideline
|
||||
// saturated the gesture — from the left box a perfect left flick moved the ball under 2 m and
|
||||
// could never find the line ("no matter how hard/good I flick"). The anchor follows the player
|
||||
// as the swipe commits (TUNE.aimAnchor); a flat tap keeps its old centre default.
|
||||
startMatch();
|
||||
G.modal = null; G.modalQ.length = 0;
|
||||
const arm = (px, swipe) => { // one rally ball, contact at the window's centre
|
||||
G.interlude.introT = 0; G.phase = 'rally';
|
||||
P.x = px; P.z = 22.8; P.swingT = -1; G.placeMark = null;
|
||||
ball.active = true; ball.lastHit = 'O'; ball.bounces = 1;
|
||||
ball.x = px; ball.y = 0.7; ball.z = P.z - 4.15;
|
||||
ball.vx = 0; ball.vy = 2.0; ball.vz = 14; ball.g = TUNE.gravity;
|
||||
G.swipe = swipe;
|
||||
keyPressed('Space');
|
||||
for (let i = 0; i < 30 && ball.lastHit !== 'P'; i++) update(DT);
|
||||
assert.equal(ball.lastHit, 'P', 'contact happened');
|
||||
G.swipe = null;
|
||||
return G.placeMark;
|
||||
test('an aimed ball never lands on the WRONG SIDE of you', () => {
|
||||
// The absolute lane's blind spot: a mistimed left flick's target sits only slightly left of
|
||||
// CENTRE — which is RIGHT of a player standing in the left box, so the ball visibly flew right
|
||||
// out of a left flick. (The fully relative lane that fixed this harder was feel-vetoed the same
|
||||
// day: "way too difficult now, I am dying constantly of out".) Model mirrors doHit's lane path.
|
||||
const land = (px, s, q, u) => {
|
||||
const reach = TUNE.flickReach + (1 - TUNE.flickReach) * q;
|
||||
let e = u * TUNE.aimError * (1 - q);
|
||||
if (s && e * Math.sign(s) < 0) e *= TUNE.aimTrust;
|
||||
let tx = s * TUNE.flickWidth * reach + e;
|
||||
const bound = Math.max(-TUNE.flickWidth, Math.min(TUNE.flickWidth, px));
|
||||
return s < 0 ? Math.min(tx, bound) : Math.max(tx, bound);
|
||||
};
|
||||
const full = fx => ({ ax: Math.sign(fx), az: 0, fx, fy: 0, mag: TUNE.flickFull });
|
||||
const line = COURT.W / 2;
|
||||
// from the LEFT service box, a committed left flick reaches PAST the line — out is aimable now
|
||||
const left = arm(-2, full(-1));
|
||||
assert.ok(left && left.x < -line, 'full left flick from the left box finds the alley: x=' + left.x.toFixed(2));
|
||||
// ...and a right flick from the same spot lands a full sweep right OF THE PLAYER, near centre-right
|
||||
const right = arm(-2, full(1));
|
||||
assert.ok(right && right.x > 1.2 && right.x < 2.8, 'full right flick sweeps from the player: x=' + right.x.toFixed(2));
|
||||
// an unaimed tap is untouched by where you stand: no mark, and the ball heads for the centre
|
||||
assert.equal(arm(-2, null), null, 'a flat tap from the box stamps no mark, exactly as before');
|
||||
assert.ok(Math.abs(ball.vx * ((3 - ball.z) / ball.vz) + ball.x) < TUNE.aimError + 1,
|
||||
'and its line stays the old centre default, not the player lane');
|
||||
for (let q = 0; q <= 1; q += 0.25) for (const u of [-1, 0, 1]) for (const s of [-0.2, -0.6, -1]) {
|
||||
assert.ok(land(-2, s, q, u) <= -2, 'a left flick from the left box never crosses the player: '
|
||||
+ land(-2, s, q, u).toFixed(2) + ' at s=' + s + ' q=' + q + ' u=' + u);
|
||||
assert.ok(land(0, s, q, u) <= 0, '...and from centre it never crosses centre');
|
||||
}
|
||||
assert.equal(land(-2, -1, 1, 0), -TUNE.flickWidth, 'a perfect corner flick is untouched by the guard');
|
||||
assert.equal(land(2, -1, 1, 0), -TUNE.flickWidth, 'crosscourt from the right box keeps its full sweep');
|
||||
// the guard can never conjure an out: the bound is capped inside the line
|
||||
assert.ok(TUNE.flickWidth < COURT.W / 2, 'flickWidth stays inside the singles line');
|
||||
assert.ok(Math.abs(Math.max(-TUNE.flickWidth, Math.min(TUNE.flickWidth, -6.5))) <= TUNE.flickWidth,
|
||||
'a body parked in the alley clamps to the corner, not past the line');
|
||||
});
|
||||
|
||||
test('the flick aims from the LIVE swipe: contact reads G.swipe, no release needed', () => {
|
||||
|
||||
Reference in new issue
Block a user