fix(input): restore launcher press and release impulses

The rewrite used a 375-millipixel impulse for both charging and release. The
reconstructed key handlers use the setup scalar 15: every repeated Down keydown
subtracts 15*50, and release subtracts a further 15*100 before clamping.

Use 750-millipixel press increments and the 1,500-millipixel release impulse,
then reproduce the randomized -3800 lower clamp and weak -2280 upper branch.
Derive the ten launcher decoration frames from the original strict multiples of
750 and keep integration/gravity assertions separate from the immediate release
state.

Test Plan:
- `cargo test --all-targets` -- passed, 60 tests
- `cargo clippy --all-targets -- -D warnings` -- passed
- `rumdl check tdkpin-rs/CHANGELOG.md tdkpin-rs/RECONSTRUCTION.md` -- passed
- `git diff --cached --check` -- passed
This commit is contained in:
2026-08-23 17:03:35 +02:00
parent 2f7e29b6a4
commit c1d8e5755f
4 changed files with 41 additions and 14 deletions
+36 -12
View File
@@ -20,9 +20,8 @@ const RIGHT_FLIPPER_PIVOT: Vec2 = Vec2::new(210.0, 397.0);
const RIGHT_FLIPPER_REST_TIP: Vec2 = Vec2::new(179.0, 419.0);
const RIGHT_FLIPPER_RAISED_TIP: Vec2 = Vec2::new(181.0, 376.0);
const LAUNCHER_POSITION: Vec2 = Vec2::new(325.0, 413.0);
const LAUNCHER_FRAME_THRESHOLDS: [f32; 10] =
[0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95];
const LAUNCHER_IMPULSE_MILLI: i32 = 375;
const LAUNCHER_PRESS_IMPULSE_MILLI: i32 = 750;
const LAUNCHER_RELEASE_IMPULSE_MILLI: i32 = 1_500;
const LAUNCHER_REPEAT_DELAY_SECONDS: f32 = 0.650;
const LAUNCHER_REPEAT_SECONDS: f32 = 0.040;
const CLAW_TRIGGER_CENTER: Vec2 = Vec2::new(289.0, 94.0);
@@ -333,7 +332,15 @@ impl Game {
}
pub fn launcher_frame(&self) -> usize {
LAUNCHER_FRAME_THRESHOLDS.partition_point(|threshold| self.launcher_charge >= *threshold)
if !self.launcher_was_down {
return 0;
}
(1..=10)
.find(|multiple| {
-LAUNCHER_PRESS_IMPULSE_MILLI * i32::try_from(*multiple).unwrap_or(10)
< self.launcher_velocity_milli
})
.unwrap_or(10)
}
pub fn add_player_before_launch(&mut self) -> bool {
@@ -354,11 +361,15 @@ impl Game {
}
fn fire_launcher(&mut self) {
self.launcher_velocity_milli -= LAUNCHER_IMPULSE_MILLI;
self.launcher_velocity_milli = self
.launcher_velocity_milli
.wrapping_sub(LAUNCHER_RELEASE_IMPULSE_MILLI);
let mut launch_velocity = self.launcher_velocity_milli;
if launch_velocity < -MAXIMUM_SPEED_MILLI_PER_STEP {
let variation = self.random.below(3_800) / 40;
launch_velocity = -MAXIMUM_SPEED_MILLI_PER_STEP + i32::from(variation);
} else if launch_velocity > -2_280 {
launch_velocity = launch_velocity.wrapping_sub(i32::from(self.random.below(3_800) / 40));
}
self.ball.in_launcher = false;
self.ball.velocity = MilliVec {
@@ -401,11 +412,15 @@ impl Game {
if self.launcher_was_down {
self.launcher_hold_seconds += frame_time.min(0.05);
while self.launcher_hold_seconds >= self.launcher_next_repeat {
self.launcher_velocity_milli -= LAUNCHER_IMPULSE_MILLI;
self.launcher_velocity_milli = self
.launcher_velocity_milli
.wrapping_sub(LAUNCHER_PRESS_IMPULSE_MILLI);
self.launcher_next_repeat += LAUNCHER_REPEAT_SECONDS;
}
} else {
self.launcher_velocity_milli -= LAUNCHER_IMPULSE_MILLI;
self.launcher_velocity_milli = self
.launcher_velocity_milli
.wrapping_sub(LAUNCHER_PRESS_IMPULSE_MILLI);
self.launcher_was_down = true;
}
let charge_milli =
@@ -1392,11 +1407,20 @@ mod tests {
#[test]
fn holding_the_launcher_produces_a_faster_shot() {
let mut quick = Game::new(1);
launch_ball(&mut quick, 1);
let mut quick = Game::new_with_seed(1, 7);
let held = Controls {
launch_down: true,
..Controls::default()
};
quick.update(0.0, 3, held);
quick.update(0.0, 3, Controls::default());
let quick_speed = -quick.ball.velocity.y;
assert_eq!(
MilliVec::from_velocity_per_second(quick.ball.velocity),
MilliVec { x: 0, y: -2_270 }
);
let mut charged = Game::new(1);
let mut charged = Game::new_with_seed(1, 7);
launch_ball(&mut charged, 60);
let charged_speed = -charged.ball.velocity.y;
@@ -1414,8 +1438,8 @@ mod tests {
for _ in 0..30 {
game.update(1.0 / 60.0, 3, held);
}
assert!((0.09..0.11).contains(&game.launcher_charge));
assert_eq!(game.launcher_frame(), 1);
assert!((0.19..0.21).contains(&game.launcher_charge));
assert_eq!(game.launcher_frame(), 2);
for _ in 0..30 {
game.update(1.0 / 60.0, 3, held);
+1 -1
View File
@@ -409,7 +409,7 @@ mod tests {
let mut simulation = Simulation::new(Scenario::Launcher, 1);
simulation.advance_to(60);
assert!(simulation.game.ball.in_launcher);
assert!((0.09..=0.11).contains(&simulation.game.launcher_charge));
assert!((0.19..=0.21).contains(&simulation.game.launcher_charge));
simulation.advance_to(121);
assert!(!simulation.game.ball.in_launcher);