Stop the dead for the changeover instead of letting the player wander
Oliver vetoed the free movement between points on sight: he never walks freely during play, so being able to only between points reads as the game breaking, not as a fix. Reverted to 'rally' only, and the rule is written into the settled-feel list so it doesn't get re-invented. The frozen changeover is answered his other way instead — the dead wait too. `held` in updateZombies stops their advance, their steering and the eat check for the breather; they still bleed and burn, they just stand there, because the umpire called time and it is still a tennis match. The path where this actually bit: losing a duel scheduled on a changeover beat spawns five fresh shamblers and THEN starts five seconds you have no agency in. The stuck pose was never about movement — 'run' is the one pose expirePose doesn't expire, and runT stops advancing outside the block, so a beat that began mid-stride welded him to a single frame. Reset it and it's fixed for every phase. And he could walk off the screen in ordinary play, not just during the beat I had added: P_BOUNDS.x is 6.5 m, portrait shows about ±4 m at the baseline. The xVis clamp already existed but only applied during auto-fire; it now always applies, floored at the sideline so every legal ball stays catchable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e00886f57e
commit
79fb43f60d
4 files changed
+68
-23
No files matched your search
+14
-6
@@ -814,11 +814,11 @@ export function update(dt) {
|
||||
if (G.phase === 'toss' && !G.aim) { const sv = score.server === 'P' ? P : O; sv.pose = 'serve'; sv.poseT = 0; }
|
||||
|
||||
// --- player movement (near half only, generous margins)
|
||||
// In splatter it also runs between points ('over' — game beats, changeovers, set cards — and
|
||||
// 'pretoss'): the zombies never stop walking, so gating movement on 'rally' froze the player
|
||||
// mid-stride with the dead closing in, and left him stuck in whatever pose he held. 'toss' is
|
||||
// the one exception — that's the aim, and the thumb is busy drawing the bow.
|
||||
if (G.phase === 'rally' || (G.mode === 'splatter' && G.phase !== 'toss')) {
|
||||
// 'rally' ONLY, deliberately. Letting the player walk during the between-point beats was tried
|
||||
// and vetoed on feel: you never walk freely during play, so suddenly being able to between points
|
||||
// reads as the game breaking, not as a fix. The frozen-changeover complaint is answered by
|
||||
// holding the DEAD instead (see updateZombies), and the stuck pose by the reset below.
|
||||
if (G.phase === 'rally') {
|
||||
if (G.mode === 'tennis' && ball.active && ball.lastHit === 'O') { // closest approach, for never-swung passes
|
||||
const d = Math.hypot(ball.x - P.x, (ball.z - P.z) * 0.8);
|
||||
if (!G.rallyNear || d < G.rallyNear.d) G.rallyNear = { d, y: ball.y, bz: ball.z, px: P.x, pz: P.z };
|
||||
@@ -854,7 +854,11 @@ export function update(dt) {
|
||||
assist = dx;
|
||||
}
|
||||
}
|
||||
const xLim = mgMode ? xVis : P_BOUNDS.x; // auto-fire keeps even keyboard players on screen
|
||||
// Stay ON SCREEN — always, not just in auto-fire. P_BOUNDS.x is 6.5 m, but at the baseline in
|
||||
// portrait the camera only shows about ±4 m either side of the centre line, so walking to the
|
||||
// bound put the player clean off the edge (x = -6.5 projects to screen -61 of 270). Floored at
|
||||
// the sideline so every legal tennis ball stays catchable — the court is never out of bounds.
|
||||
const xLim = Math.max(xVis, COURT.W / 2);
|
||||
P.x = Math.max(-xLim, Math.min(xLim, P.x));
|
||||
P.z = Math.max(P_BOUNDS.zMin, Math.min(P_BOUNDS.zMax, P.z));
|
||||
const moving = mx || mz || assist !== 0;
|
||||
@@ -863,6 +867,10 @@ export function update(dt) {
|
||||
if (mx) P.facing = mx > 0 ? 1 : -1;
|
||||
else if (Math.abs(assist) > 0.25) P.facing = assist > 0 ? 1 : -1; // hysteresis: small corrections don't flip facing
|
||||
}
|
||||
// ...and out of 'rally' he STANDS. 'run' is the one pose nothing else expires (expirePose only
|
||||
// handles swing/serve), and P.runT stops advancing outside the block, so a beat that began
|
||||
// mid-stride left him welded to a single run frame — the "stuck mid-animation" report.
|
||||
else if (P.pose === 'run') { P.pose = 'idle'; P.poseT = 0; }
|
||||
// splatter: you START at the baseline but you're free to advance up-court (bounded at the net by
|
||||
// P_BOUNDS) — hunt the shamblers down, especially when mopping up a won game. Auto-assist still
|
||||
// recovers you toward the baseline between shots on touch; the duel is plain tennis as ever.
|
||||
|
||||
Reference in new issue
Block a user