feat(game): implement pause system with Escape key and visual overlay

This commit is contained in:
2025-12-29 01:03:06 -06:00
parent d320f2b01b
commit 949899b035
4 changed files with 31 additions and 7 deletions
+3 -3
View File
@@ -541,9 +541,9 @@ impl Game {
))
.configure_sets((
GameplaySet::Input,
GameplaySet::Update.run_if(|paused: Res<PauseState>| paused.active()),
GameplaySet::Respond.run_if(|paused: Res<PauseState>| paused.active()),
RenderSet::Animation.run_if(|paused: Res<PauseState>| paused.active()),
GameplaySet::Update.run_if(|paused: Res<PauseState>| !paused.active()),
GameplaySet::Respond.run_if(|paused: Res<PauseState>| !paused.active()),
RenderSet::Animation.run_if(|paused: Res<PauseState>| !paused.active()),
RenderSet::Draw,
RenderSet::Present,
));
+26 -1
View File
@@ -1,11 +1,12 @@
use crate::constants;
use crate::error::{GameError, TextureError};
use crate::systems::{BackbufferResource, GameStage, ScoreResource, StartupSequence};
use crate::systems::{BackbufferResource, GameStage, PauseState, ScoreResource, StartupSequence};
use crate::texture::sprite::SpriteAtlas;
use crate::texture::text::TextTexture;
use bevy_ecs::event::EventWriter;
use bevy_ecs::system::{NonSendMut, Res};
use sdl2::pixels::Color;
use sdl2::rect::Rect;
use sdl2::render::Canvas;
use sdl2::video::Window;
@@ -17,6 +18,7 @@ pub fn hud_render_system(
mut atlas: NonSendMut<SpriteAtlas>,
score: Res<ScoreResource>,
stage: Res<GameStage>,
pause_state: Res<PauseState>,
mut errors: EventWriter<GameError>,
) {
let _ = canvas.with_texture_canvas(&mut backbuffer.0, |canvas| {
@@ -82,5 +84,28 @@ pub fn hud_render_system(
}
}
}
// Render pause overlay when game is paused (allowed during any stage)
if pause_state.active() {
// Enable blending for transparency
canvas.set_blend_mode(sdl2::render::BlendMode::Blend);
// Draw semi-transparent black overlay
canvas.set_draw_color(Color::RGBA(0, 0, 0, 160));
let _ = canvas.fill_rect(Rect::new(0, 0, constants::CANVAS_SIZE.x, constants::CANVAS_SIZE.y));
// Render "PAUSED" text centered and larger (2.5x scale)
let mut paused_renderer = TextTexture::new(2.5);
let paused_text = "PAUSED";
let paused_width = paused_renderer.text_width(paused_text);
let paused_height = paused_renderer.text_height();
let paused_position = glam::UVec2::new(
(constants::CANVAS_SIZE.x - paused_width) / 2,
(constants::CANVAS_SIZE.y - paused_height) / 2
);
if let Err(e) = paused_renderer.render_with_color(canvas, &mut atlas, paused_text, paused_position, Color::YELLOW) {
errors.write(TextureError::RenderFailed(format!("Failed to render PAUSED text: {}", e)).into());
}
}
});
}
+1 -2
View File
@@ -81,7 +81,7 @@ impl Default for Bindings {
key_bindings.insert(Keycode::D, GameCommand::MovePlayer(Direction::Right));
// Game actions
key_bindings.insert(Keycode::P, GameCommand::TogglePause);
key_bindings.insert(Keycode::Escape, GameCommand::TogglePause);
key_bindings.insert(Keycode::Space, GameCommand::ToggleDebug);
key_bindings.insert(Keycode::M, GameCommand::MuteAudio);
key_bindings.insert(Keycode::R, GameCommand::ResetLevel);
@@ -89,7 +89,6 @@ impl Default for Bindings {
#[cfg(not(target_os = "emscripten"))]
{
key_bindings.insert(Keycode::Escape, GameCommand::Exit);
key_bindings.insert(Keycode::Q, GameCommand::Exit);
// Desktop-only fullscreen toggle
key_bindings.insert(Keycode::F, GameCommand::ToggleFullscreen);
+1 -1
View File
@@ -68,7 +68,7 @@ pub enum PauseState {
impl Default for PauseState {
fn default() -> Self {
Self::Active { remaining_ticks: None }
Self::Inactive
}
}