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!
This commit is contained in:
2025-08-13 11:58:11 -05:00
parent 54ef257ab4
commit 2f9401e93f
3 changed files with 80 additions and 2 deletions

View File

@@ -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);

View File

@@ -35,6 +35,7 @@ impl Plugin for AsteroidPlugin {
fn build(&self, app: &mut App) {
app.add_plugins((
widgets::PluginGameMenu,
widgets::PluginGameOver,
widgets::PluginGetReady,
RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(10.0),
RapierDebugRenderPlugin::default(),
@@ -80,7 +81,7 @@ impl Plugin for AsteroidPlugin {
.add_event::<events::AsteroidDestroy>()
.add_event::<events::ShipDestroy>()
.add_event::<events::BulletDestroy>();
app.insert_state(GameState::Playing);
app.insert_state(GameState::GameOver);
}
}

View File

@@ -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::<MarkerGameOver>);
}
}
@@ -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<T>` 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<CountdownText>>,
mut bar_segment: Single<&mut Node, With<CountdownBar>>,
@@ -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)]