diff --git a/src/credits.rs b/src/credits.rs index 6cf40d6..531d24f 100644 --- a/src/credits.rs +++ b/src/credits.rs @@ -23,6 +23,7 @@ fn init_credits_ui(mut commands: Commands) { justify_content: JustifyContent::Center, align_items: AlignItems::Center, position_type: PositionType::Absolute, + flex_direction: FlexDirection::Column, ..default() }, visibility: Visibility::Hidden, @@ -32,16 +33,59 @@ fn init_credits_ui(mut commands: Commands) { .with_children(|parent| { parent.spawn(( Credits, - TextBundle { - text: Text { - alignment: TextAlignment::Center, - sections: vec![], + NodeBundle { + style: Style { + padding: UiRect::all(Val::Px(25.0)), ..default() }, background_color: Color::BLACK.with_a(0.5).into(), ..default() - }, - )); + } + )).with_children(|parent| { + parent.spawn(( + Credits, + TextBundle { + text: Text { + alignment: TextAlignment::Center, + sections: vec![], + ..default() + }, + ..default() + }, + )); + }); + + parent + .spawn(( + menu::ButtonAction(GameState::Play), + menu::ButtonAction(menu::MenuState::Play), + ButtonBundle { + style: Style { + padding: UiRect::all(Val::Px(5.0)), + margin: UiRect::all(Val::Px(5.0)), + ..default() + }, + background_color: Color::ORANGE.with_a(0.5).into(), + ..default() + }, + )) + .with_children(|parent| { + parent.spawn(TextBundle { + text: Text { + sections: vec![TextSection { + value: "Back".into(), + style: TextStyle { + color: Color::BLACK, + font_size: 32.0, + ..default() + }, + }], + ..default() + }, + ..default() + }); + }); + }); } diff --git a/src/game.rs b/src/game.rs index 2a6654b..ee0448f 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,3 +1,4 @@ +use bevy::app::AppExit; use bevy::utils::HashSet; use crate::audio::AudioEvent; @@ -44,7 +45,8 @@ impl Plugin for GamePlugin { .add_systems( PostUpdate, (debug_board.run_if(resource_exists::()),), - ); + ) + .add_systems(OnEnter(GameState::Quit), handle_quit); } } @@ -842,3 +844,11 @@ fn reset_game( .remove::(); }); } + + +/// Very simple system to handle the "Quit" state (shutdown the game) +fn handle_quit( + mut app_exit_events: EventWriter, +) { + app_exit_events.send(AppExit); +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 6b7c051..722be62 100644 --- a/src/main.rs +++ b/src/main.rs @@ -74,6 +74,8 @@ pub enum GameState { Intro, Play, Endgame, + Restart, + Quit, } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States, Component)] diff --git a/src/menu.rs b/src/menu.rs index 0076ab5..bf9b691 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -1,5 +1,3 @@ -use bevy::app::AppExit; - use crate::prelude::*; use self::tutorial::TutorialState; @@ -19,16 +17,17 @@ impl Plugin for MenuPlugin { Update, manage_state_entities::().run_if(state_changed::()), ) - .add_systems( - Update, - handle_button_press.run_if(any_component_changed::()), - ) + .add_systems(Update, ( + handle_button_press::, + handle_button_press::, + handle_button_press::, + ).run_if(any_component_changed::())) .add_systems(Update, set_menu_state.run_if(just_pressed(KeyCode::Escape))); } } #[derive(Debug, States, Hash, Default, PartialEq, Eq, Clone, Component)] -enum MenuState { +pub(crate) enum MenuState { #[default] None, Play, @@ -37,13 +36,7 @@ enum MenuState { } #[derive(Debug, Component)] -enum ButtonAction { - GameState(GameState), - MenuState(MenuState), - TutorialState(tutorial::TutorialState), - Restart, - Quit, -} +pub(crate) struct ButtonAction(pub S); fn init_play_menu(mut commands: Commands) { info!("Initializing Play menu"); @@ -80,7 +73,8 @@ fn init_play_menu(mut commands: Commands) { // Continue button parent .spawn(( - ButtonAction::MenuState(MenuState::None), + ButtonAction(GameState::Play), + ButtonAction(MenuState::None), ButtonBundle { style: Style { padding: UiRect::all(Val::Px(5.0)), @@ -105,7 +99,8 @@ fn init_play_menu(mut commands: Commands) { // Tutorial button parent .spawn(( - ButtonAction::TutorialState(tutorial::TutorialState::Intro), + ButtonAction(tutorial::TutorialState::Intro), + ButtonAction(MenuState::None), ButtonBundle { style: Style { padding: UiRect::all(Val::Px(5.0)), @@ -130,7 +125,8 @@ fn init_play_menu(mut commands: Commands) { // Credits button parent .spawn(( - ButtonAction::GameState(GameState::Credits), + ButtonAction(GameState::Credits), + ButtonAction(MenuState::None), ButtonBundle { style: Style { padding: UiRect::all(Val::Px(5.0)), @@ -155,7 +151,8 @@ fn init_play_menu(mut commands: Commands) { // Quit button parent .spawn(( - ButtonAction::Quit, + ButtonAction(GameState::Quit), + ButtonAction(MenuState::None), ButtonBundle { style: Style { padding: UiRect::all(Val::Px(5.0)), @@ -202,7 +199,8 @@ fn init_tutorial_menu(mut commands: Commands) { // Continue button parent .spawn(( - ButtonAction::MenuState(MenuState::None), + ButtonAction(GameState::Play), + ButtonAction(MenuState::None), ButtonBundle { style: Style { padding: UiRect::all(Val::Px(5.0)), @@ -227,7 +225,8 @@ fn init_tutorial_menu(mut commands: Commands) { // Quit button parent .spawn(( - ButtonAction::Restart, + ButtonAction(GameState::Restart), + ButtonAction(MenuState::None), ButtonBundle { style: Style { padding: UiRect::all(Val::Px(5.0)), @@ -271,10 +270,11 @@ fn init_endgame_menu(mut commands: Commands) { }, )) .with_children(|parent| { - // Continue button + // New Game button parent .spawn(( - ButtonAction::Restart, + ButtonAction(GameState::Restart), + ButtonAction(MenuState::None), ButtonBundle { style: Style { padding: UiRect::all(Val::Px(5.0)), @@ -299,7 +299,8 @@ fn init_endgame_menu(mut commands: Commands) { // Quit button parent .spawn(( - ButtonAction::Quit, + ButtonAction(MenuState::None), + ButtonAction(GameState::Quit), ButtonBundle { style: Style { padding: UiRect::all(Val::Px(5.0)), @@ -333,26 +334,20 @@ fn set_menu_state( GameState::Endgame => next_menu_state.set(MenuState::Endgame), GameState::Intro => error!("Should skip to GameState::Play"), GameState::Credits => error!("Should pop back to GameState::Play"), + GameState::Restart | GameState::Quit => panic!("This shouldn't be possible!"), } } -fn handle_button_press( - events: Query<(&Interaction, &ButtonAction), Changed>, - mut next_game_state: ResMut>, - mut next_tutorial_state: ResMut>, - mut next_menu_state: ResMut>, - mut app_exit_events: EventWriter, +fn handle_button_press( + events: Query<(&Interaction, &ButtonAction), Changed>, + mut next_state: ResMut>, ) { events .iter() .filter_map(|(interaction, button_action)| { (*interaction == Interaction::Pressed).then_some(button_action) }) - .for_each(|button_action| match button_action { - ButtonAction::GameState(gs) => next_game_state.set(gs.clone()), - ButtonAction::MenuState(ms) => next_menu_state.set(ms.clone()), - ButtonAction::TutorialState(ts) => next_tutorial_state.set(ts.clone()), - ButtonAction::Quit => app_exit_events.send(AppExit), - ButtonAction::Restart => panic!("TODO: Restart game!"), + .for_each(|ButtonAction(ba)| { + next_state.set(ba.clone()) }); }