Assist predicts the interception point instead of chasing the ball

Same predictive brain as the CPU: simulate the trajectory, run to where the
ball will be hittable (x and z), and drift back to home position after your
own shot. Full speed while chasing, 55% while recovering.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Fable 5 committed 2026-07-11 10:45:36 +02:00
1 parent 9268529c8f
commit d69896ddb8
1 file changed
+20 -17
+20 -17
View File
@@ -321,21 +321,24 @@ function onBounce() {
let phaseWasServe = false; let phaseWasServe = false;
// ---------------------------------------------------------------- update ---- // ---------------------------------------------------------------- update ----
// Where should the AI run to? Simulate the ball forward and take the first point // Where should a player run to? Simulate the ball forward and take the first point
// in its half where the ball is at comfortable hitting height. // in their half where the ball is at comfortable hitting height.
function aiIntercept() { function intercept(side) {
let { x, y, z, vx, vy, vz } = ball; let { x, y, z, vx, vy, vz } = ball;
const g = TUNE.gravity, dt = 0.01; const g = TUNE.gravity, dt = 0.01;
const inZone = side === 'O' ? zz => zz <= 9.5 : zz => zz >= COURT.L - 9.5;
const home = side === 'O' ? { x: 0, z: 2.5 } : { x: 0, z: 22.8 };
let fallback = null; let fallback = null;
for (let i = 0; i < 240; i++) { for (let i = 0; i < 240; i++) {
vy -= g * dt; x += vx * dt; y += vy * dt; z += vz * dt; vy -= g * dt; x += vx * dt; y += vy * dt; z += vz * dt;
if (y <= 0 && vy < 0) { y = 0; vy = -vy * TUNE.bounceY; vx *= TUNE.bounceXZ; vz *= TUNE.bounceXZ; } if (y <= 0 && vy < 0) { y = 0; vy = -vy * TUNE.bounceY; vx *= TUNE.bounceXZ; vz *= TUNE.bounceXZ; }
if (i > 5 && z <= 9.5 && y < 1.6) { if (i > 5 && inZone(z) && y < 1.6) {
if (y > 0.7) return { x, z: Math.max(0.8, z) }; // waist-high contact preferred const pt = { x, z: side === 'O' ? Math.max(0.8, z) : Math.min(24.5, z) };
if (y > 0.3 && !fallback) fallback = { x, z: Math.max(0.8, z) }; if (y > 0.7) return pt; // waist-high contact preferred
if (y > 0.3 && !fallback) fallback = pt;
} }
} }
return fallback || { x: 0, z: 2.5 }; return fallback || home;
} }
function trySwing(ch, isAI) { function trySwing(ch, isAI) {
@@ -397,15 +400,15 @@ function update(dt) {
P.x += mx * TUNE.playerSpeed * slow * dt; P.x += mx * TUNE.playerSpeed * slow * dt;
P.z += mz * TUNE.playerSpeed * slow * dt; P.z += mz * TUNE.playerSpeed * slow * dt;
let assist = 0; let assist = 0;
if (!mx && !mz && TUNE.autoAssist > 0 && ball.active && ball.lastHit === 'O') { if (!mx && !mz && TUNE.autoAssist > 0 && ball.active) {
const rate = TUNE.playerSpeed * TUNE.autoAssist * slow * dt; const chasing = ball.lastHit === 'O';
const dx = ball.x - P.x; // run toward the incoming ball so one thumb suffices const rate = TUNE.playerSpeed * TUNE.autoAssist * slow * dt * (chasing ? 1 : 0.55);
assist = Math.sign(dx) * Math.min(Math.abs(dx), rate); const tgt = chasing ? intercept('P') : { x: 0, z: 22.8 }; // run to the ball, then recover home
P.x += assist; const dx = tgt.x - P.x, dz = tgt.z - P.z, d = Math.hypot(dx, dz);
if (ball.bounces > 0) { // ball on our side: also close the depth gap if (d > 0.05) {
const dz = Math.max(COURT.netZ + 1.5, Math.min(24.5, ball.z)) - P.z; P.x += dx / d * Math.min(rate, d);
P.z += Math.sign(dz) * Math.min(Math.abs(dz), rate); P.z += dz / d * Math.min(rate, d);
if (!assist) assist = dz; assist = dx || 0.01;
} }
} }
P.x = Math.max(-6.5, Math.min(6.5, P.x)); P.x = Math.max(-6.5, Math.min(6.5, P.x));
@@ -428,7 +431,7 @@ function update(dt) {
} }
if (phase === 'rally') { if (phase === 'rally') {
const incoming = ball.active && ball.lastHit === 'P'; const incoming = ball.active && ball.lastHit === 'P';
const tgt = incoming ? aiIntercept() : { x: 0, z: 2.5 }; const tgt = incoming ? intercept('O') : { x: 0, z: 2.5 };
const dx = tgt.x - O.x, dz = tgt.z - O.z, d = Math.hypot(dx, dz); const dx = tgt.x - O.x, dz = tgt.z - O.z, d = Math.hypot(dx, dz);
if (d > 0.1) { if (d > 0.1) {
O.x += dx / d * Math.min(TUNE.aiSpeed * dt, d); O.x += dx / d * Math.min(TUNE.aiSpeed * dt, d);