use crate::prelude::*; use self::tutorial::TutorialState; pub(crate) struct MenuPlugin; impl Plugin for MenuPlugin { fn build(&self, app: &mut App) { app.add_state::() // Initialize menus .add_systems( OnExit(GameState::Loading), (init_play_menu, init_tutorial_menu, init_endgame_menu), ) // Manage visible/hidden states .add_systems( Update, manage_state_entities::().run_if(state_changed::()), ) .add_systems( Update, set_menu_state.run_if(just_pressed(KeyCode::Escape)) ); } } #[derive(Debug, States, Hash, Default, PartialEq, Eq, Clone, Component)] enum MenuState { #[default] None, Play, Tutorial, Endgame, } #[derive(Debug, Component)] enum ButtonAction { GameState(GameState), MenuState(MenuState), TutorialState(tutorial::TutorialState), Restart, Quit, } fn init_play_menu(mut commands: Commands) { info!("Initializing Play menu"); commands .spawn(( MenuState::Play, 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| { // Title parent.spawn(( TextBundle::from_section( "M A R T I A N C H E S S", TextStyle { font_size: 48.0, color: Color::ORANGE_RED, ..default() }, ), )); // Continue button parent .spawn(( ButtonAction::MenuState(MenuState::None), 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::from_section( "Continue", TextStyle { color: Color::BLACK, font_size: 32.0, ..default() }, ), )); }); // Tutorial button parent .spawn(( ButtonAction::TutorialState(tutorial::TutorialState::Intro), 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::from_section( "Tutorial", TextStyle { color: Color::BLACK, font_size: 32.0, ..default() }, ), )); }); // Credits button parent .spawn(( ButtonAction::GameState(GameState::Credits), 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::from_section( "Credits", TextStyle { color: Color::BLACK, font_size: 32.0, ..default() }, ), )); }); // Quit button parent .spawn(( ButtonAction::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((TextBundle::from_section( "Quit", TextStyle { color: Color::BLACK, font_size: 32.0, ..default() }, ),)); }); }); } fn init_tutorial_menu(mut commands: Commands) { commands .spawn(( MenuState::Tutorial, 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| { // Continue button parent .spawn(( ButtonAction::MenuState(MenuState::None), 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::from_section( "Continue Game", TextStyle { color: Color::BLACK, font_size: 32.0, ..default() }, ), )); }); // Quit button parent .spawn(( ButtonAction::Restart, 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::from_section( "Restart", TextStyle { color: Color::BLACK, font_size: 32.0, ..default() }, ),)); }); }); } fn init_endgame_menu(mut commands: Commands) { commands .spawn(( MenuState::Endgame, 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| { // Continue button parent .spawn(( ButtonAction::Restart, 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::from_section( "New Game", TextStyle { color: Color::BLACK, font_size: 32.0, ..default() }, ), )); }); // Quit button parent .spawn(( ButtonAction::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((TextBundle::from_section( "Quit", TextStyle { color: Color::BLACK, font_size: 32.0, ..default() }, ),)); }); }); } fn set_menu_state( game_state: Res>, mut next_menu_state: ResMut>, ) { match game_state.get() { GameState::Loading => error!("No menu while loading!"), GameState::Play => next_menu_state.set(MenuState::Play), 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") } }