From 2f9401e93f7a4bc2612d8ced3818308c981bdf91 Mon Sep 17 00:00:00 2001 From: Robert Garrett Date: Wed, 13 Aug 2025 11:58:11 -0500 Subject: [PATCH] Begin GameOver scene, widget spawner works I've taken a lot directly from the Bevy UI button example. (https://bevy.org/examples/ui-user-interface/button/) I'll make it look better later. For now, it just needs to exist. Onward to the UI operation system! --- src/config.rs | 4 +++ src/lib.rs | 3 +- src/widgets.rs | 75 +++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 80 insertions(+), 2 deletions(-) diff --git a/src/config.rs b/src/config.rs index 2041620..e6f195e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -5,6 +5,10 @@ use bevy::color::Color; pub const WINDOW_SIZE: bevy::prelude::Vec2 = bevy::prelude::Vec2::new(800.0, 600.0); +pub const UI_BUTTON_NORMAL: Color = Color::srgb(0.15, 0.15, 0.15); // Button color when it's just hanging out +pub const UI_BUTTON_HOVERED: Color = Color::srgb(0.25, 0.25, 0.25); // ... when it's hovered +pub const UI_BUTTON_PRESSED: Color = Color::srgb(0.35, 0.75, 0.35); // ... when it's pressed + pub(crate) const BACKGROUND_COLOR: Color = Color::srgb(0.3, 0.3, 0.3); pub(crate) const PLAYER_SHIP_COLOR: Color = Color::srgb(1.0, 1.0, 1.0); pub(crate) const SHIP_THRUSTER_COLOR_ACTIVE: Color = Color::srgb(1.0, 0.2, 0.2); diff --git a/src/lib.rs b/src/lib.rs index e174a83..16e78ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,6 +35,7 @@ impl Plugin for AsteroidPlugin { fn build(&self, app: &mut App) { app.add_plugins(( widgets::PluginGameMenu, + widgets::PluginGameOver, widgets::PluginGetReady, RapierPhysicsPlugin::::pixels_per_meter(10.0), RapierDebugRenderPlugin::default(), @@ -80,7 +81,7 @@ impl Plugin for AsteroidPlugin { .add_event::() .add_event::() .add_event::(); - app.insert_state(GameState::Playing); + app.insert_state(GameState::GameOver); } } diff --git a/src/widgets.rs b/src/widgets.rs index 6408ecc..06aeb75 100644 --- a/src/widgets.rs +++ b/src/widgets.rs @@ -1,5 +1,6 @@ use crate::{ GameState, + config::UI_BUTTON_NORMAL, resources::{Lives, Score}, }; @@ -42,7 +43,8 @@ pub struct PluginGameOver; impl Plugin for PluginGameOver { fn build(&self, app: &mut App) { - todo!(); + app.add_systems(OnEnter(GameState::GameOver), spawn_gameover_ui) + .add_systems(OnExit(GameState::GameOver), despawn::); } } @@ -50,6 +52,10 @@ impl Plugin for PluginGameOver { #[derive(Component)] struct OnReadySetGo; +/// Marker for things on the game-over screen +#[derive(Component)] +struct MarkerGameOver; + /// Newtype wrapper for `Timer`. Used to count down during the "get ready" phase. #[derive(Deref, DerefMut, Resource)] struct ReadySetGoTimer(Timer); @@ -104,6 +110,65 @@ fn spawn_get_ready(mut commands: Commands) { )); } +/// Spawns the game over screen. +/// +/// Used by [`PluginGameOver`] when entering the [`GameState::GameOver`] state. +fn spawn_gameover_ui(mut commands: Commands) { + commands.spawn(( + MarkerGameOver, // Marker, so `despawn` can remove this on state exit. + Node { + width: Val::Percent(100.0), + height: Val::Percent(100.0), + align_items: AlignItems::Center, + justify_content: JustifyContent::Center, + flex_direction: FlexDirection::Column, + ..default() + }, + children![ + ( + Button, + Node { + width: Val::Px(150.0), + height: Val::Px(65.0), + border: UiRect::all(Val::Px(2.0)), + justify_content: JustifyContent::Center, + align_items: AlignItems::Center, + margin: UiRect::all(Val::Px(5.0)), + ..default() + }, + BorderColor(Color::BLACK), + BorderRadius::MAX, + BackgroundColor(UI_BUTTON_NORMAL), + children![( + Text::new("Main Menu"), + TextColor(Color::srgb(0.9, 0.9, 0.9)), + TextShadow::default(), + )] + ), + ( + Button, + Node { + width: Val::Px(150.0), + height: Val::Px(65.0), + border: UiRect::all(Val::Px(2.0)), + justify_content: JustifyContent::Center, + align_items: AlignItems::Center, + margin: UiRect::all(Val::Px(5.0)), + ..default() + }, + BorderColor(Color::BLACK), + BorderRadius::MAX, + BackgroundColor(UI_BUTTON_NORMAL), + children![( + Text::new("Quit"), + TextColor(Color::srgb(0.9, 0.9, 0.9)), + TextShadow::default(), + )] + ) + ], + )); +} + fn animate_get_ready_widget( mut text_segment: Single<&mut Text, With>, mut bar_segment: Single<&mut Node, With>, @@ -129,6 +194,14 @@ fn animate_get_ready_widget( } } +/// Handles interaction and performs updates to the game over UI. +/// +/// Used by [`PluginGameOver`] while in the [`GameState::GameOver`] state. +/// +/// Mostly a button input handler, but it also makes for a convenient single +/// place to keep all system logic for this plugin. +fn operate_gameover_ui() {} + // Marker component for the title screen UI entity. // This way, a query for the TitleUI can be used to despawn the title screen #[derive(Component)]