fix(game): restore deliberate plunger charging
Advance the recovered eleven-frame plunger over a full one-second hold and use that same frame selection for rendering. This makes a short tap visibly and physically weaker while a complete pull still clears the shooter lane. Test Plan: - cargo fmt --check - cargo test - cargo clippy --all-targets --all-features -- -D warnings - git diff --check
This commit is contained in:
@@ -438,8 +438,6 @@ impl App {
|
||||
}
|
||||
}
|
||||
if game.ball.in_launcher {
|
||||
let frame = [0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95]
|
||||
.partition_point(|threshold| game.launcher_charge >= *threshold);
|
||||
draw_texture_ex(
|
||||
&self.assets.plunger,
|
||||
314.0,
|
||||
@@ -447,7 +445,12 @@ impl App {
|
||||
WHITE,
|
||||
DrawTextureParams {
|
||||
dest_size: Some(vec2(21.0, 18.0)),
|
||||
source: Some(Rect::new(frame as f32 * 21.0, 0.0, 20.0, 17.0)),
|
||||
source: Some(Rect::new(
|
||||
game.launcher_frame() as f32 * 21.0,
|
||||
0.0,
|
||||
20.0,
|
||||
17.0,
|
||||
)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
+39
-4
@@ -22,7 +22,12 @@ const BALL_SEARCH_DELAY: f32 = 3.0;
|
||||
const BALL_SEARCH_SPEED: f32 = 24.0;
|
||||
const TILT_THRESHOLD: f32 = 1.15;
|
||||
const LAUNCHER_POSITION: Vec2 = Vec2::new(325.0, 413.0);
|
||||
const LAUNCHER_CHARGE_SECONDS: f32 = 0.55;
|
||||
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];
|
||||
// The original advances resource 901 through repeated Down-key events. A
|
||||
// fixed duration keeps that deliberate hold consistent across modern systems
|
||||
// whose keyboard-repeat delay and rate differ.
|
||||
const LAUNCHER_CHARGE_SECONDS: f32 = 1.0;
|
||||
const LAUNCH_SPEED_MIN: f32 = 330.0;
|
||||
const LAUNCH_SPEED_RANGE: f32 = 100.0;
|
||||
|
||||
@@ -159,6 +164,10 @@ impl Game {
|
||||
&self.players[self.current_player]
|
||||
}
|
||||
|
||||
pub fn launcher_frame(&self) -> usize {
|
||||
LAUNCHER_FRAME_THRESHOLDS.partition_point(|threshold| self.launcher_charge >= *threshold)
|
||||
}
|
||||
|
||||
fn fire_launcher(&mut self) {
|
||||
let launch_speed = LAUNCH_SPEED_MIN + self.launcher_charge * LAUNCH_SPEED_RANGE;
|
||||
self.ball.in_launcher = false;
|
||||
@@ -185,7 +194,12 @@ impl Game {
|
||||
if self.ball.in_launcher && !self.tilted {
|
||||
if controls.launch_down {
|
||||
let charge_step = frame_time.min(0.05) / LAUNCHER_CHARGE_SECONDS;
|
||||
self.launcher_charge = (self.launcher_charge + charge_step).min(1.0);
|
||||
let next_charge = self.launcher_charge + charge_step;
|
||||
self.launcher_charge = if next_charge >= 1.0 - f32::EPSILON * 4.0 {
|
||||
1.0
|
||||
} else {
|
||||
next_charge
|
||||
};
|
||||
self.launcher_was_down = true;
|
||||
} else if self.launcher_was_down {
|
||||
self.fire_launcher();
|
||||
@@ -649,17 +663,38 @@ mod tests {
|
||||
let quick_speed = -quick.ball.velocity.y;
|
||||
|
||||
let mut charged = Game::new(1);
|
||||
launch_ball(&mut charged, 33);
|
||||
launch_ball(&mut charged, 60);
|
||||
let charged_speed = -charged.ball.velocity.y;
|
||||
|
||||
assert!(charged_speed > quick_speed + 80.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn maximum_launch_requires_a_deliberate_hold() {
|
||||
let mut game = Game::new(1);
|
||||
let held = Controls {
|
||||
launch_down: true,
|
||||
..Controls::default()
|
||||
};
|
||||
|
||||
for _ in 0..30 {
|
||||
game.update(1.0 / 60.0, 3, held);
|
||||
}
|
||||
assert!((0.45..0.55).contains(&game.launcher_charge));
|
||||
assert_eq!(game.launcher_frame(), 5);
|
||||
|
||||
for _ in 0..30 {
|
||||
game.update(1.0 / 60.0, 3, held);
|
||||
}
|
||||
assert!((game.launcher_charge - 1.0).abs() <= f32::EPSILON);
|
||||
assert_eq!(game.launcher_frame(), 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn charged_ball_clears_the_shooter_lane() {
|
||||
for detail in 1..=5 {
|
||||
let mut game = Game::new(1);
|
||||
launch_ball(&mut game, 33);
|
||||
launch_ball(&mut game, 60);
|
||||
let mut entered_table = false;
|
||||
let mut returned_to_launcher = false;
|
||||
let mut minimum_y = game.ball.position.y;
|
||||
|
||||
Reference in New Issue
Block a user