From 293f27aba976555697c5e09e7247b1783def67a6 Mon Sep 17 00:00:00 2001 From: Elijah Voigt Date: Sat, 7 Oct 2023 21:16:46 -0700 Subject: [PATCH] menu! --- src/audio.rs | 2 +- src/debug.rs | 106 ++++++++++++++++++++++-- src/display2d.rs | 38 +++++++-- src/display3d.rs | 20 +++-- src/game.rs | 2 +- src/main.rs | 7 +- src/menu.rs | 211 +++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 361 insertions(+), 25 deletions(-) create mode 100644 src/menu.rs diff --git a/src/audio.rs b/src/audio.rs index 82e93e3..f77cccf 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -1,6 +1,6 @@ use crate::prelude::*; -pub struct AudioPlugin; +pub(crate) struct AudioPlugin; impl Plugin for AudioPlugin { fn build(&self, app: &mut App) { diff --git a/src/debug.rs b/src/debug.rs index 1f5bf76..38d0102 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,20 +1,114 @@ +use bevy::{ + asset::diagnostic::AssetCountDiagnosticsPlugin, + diagnostic::{ + DiagnosticsStore, EntityCountDiagnosticsPlugin, FrameTimeDiagnosticsPlugin, + SystemInformationDiagnosticsPlugin, + }, + input::{keyboard::KeyboardInput, ButtonState}, +}; + use crate::prelude::*; -pub struct DebugPlugin; +pub(crate) struct DebugPlugin; impl Plugin for DebugPlugin { fn build(&self, app: &mut App) { - app.add_systems( + app.add_plugins(( + FrameTimeDiagnosticsPlugin, + EntityCountDiagnosticsPlugin::default(), + AssetCountDiagnosticsPlugin::::default(), + AssetCountDiagnosticsPlugin::::default(), + AssetCountDiagnosticsPlugin::::default(), + AssetCountDiagnosticsPlugin::::default(), + SystemInformationDiagnosticsPlugin::default(), + )) + .add_systems(Startup, init_debug_ui) + .add_systems( Update, - display_board.run_if(resource_exists::()), + ( + toggle_debug_mode.run_if(on_event::()), + display_diagnostics.run_if(resource_exists::()), + toggle_debug_ui.run_if(resource_changed_or_removed::()), + ), ); } } /// Marker resource used to enable Debug mode when present -#[derive(Debug, Resource)] +#[derive(Debug, Resource, Default)] struct DebugEnabled; -fn display_board(board: Res) { - info!("{}", *board); +#[derive(Debug, Component)] +struct DebugRoot; + +fn toggle_debug_mode( + mut events: EventReader, + enabled: Option>, + mut commands: Commands, +) { + events + .iter() + .filter( + |KeyboardInput { + state, key_code, .. + }| *state == ButtonState::Pressed && *key_code == Some(KeyCode::F3), + ) + .for_each(|_| match enabled { + Some(_) => commands.remove_resource::(), + None => commands.insert_resource(DebugEnabled), + }); +} + +fn toggle_debug_ui( + mut visibility: Query<&mut Visibility, (With, Without)>, + enabled: Option>, +) { + visibility.iter_mut().for_each(|mut vis| { + *vis = match enabled { + Some(_) => Visibility::Visible, + None => Visibility::Hidden, + } + }); +} + +fn init_debug_ui(mut commands: Commands) { + commands + .spawn(( + NodeBundle { + style: Style { ..default() }, + ..default() + }, + DebugRoot, + )) + .with_children(|parent| { + parent.spawn(( + TextBundle { + style: Style { ..default() }, + ..default() + }, + DebugRoot, + )); + }); +} + +fn display_diagnostics( + mut root: Query<&mut Text, With>, + diagnostics: Res, +) { + root.iter_mut().for_each(|mut text| { + text.sections = diagnostics + .iter() + .map(|diagnostic| { + TextSection::new( + format!( + "{}: {:.0}\n", + diagnostic.name, + diagnostic.smoothed().unwrap_or(0.0), + ), + TextStyle { ..default() }, + ) + }) + .collect(); + text.sections.sort_unstable_by(|a, b| a.value.cmp(&b.value)); + }); } diff --git a/src/display2d.rs b/src/display2d.rs index c513065..923e687 100644 --- a/src/display2d.rs +++ b/src/display2d.rs @@ -6,7 +6,7 @@ use crate::{ const SCALE: f32 = 4.0; const TILE_SIZE: f32 = 16.0; -pub struct Display2dPlugin; +pub(crate) struct Display2dPlugin; impl Plugin for Display2dPlugin { fn build(&self, app: &mut App) { @@ -24,9 +24,11 @@ impl Plugin for Display2dPlugin { .run_if(any_with_component::()), cursor_position.run_if(in_state(GameState::Display2d)), selected.run_if(resource_changed::()), + menu::exit_to_menu.run_if(in_state(GameState::Display2d)), ), ) - .add_systems(OnEnter(GameState::Display2d), (activate, draw_board)); + .add_systems(OnEnter(GameState::Display2d), (activate, draw_board)) + .add_systems(OnExit(GameState::Display2d), deactivate); } } @@ -44,15 +46,22 @@ struct Board2d; #[derive(Debug, Component)] struct Piece2d; +#[derive(Debug, Component)] +struct Display2dCamera; + /// STARTUP: Initialize 2d gameplay Camera fn initialize_camera(mut commands: Commands) { - commands.spawn(Camera2dBundle { - camera: Camera { - is_active: false, + commands.spawn(( + Display2dCamera, + Camera2dBundle { + camera: Camera { + is_active: false, + ..default() + }, ..default() }, - ..default() - }); + UiCameraConfig { show_ui: true }, + )); } /// STARTUP: Load sprite sheet and insert texture atlas @@ -85,6 +94,7 @@ fn initialize_board(sprite_sheet: Option>, mut commands: Comman -SCALE * TILE_SIZE * 3.0 / 2.0, // Why 7 and 3?? 0.0, ), + visibility: Visibility::Hidden, ..default() }, Board2d, @@ -166,7 +176,7 @@ fn draw_board( } fn activate( - mut cameras: Query<&mut Camera, With>, + mut cameras: Query<&mut Camera, With>, mut boards: Query<&mut Visibility, With>, ) { cameras.iter_mut().for_each(|mut camera| { @@ -177,6 +187,18 @@ fn activate( }); } +fn deactivate( + mut cameras: Query<&mut Camera, With>, + mut boards: Query<&mut Visibility, With>, +) { + cameras.iter_mut().for_each(|mut camera| { + camera.is_active = false; + }); + boards.iter_mut().for_each(|mut visibility| { + *visibility = Visibility::Hidden; + }); +} + fn cursor_position( mut events: EventReader, sprite_q: Query<( diff --git a/src/display3d.rs b/src/display3d.rs index 8c9ce1a..e977239 100644 --- a/src/display3d.rs +++ b/src/display3d.rs @@ -1,6 +1,6 @@ use crate::prelude::*; -pub struct Display3dPlugin; +pub(crate) struct Display3dPlugin; impl Plugin for Display3dPlugin { fn build(&self, app: &mut App) { @@ -10,7 +10,10 @@ impl Plugin for Display3dPlugin { ) .add_systems( Update, - initialize_board.run_if(resource_added::()), + ( + initialize_board.run_if(resource_added::()), + menu::exit_to_menu.run_if(in_state(GameState::Display3d)), + ), ) .add_systems(OnEnter(GameState::Display3d), activate); } @@ -23,13 +26,16 @@ struct Board3d; struct ModelMap; fn initialize_camera(mut commands: Commands) { - commands.spawn(Camera3dBundle { - camera: Camera { - is_active: false, + commands.spawn(( + Camera3dBundle { + camera: Camera { + is_active: false, + ..default() + }, ..default() }, - ..default() - }); + UiCameraConfig { show_ui: true }, + )); } fn load_models(server: Res, mut commands: Commands) { diff --git a/src/game.rs b/src/game.rs index 343c734..d5613a5 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,6 +1,6 @@ use crate::prelude::*; -pub struct GamePlugin; +pub(crate) struct GamePlugin; impl Plugin for GamePlugin { fn build(&self, app: &mut App) { diff --git a/src/main.rs b/src/main.rs index 5f6c26d..201cccc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ mod debug; mod display2d; mod display3d; mod game; +mod menu; mod prelude; use std::time::Duration; @@ -40,6 +41,7 @@ fn main() { display2d::Display2dPlugin, display3d::Display3dPlugin, game::GamePlugin, + menu::MenuPlugin, )) .run(); } @@ -61,15 +63,16 @@ fn loading( let items = { sprites.ids() }; let states = server.get_group_load_state(items); match states { - LoadState::Loaded | LoadState::NotLoaded => next_state.set(GameState::Display2d), + LoadState::Loaded | LoadState::NotLoaded => next_state.set(GameState::Menu), _ => (), } } +/// System for printing the current state fn state(state: Option>>) { state.map(|s| { if s.is_added() || s.is_changed() { - info!("Updated state is {:?}", s); + info!("State is {:?}", s); } }); } diff --git a/src/menu.rs b/src/menu.rs new file mode 100644 index 0000000..c2205e5 --- /dev/null +++ b/src/menu.rs @@ -0,0 +1,211 @@ +use bevy::{ + app::AppExit, + input::{keyboard::KeyboardInput, ButtonState}, + window::PrimaryWindow, +}; + +use crate::prelude::*; + +pub(crate) struct MenuPlugin; + +impl Plugin for MenuPlugin { + fn build(&self, app: &mut App) { + app.add_systems(Startup, init_menu_ui) + .add_systems( + Update, + ( + handle_menu_start, + handle_menu_quit, + bevy::window::close_on_esc, + interactive_button, + ) + .run_if(in_state(GameState::Menu)), + ) + .add_systems(OnEnter(GameState::Menu), activate) + .add_systems(OnExit(GameState::Menu), deactivate); + } +} + +#[derive(Debug, Component)] +struct MenuCamera; + +#[derive(Debug, Component)] +struct MenuRoot; + +#[derive(Debug, Component)] +struct Start; + +#[derive(Debug, Component)] +struct Quit; + +fn init_menu_ui(mut commands: Commands) { + commands.spawn(( + MenuCamera, + Camera2dBundle { + camera: Camera { + is_active: false, + ..default() + }, + ..default() + }, + UiCameraConfig { show_ui: true }, + )); + + commands + .spawn(( + MenuRoot, + NodeBundle { + style: Style { + width: Val::Percent(100.0), + height: Val::Percent(100.0), + justify_content: JustifyContent::Center, + align_items: AlignItems::Center, + flex_direction: FlexDirection::Column, + position_type: PositionType::Absolute, + ..default() + }, + background_color: Color::NONE.into(), + ..default() + }, + )) + .with_children(|parent| { + parent + .spawn(( + Start, + 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(( + Start, + TextBundle::from_section( + "Start", + TextStyle { + color: Color::BLACK, + font_size: 32.0, + ..default() + }, + ), + )); + }); + + parent + .spawn(( + Quit, + 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(( + Quit, + TextBundle::from_section( + "Quit", + TextStyle { + color: Color::BLACK, + font_size: 32.0, + ..default() + }, + ), + )); + }); + }); +} + +fn activate( + mut cameras: Query<&mut Camera, With>, + mut boards: Query<&mut Visibility, With>, +) { + cameras.iter_mut().for_each(|mut camera| { + camera.is_active = true; + }); + boards.iter_mut().for_each(|mut visibility| { + *visibility = Visibility::Visible; + }); +} + +fn deactivate( + mut cameras: Query<&mut Camera, With>, + mut boards: Query<&mut Visibility, With>, +) { + cameras.iter_mut().for_each(|mut camera| { + camera.is_active = false; + }); + boards.iter_mut().for_each(|mut visibility| { + *visibility = Visibility::Hidden; + }); +} + +fn handle_menu_start( + events: Query<&Interaction, (With, With