Fix action drift during freeze states by parking ship and combat bodies
The level-up marquee, jump clip, and ack comm freezes gate world drivers but not physics: the Arcade world still steps, so coasting bodies kept gliding through the beat. Add _parkForFreeze() to zero ship velocity/acceleration and all enemy/ally body motion every frozen frame, killing any mid-freeze injection on the next tick.
This commit is contained in:
parent
098b41b2fc
commit
bb0005b5a5
|
|
@ -2627,7 +2627,26 @@ export class GameScene extends Phaser.Scene {
|
||||||
// The level-up marquee's freeze (js/ui/LevelUpMarquee.js): the beat
|
// The level-up marquee's freeze (js/ui/LevelUpMarquee.js): the beat
|
||||||
// owns the screen, so the action holds while it plays — the same
|
// owns the screen, so the action holds while it plays — the same
|
||||||
// rule as the ack pause, one frame of the world standing still.
|
// rule as the ack pause, one frame of the world standing still.
|
||||||
const _frozen = _commsPaused || this.levelMarquee?.active === true;
|
// The JUMP CLIP's freeze (GameScene._playJumpClip): the transport
|
||||||
|
// owns the screen (opaque backdrop + the gate video) for the clip's
|
||||||
|
// length, so the action holds the same way — the ship parks, the
|
||||||
|
// fight waits, the ticks stand down — and restart() lands the
|
||||||
|
// destination the moment it ends (the deadlines are time-based, so
|
||||||
|
// a project that finished mid-clip completes on the first tick
|
||||||
|
// after, exactly like the ack pause's completion path).
|
||||||
|
const _frozen =
|
||||||
|
_commsPaused || this.levelMarquee?.active === true || !!this._jumping;
|
||||||
|
// The freeze's PARKING (the ack pause's onPause is the same contract
|
||||||
|
// for its own freeze): while ANY freeze holds, the action is parked
|
||||||
|
// dead EVERY frame — the ship (target + throttle cleared, velocity
|
||||||
|
// and acceleration zeroed) and the combat actors' bodies. The Arcade
|
||||||
|
// world keeps stepping through a freeze (only the drivers —
|
||||||
|
// ship.update / combat.update — stand down), so anything that still
|
||||||
|
// injects motion (a coasting body, a collision response, a body that
|
||||||
|
// was set after the freeze began) is killed the very next frame.
|
||||||
|
// Resuming a freeze needs no work (the ship stays parked; the next
|
||||||
|
// input steers it again — the ack pause's same rule).
|
||||||
|
if (_frozen) this._parkForFreeze();
|
||||||
// The deck goes to STANDBY while an 'ack' comm holds (the pause
|
// The deck goes to STANDBY while an 'ack' comm holds (the pause
|
||||||
// contract's face): the slots dim and stop hovering/pressing, so the
|
// contract's face): the slots dim and stop hovering/pressing, so the
|
||||||
// pulsing ACKNOWLEDGE button is the only live control on screen.
|
// pulsing ACKNOWLEDGE button is the only live control on screen.
|
||||||
|
|
@ -2771,6 +2790,36 @@ export class GameScene extends Phaser.Scene {
|
||||||
if (!_frozen) this.updateDiscovery(_time, delta); // last: sees this frame's final camera view
|
if (!_frozen) this.updateDiscovery(_time, delta); // last: sees this frame's final camera view
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Park the action for a frozen frame (the level-up beat, the jump
|
||||||
|
* clip, the ack comm's pause — all three gate on _frozen in update
|
||||||
|
* above, and all three need this): the ship dead (stop() clears its
|
||||||
|
* target + throttle and zeros velocity/acceleration), and the combat
|
||||||
|
* actors' bodies zeroed too. The Arcade world still steps while the
|
||||||
|
* drivers (ship.update / combat.update) stand down, so un-parked
|
||||||
|
* bodies would keep gliding through the beat/clip — the visible
|
||||||
|
* "the action isn't actually paused" drift. Cheap + idempotent, so it
|
||||||
|
* runs every frozen frame (a velocity set mid-freeze dies next frame);
|
||||||
|
* resuming a freeze needs no work (the next input steers again).
|
||||||
|
*/
|
||||||
|
_parkForFreeze() {
|
||||||
|
try {
|
||||||
|
this.ship?.stop?.();
|
||||||
|
} catch {
|
||||||
|
/* the ship is optional (a scene mid-setup) — the park stands or falls with it */
|
||||||
|
}
|
||||||
|
const c = this.combat;
|
||||||
|
if (!c) return;
|
||||||
|
for (const list of [c.enemies, c.allies]) {
|
||||||
|
for (const a of list ?? []) {
|
||||||
|
const b = a?.body;
|
||||||
|
if (!b) continue;
|
||||||
|
if (typeof b.setVelocity === 'function') b.setVelocity(0, 0);
|
||||||
|
if (typeof b.setAcceleration === 'function') b.setAcceleration(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ship met the tether boundary: a small camera kick (impact), and a
|
* The ship met the tether boundary: a small camera kick (impact), and a
|
||||||
* console warning — throttled so a held push against the line doesn't
|
* console warning — throttled so a held push against the line doesn't
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue