diff --git a/src/audio.rs b/src/audio.rs index 7268655..b26a51c 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -22,7 +22,7 @@ impl Plugin for AudioPlugin { }); app.init_resource::(); - app.add_systems(OnEnter(GameState::Menu), play_background); + app.add_systems(OnEnter(GameState::Intro), play_background); app.add_systems( Update, ( diff --git a/src/credits.rs b/src/credits.rs index 8f2f643..6cf40d6 100644 --- a/src/credits.rs +++ b/src/credits.rs @@ -5,15 +5,7 @@ pub(crate) struct CreditsPlugin; impl Plugin for CreditsPlugin { fn build(&self, app: &mut App) { app.add_systems(Startup, init_credits_ui) - .add_systems( - Update, - (menu::exit_to_menu.run_if(in_state(GameState::Credits)),), - ) - .add_systems( - OnEnter(GameState::Credits), - (update_credits, activate::.after(update_credits)), - ) - .add_systems(OnExit(GameState::Credits), deactivate::); + .add_systems(OnEnter(GameState::Credits), update_credits); } } @@ -23,7 +15,7 @@ struct Credits; fn init_credits_ui(mut commands: Commands) { commands .spawn(( - Credits, + GameState::Credits, NodeBundle { style: Style { width: Val::Percent(100.0), diff --git a/src/display3d.rs b/src/display3d.rs index 5d6ddf1..487190d 100644 --- a/src/display3d.rs +++ b/src/display3d.rs @@ -104,11 +104,14 @@ impl Plugin for Display3dPlugin { .run_if(in_state(GameState::Play)) .run_if(in_state(DisplayState::Display3d)), ) - .add_systems(OnExit(DisplayState::Display3d), deactivate::) + // Manage visible/hidden states + .add_systems( + Update, + manage_state_entities::().run_if(state_changed::()), + ) .add_systems( OnEnter(GameState::Play), ( - activate::.run_if(in_state(DisplayState::Display3d)), set_piece_texture.run_if(resource_exists::()), update_tweaks.run_if(resource_exists::()), opening_animation @@ -119,7 +122,7 @@ impl Plugin for Display3dPlugin { } } -#[derive(Debug, Component)] +#[derive(Debug, Component, PartialEq)] pub(crate) struct Display3d; #[derive(Debug, Component)] diff --git a/src/game.rs b/src/game.rs index c6ce46f..5cf6b12 100644 --- a/src/game.rs +++ b/src/game.rs @@ -13,11 +13,13 @@ impl Plugin for GamePlugin { .insert_resource(Score { ..default() }) .add_systems(Startup, setup_board) .add_systems(OnEnter(GameState::Play), hide_valid_moves) + .add_systems( + Update, + manage_state_entities::().run_if(state_changed::()), + ) .add_systems( Update, ( - menu::exit_to_menu - .run_if(in_state(GameState::Play).or_else(in_state(GameState::Endgame))), update_board .run_if(on_event::()) .after(handle_selection), diff --git a/src/intro.rs b/src/intro.rs index 6e1100b..6448278 100644 --- a/src/intro.rs +++ b/src/intro.rs @@ -14,15 +14,11 @@ impl Plugin for IntroPlugin { .run_if(run_once()), ) .add_systems(OnEnter(GameState::Intro), manage_intro) - .add_systems( - OnExit(GameState::Intro), - (deactivate::, cleanup_intro), - ) + .add_systems(OnExit(GameState::Intro), cleanup_intro) // All of these run during GameState::Intro .add_systems( Update, ( - menu::exit_to_menu, manage_intro.run_if(any_component_removed::()), // Started when the TextScrollAnimation component is added to the parent entity // Updated for as long as there is scrolling text @@ -42,12 +38,12 @@ impl Plugin for IntroPlugin { } } -#[derive(Debug, Component)] -struct Intro; - #[derive(Debug, Resource)] struct IntroPlayed; +#[derive(Debug, Component)] +struct IntroUi; + // Draw the intro text (invisible) on startup // Requires the Tweakfile to be loaded fn init_intro_text( @@ -65,7 +61,7 @@ fn init_intro_text( commands .spawn(( - Intro, + IntroUi, NodeBundle { style: Style { width: Val::Percent(100.0), @@ -85,7 +81,7 @@ fn init_intro_text( texts.iter().for_each(|text| { parent .spawn(( - Intro, + IntroUi, NodeBundle { style: Style { position_type: PositionType::Absolute, @@ -99,7 +95,7 @@ fn init_intro_text( )) .with_children(|parent| { parent.spawn(( - Intro, + IntroUi, TextBundle { text: Text { sections: text @@ -127,7 +123,7 @@ fn init_intro_text( fn manage_intro( // Hack, this way of "finding" the root Node containing our paragraphs is precarious - query: Query, With, Without)>, + query: Query, With, Without)>, mut commands: Commands, ) { info!("Managing intro"); @@ -140,8 +136,8 @@ fn manage_intro( } fn cleanup_intro( - query: Query>, - mut texts: Query<&mut Text, With>, + query: Query>, + mut texts: Query<&mut Text, With>, mut curr: ResMut, tweaks_file: Res, tweaks: Res>, @@ -183,7 +179,7 @@ fn manage_scroll_text_animation( Added, )>, >, - texts: Query, With)>, + texts: Query, With)>, animated_texts: Query<&ui::TextScroll>, parents: Query<&Parent>, children: Query<&Children>, diff --git a/src/loading.rs b/src/loading.rs index a3a6b6e..9b943c6 100644 --- a/src/loading.rs +++ b/src/loading.rs @@ -6,18 +6,12 @@ impl Plugin for LoadingPlugin { fn build(&self, app: &mut App) { app.add_systems(Startup, initialize) .add_systems(Update, loading.run_if(in_state(GameState::Loading))) - .add_systems( - OnEnter(GameState::Loading), - (activate::, enter_loading), - ) - .add_systems( - OnExit(GameState::Loading), - (deactivate::, exit_loading), - ); + .add_systems(OnEnter(GameState::Loading), enter_loading) + .add_systems(OnExit(GameState::Loading), exit_loading); } } -#[derive(Debug, Component)] +#[derive(Debug, Component, PartialEq)] struct Loading; // TODO: Why is this image not showing?? @@ -82,6 +76,6 @@ fn loading( debug!("s {} g {} t {} f {}", s, g, t, f); if t { - next_state.set(GameState::Menu) + next_state.set(GameState::Intro) } } diff --git a/src/main.rs b/src/main.rs index 3550c22..84cc1e1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -70,7 +70,6 @@ fn main() { pub enum GameState { #[default] Loading, - Menu, Credits, Intro, Play, @@ -90,31 +89,38 @@ fn debug_state(state: Res>) { info!("State change {:?}", *state); } -fn activate( - mut entities: Query< - &mut Visibility, +pub(crate) fn manage_state_entities() -> impl FnMut( + Query< + (&Marker, &mut Visibility), ( With, Without, Without, ), >, -) { - info!("Activating state"); - entities.iter_mut().for_each(|mut visibility| { - *visibility = Visibility::Visible; - }); -} - -fn deactivate( - mut entities: Query< - &mut Visibility, - (With, Without, Without), + Res>, +) +where + Marker: Component + States + PartialEq + std::fmt::Debug, +{ + move |mut entities: Query< + (&Marker, &mut Visibility), + ( + With, + Without, + Without, + ), >, -) { - entities.iter_mut().for_each(|mut visibility| { - *visibility = Visibility::Hidden; - }); + curr_state: Res>| { + info!("Activating state {:?}", *curr_state); + entities.iter_mut().for_each(|(mark, mut visibility)| { + *visibility = if mark == curr_state.get() { + Visibility::Inherited + } else { + Visibility::Hidden + }; + }); + } } pub(crate) fn any_component_changed(q: Query>) -> bool { diff --git a/src/menu.rs b/src/menu.rs index b56c74a..6c3086c 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -1,56 +1,48 @@ -use bevy::{ - app::AppExit, - input::{keyboard::KeyboardInput, ButtonState}, -}; - use crate::prelude::*; pub(crate) struct MenuPlugin; impl Plugin for MenuPlugin { fn build(&self, app: &mut App) { - app.add_systems(Startup, init_menu_ui) + app.add_state::() + // Initialize menus .add_systems( - Update, - ( - handle_menu_button::, // Run in all states - handle_menu_quit.run_if(in_state(GameState::Menu)), - bevy::window::close_on_esc.run_if(in_state(GameState::Menu)), - ), + OnExit(GameState::Loading), + (init_play_menu, init_tutorial_menu, init_endgame_menu), ) + // Manage visible/hidden states .add_systems( - OnEnter(GameState::Menu), - (activate::, activate::), - ) - .add_systems(OnExit(GameState::Menu), deactivate::); + Update, + manage_state_entities::().run_if(state_changed::()), + ); } } -#[derive(Debug, Component)] -struct Menu; - -#[derive(Debug, Component)] -struct Quit; +#[derive(Debug, States, Hash, Default, PartialEq, Eq, Clone, Component)] +enum MenuState { + #[default] + None, + Play, + Tutorial, + Endgame, +} fn init_menu_ui(mut commands: Commands) { commands - .spawn(( - Menu, - 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(), - visibility: Visibility::Hidden, + .spawn((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(), + visibility: Visibility::Hidden, + ..default() + },)) .with_children(|parent| { parent.spawn(TextBundle::from_section( "M A R T I A N C H E S S", @@ -115,71 +107,36 @@ fn init_menu_ui(mut commands: Commands) { }); 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(), + .spawn((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() - }, - ), - )); + parent.spawn((TextBundle::from_section( + "Quit", + TextStyle { + color: Color::BLACK, + font_size: 32.0, + ..default() + }, + ),)); }); }); } -pub(crate) fn handle_menu_button( - events: Query<(&Interaction, &T), (With