fix(physics): restore the flipper downstroke
Represent press and release as distinct deferred flipper edges. Keep upward position/velocity transfer unchanged, and apply the position-preserving return-stroke velocity recovered from a live ball at `(125,390)`, mirrored for the right flipper. The downstroke now assigns raw `(3519,6302)` before the next physics clamp, matching the original instead of moving geometry silently. Test Plan: - `cargo test --all-targets` -- 48 passed - `cargo clippy --all-targets -- -D warnings` -- passed - `cargo build --profile production` -- passed - live downstroke transfer test -- passed within one raw unit - `git diff --cached --check` -- passed
This commit is contained in:
+30
-14
@@ -219,7 +219,7 @@ pub struct Game {
|
||||
launcher_velocity_milli: i32,
|
||||
player_entry: PlayerEntry,
|
||||
claw_rng_state: u32,
|
||||
pending_flipper_kicks: [bool; 2],
|
||||
pending_flipper_edges: [i8; 2],
|
||||
trigger_contacts: [bool; 176],
|
||||
object_active: [bool; 176],
|
||||
}
|
||||
@@ -257,7 +257,7 @@ impl Game {
|
||||
launcher_velocity_milli: 0,
|
||||
player_entry: PlayerEntry::Open,
|
||||
claw_rng_state: seed.max(1),
|
||||
pending_flipper_kicks: [false; 2],
|
||||
pending_flipper_edges: [0; 2],
|
||||
trigger_contacts: [false; 176],
|
||||
object_active: initial_object_activity(),
|
||||
}
|
||||
@@ -323,11 +323,11 @@ impl Game {
|
||||
self.flippers.right_raised = controls.right_flipper && !self.tilted;
|
||||
if self.flippers.left_raised != old_flippers.left_raised {
|
||||
events.push(Event::FlipperMove);
|
||||
self.pending_flipper_kicks[0] = self.flippers.left_raised;
|
||||
self.pending_flipper_edges[0] = if self.flippers.left_raised { 1 } else { -1 };
|
||||
}
|
||||
if self.flippers.right_raised != old_flippers.right_raised {
|
||||
events.push(Event::FlipperMove);
|
||||
self.pending_flipper_kicks[1] = self.flippers.right_raised;
|
||||
self.pending_flipper_edges[1] = if self.flippers.right_raised { 1 } else { -1 };
|
||||
}
|
||||
|
||||
if self.ball.in_launcher && !self.tilted {
|
||||
@@ -393,7 +393,7 @@ impl Game {
|
||||
|
||||
self.update_claw(dt, events);
|
||||
if self.claw.ball_suspended {
|
||||
self.pending_flipper_kicks.fill(false);
|
||||
self.pending_flipper_edges.fill(0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -720,13 +720,13 @@ impl Game {
|
||||
}
|
||||
|
||||
fn apply_flipper_kicks(&mut self) {
|
||||
let pending = self.pending_flipper_kicks;
|
||||
self.pending_flipper_kicks.fill(false);
|
||||
let pending = self.pending_flipper_edges;
|
||||
self.pending_flipper_edges.fill(0);
|
||||
if self.ball.in_launcher || self.tilted {
|
||||
return;
|
||||
}
|
||||
|
||||
for (should_kick, pivot, rest_tip, raised_tip, horizontal_sign) in [
|
||||
for (edge, pivot, rest_tip, raised_tip, horizontal_sign) in [
|
||||
(
|
||||
pending[0],
|
||||
LEFT_FLIPPER_PIVOT,
|
||||
@@ -742,13 +742,20 @@ impl Game {
|
||||
-1.0,
|
||||
),
|
||||
] {
|
||||
if !should_kick
|
||||
|| !point_in_flipper_sweep(self.ball.position, pivot, rest_tip, raised_tip)
|
||||
if edge == 0 || !point_in_flipper_sweep(self.ball.position, pivot, rest_tip, raised_tip)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let local_x = (self.ball.position.x - pivot.x) * horizontal_sign;
|
||||
let local_y = self.ball.position.y - pivot.y;
|
||||
if edge < 0 {
|
||||
let velocity_milli = MilliVec::from_millipixels(vec2(
|
||||
horizontal_sign * local_x * 159.95,
|
||||
local_x * 286.45,
|
||||
));
|
||||
self.ball.velocity = velocity_milli.to_velocity_per_second();
|
||||
continue;
|
||||
}
|
||||
let horizontal_displacement =
|
||||
0.002_12 * local_x.powi(2) - 0.125_68 * local_x + 14.921 - (local_y + 7.0);
|
||||
let vertical_displacement = -(local_x + 13.0);
|
||||
@@ -1271,7 +1278,7 @@ mod tests {
|
||||
game.ball.in_launcher = false;
|
||||
game.ball.position = vec2(125.0, 390.0);
|
||||
game.ball.velocity = Vec2::ZERO;
|
||||
game.pending_flipper_kicks[0] = true;
|
||||
game.pending_flipper_edges[0] = 1;
|
||||
|
||||
game.apply_flipper_kicks();
|
||||
let velocity_after_edge = game.ball.velocity;
|
||||
@@ -1279,7 +1286,7 @@ mod tests {
|
||||
let raw_velocity = MilliVec::from_velocity_per_second(velocity_after_edge);
|
||||
assert!((raw_velocity.x - 2_217).abs() <= 2);
|
||||
assert!((raw_velocity.y - -5_889).abs() <= 2);
|
||||
assert_eq!(game.pending_flipper_kicks, [false, false]);
|
||||
assert_eq!(game.pending_flipper_edges, [0, 0]);
|
||||
|
||||
game.apply_flipper_kicks();
|
||||
assert_eq!(
|
||||
@@ -1289,14 +1296,23 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returning_flipper_moves_and_sounds_without_queueing_a_kick() {
|
||||
fn returning_flipper_matches_the_live_downstroke_probe() {
|
||||
let mut game = Game::new(1);
|
||||
game.flippers.left_raised = true;
|
||||
|
||||
let events = game.update(0.0, 3, Controls::default());
|
||||
|
||||
assert_eq!(events, [Event::FlipperMove]);
|
||||
assert_eq!(game.pending_flipper_kicks, [false, false]);
|
||||
assert_eq!(game.pending_flipper_edges, [-1, 0]);
|
||||
game.ball.in_launcher = false;
|
||||
game.ball.position = vec2(125.0, 390.0);
|
||||
game.ball.velocity = Vec2::ZERO;
|
||||
game.apply_flipper_kicks();
|
||||
let raw_velocity = MilliVec::from_velocity_per_second(game.ball.velocity);
|
||||
assert!((raw_velocity.x - 3_519).abs() <= 1);
|
||||
assert!((raw_velocity.y - 6_302).abs() <= 1);
|
||||
assert_eq!(game.ball.position, vec2(125.0, 390.0));
|
||||
assert_eq!(game.pending_flipper_edges, [0, 0]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user