fix(render): restore animated playfield artwork
The gameplay renderer drew the inactive table and then placed thin line flippers and procedural circles over baked resting artwork. This left two flipper poses visible at once, made the ball difficult to see, and ignored recovered animation resources already embedded with the reconstruction. Build an alpha-masked texture from the original ball bitmap and mask, erase the baked flipper pose before drawing collision-aligned moving flippers, and animate the recovered wheel, robot, and magnet sheets from their gameplay events. Add bumper flashes, exact lit-table pixels for TILT, and a short visual table shake for nudges so contacts and machine state have immediate feedback. Test Plan: - `cargo fmt -- --check` -- passed - `cargo test --all-targets` -- passed - `cargo clippy --all-targets -- -D warnings` -- passed - launched the Linux window and inspected attract, gameplay, resting flippers, raised flipper cleanup, and the masked ball sprite -- passed - `git diff --check` -- passed
This commit is contained in:
+103
-18
@@ -384,6 +384,35 @@ impl App {
|
||||
return;
|
||||
};
|
||||
|
||||
if game.wheel_animation > 0.0 {
|
||||
let frame = animation_frame(f64::from(0.65 - game.wheel_animation), 18.0, 5);
|
||||
draw_texture_ex(
|
||||
&self.assets.wheel,
|
||||
80.0,
|
||||
49.0,
|
||||
WHITE,
|
||||
DrawTextureParams {
|
||||
dest_size: Some(vec2(68.0, 60.0)),
|
||||
source: Some(Rect::new(frame as f32 * 68.0, 0.0, 68.0, 60.0)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
if game.robot_animation > 0.0 {
|
||||
let frame = animation_frame(f64::from(1.0 - game.robot_animation), 14.0, 10);
|
||||
draw_texture_ex(
|
||||
&self.assets.robot,
|
||||
238.0,
|
||||
31.0,
|
||||
WHITE,
|
||||
DrawTextureParams {
|
||||
dest_size: Some(vec2(90.0, 74.0)),
|
||||
source: Some(Rect::new(frame as f32 * 90.0, 0.0, 90.0, 74.0)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
for (index, center) in [vec2(205.0, 47.0), vec2(234.0, 50.0), vec2(262.0, 53.0)]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
@@ -431,6 +460,15 @@ impl App {
|
||||
},
|
||||
);
|
||||
}
|
||||
for (index, center) in [vec2(207.0, 109.0), vec2(167.0, 148.0), vec2(219.0, 167.0)]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
{
|
||||
if game.bumper_flash[index] > 0.0 {
|
||||
draw_circle_lines(center.x, center.y, 17.0, 3.0, WHITE);
|
||||
draw_circle_lines(center.x, center.y, 13.0, 2.0, YELLOW);
|
||||
}
|
||||
}
|
||||
if game.player().diamond_segments > 0 {
|
||||
let index = usize::from(game.player().diamond_segments.min(9) - 1);
|
||||
draw_texture(&self.assets.diamond[index], 123.0, 298.0, WHITE);
|
||||
@@ -450,8 +488,27 @@ impl App {
|
||||
YELLOW,
|
||||
);
|
||||
}
|
||||
let frame = animation_frame(get_time(), 18.0, 10);
|
||||
draw_texture_ex(
|
||||
&self.assets.magnet,
|
||||
306.0,
|
||||
411.0,
|
||||
WHITE,
|
||||
DrawTextureParams {
|
||||
dest_size: Some(vec2(23.0, 17.0)),
|
||||
source: Some(Rect::new(frame as f32 * 23.0, 0.0, 23.0, 17.0)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
for (start, end) in [
|
||||
(vec2(103.0, 394.0), vec2(58.0, 374.0)),
|
||||
(vec2(211.0, 394.0), vec2(256.0, 374.0)),
|
||||
] {
|
||||
draw_line(start.x, start.y, end.x, end.y, 22.0, BLACK);
|
||||
draw_circle(start.x, start.y, 11.0, BLACK);
|
||||
}
|
||||
let (left, right) = game.flippers();
|
||||
for flipper in [left, right] {
|
||||
draw_line(
|
||||
@@ -459,36 +516,48 @@ impl App {
|
||||
flipper.start.y,
|
||||
flipper.end.x,
|
||||
flipper.end.y,
|
||||
10.0,
|
||||
DARKGRAY,
|
||||
18.0,
|
||||
Color::from_rgba(32, 32, 32, 255),
|
||||
);
|
||||
draw_line(
|
||||
flipper.start.x,
|
||||
flipper.start.y - 1.0,
|
||||
flipper.end.x,
|
||||
flipper.end.y - 1.0,
|
||||
6.0,
|
||||
12.0,
|
||||
LIGHTGRAY,
|
||||
);
|
||||
draw_circle(flipper.start.x, flipper.start.y, 6.0, GRAY);
|
||||
draw_line(
|
||||
flipper.start.x,
|
||||
flipper.start.y - 3.0,
|
||||
flipper.end.x,
|
||||
flipper.end.y - 3.0,
|
||||
3.0,
|
||||
WHITE,
|
||||
);
|
||||
draw_circle(flipper.start.x, flipper.start.y, 9.0, DARKGRAY);
|
||||
draw_circle(flipper.start.x, flipper.start.y - 1.0, 6.0, GRAY);
|
||||
}
|
||||
draw_circle(game.ball.position.x, game.ball.position.y, 6.0, DARKGRAY);
|
||||
draw_circle(
|
||||
game.ball.position.x - 1.0,
|
||||
game.ball.position.y - 1.0,
|
||||
4.5,
|
||||
LIGHTGRAY,
|
||||
);
|
||||
draw_circle(
|
||||
game.ball.position.x - 2.0,
|
||||
game.ball.position.y - 2.0,
|
||||
1.5,
|
||||
draw_texture(
|
||||
&self.assets.ball,
|
||||
game.ball.position.x - 8.0,
|
||||
game.ball.position.y - 8.0,
|
||||
WHITE,
|
||||
);
|
||||
|
||||
self.draw_displays(game);
|
||||
if game.tilted {
|
||||
draw_centered_at("TILT", 160.0, 263.0, 30, RED);
|
||||
draw_texture_ex(
|
||||
&self.assets.active_table,
|
||||
82.0,
|
||||
238.0,
|
||||
WHITE,
|
||||
DrawTextureParams {
|
||||
dest_size: Some(vec2(151.0, 33.0)),
|
||||
source: Some(Rect::new(82.0, 238.0, 151.0, 33.0)),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
draw_text("F1 HELP F2 SETUP", 345.0, 448.0, 11.0, BLACK);
|
||||
}
|
||||
@@ -636,10 +705,21 @@ impl App {
|
||||
let height = HEIGHT * scale;
|
||||
let x = (screen_width() - width) * 0.5;
|
||||
let y = (screen_height() - height) * 0.5;
|
||||
let shake = self.game.as_ref().map_or(Vec2::ZERO, |game| {
|
||||
if game.nudge_shake <= 0.0 {
|
||||
return Vec2::ZERO;
|
||||
}
|
||||
let strength = (game.nudge_shake / 0.18).min(1.0) * 2.5 * scale;
|
||||
let phase = game.nudge_shake * 950.0;
|
||||
vec2(
|
||||
phase.sin() * strength,
|
||||
(phase * 0.73).cos() * strength * 0.45,
|
||||
)
|
||||
});
|
||||
draw_texture_ex(
|
||||
&self.render_target.texture,
|
||||
x,
|
||||
y,
|
||||
x + shake.x,
|
||||
y + shake.y,
|
||||
WHITE,
|
||||
DrawTextureParams {
|
||||
dest_size: Some(vec2(width, height)),
|
||||
@@ -673,6 +753,11 @@ fn draw_panel(x: f32, y: f32, width: f32, height: f32) {
|
||||
draw_rectangle_lines(x + 4.0, y + 4.0, width - 8.0, height - 8.0, 2.0, DARKGRAY);
|
||||
}
|
||||
|
||||
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
|
||||
fn animation_frame(elapsed: f64, frames_per_second: f64, frame_count: usize) -> usize {
|
||||
((elapsed.max(0.0) * frames_per_second) as usize) % frame_count
|
||||
}
|
||||
|
||||
fn draw_centered(text: &str, baseline: f32, font_size: u16, color: Color) {
|
||||
draw_centered_at(text, WIDTH * 0.5, baseline, font_size, color);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user