use crate::{GameState, control::CharacterInputEnabled}; use bevy::{color::palettes::css::BLACK, prelude::*}; use shared::{HEDZ_GREEN, HEDZ_PURPLE, loading_assets::UIAssets}; #[derive(States, Default, Clone, Eq, PartialEq, Debug, Hash)] #[states(scoped_entities)] enum PauseMenuState { #[default] Closed, Open, } #[derive(Component, PartialEq, Eq, Clone, Copy)] enum ProgressBar { Music, Sound, } #[derive(Resource)] struct PauseMenuSelection(ProgressBar); pub fn plugin(app: &mut App) { app.init_state::(); app.add_systems(Update, open_pause_menu.run_if(in_state(GameState::Playing))); app.add_systems( Update, (selection_input, selection_changed).run_if(in_state(PauseMenuState::Open)), ); app.add_systems(OnEnter(PauseMenuState::Open), setup); } fn open_pause_menu( state: Res>, mut next_state: ResMut>, mut char_controls: ResMut, keyboard: Res>, ) { if keyboard.just_pressed(KeyCode::Escape) { let menu_open = match state.get() { PauseMenuState::Closed => { next_state.set(PauseMenuState::Open); true } PauseMenuState::Open => { next_state.set(PauseMenuState::Closed); false } }; if menu_open { *char_controls = CharacterInputEnabled::Off; } else { *char_controls = CharacterInputEnabled::On; } } } fn setup(mut commands: Commands, assets: Res) { commands.spawn(( Name::new("pause-menu"), Node { width: Val::Percent(100.0), height: Val::Percent(100.0), flex_direction: FlexDirection::Column, align_items: AlignItems::Center, justify_content: JustifyContent::Center, row_gap: Val::Px(10.), ..default() }, BackgroundColor(Color::linear_rgba(0., 0., 0., 0.6)), StateScoped(PauseMenuState::Open), children![ spawn_progress(ProgressBar::Music, 100, assets.font.clone()), spawn_progress(ProgressBar::Sound, 80, assets.font.clone()) ], )); commands.insert_resource(PauseMenuSelection(ProgressBar::Music)); } fn spawn_progress(bar: ProgressBar, value: u8, font: Handle) -> impl Bundle { ( Node { width: Val::Px(500.0), height: Val::Px(60.0), border: UiRect::all(Val::Px(8.)), align_items: AlignItems::Center, row_gap: Val::Px(10.), ..default() }, BackgroundColor(BLACK.into()), BorderRadius::all(Val::Px(100.)), BorderColor(HEDZ_PURPLE.into()), BoxShadow::new( BLACK.into(), Val::Px(2.), Val::Px(2.), Val::Px(4.), Val::Px(4.), ), bar, children![ ( Node { width: Val::Percent(100.0), margin: UiRect::left(Val::Px(10.)), ..default() }, Text::new(match bar { ProgressBar::Music => "MUSIC".to_string(), ProgressBar::Sound => "SOUND".to_string(), }), TextFont { font: font.clone(), font_size: 16.0, ..Default::default() }, TextColor(HEDZ_GREEN.into()), TextLayout::new_with_justify(JustifyText::Left), ), ( Node { margin: UiRect::horizontal(Val::Px(5.)), ..default() }, Text::new("<".to_string()), TextFont { font: font.clone(), font_size: 16.0, ..Default::default() }, TextColor(HEDZ_GREEN.into()), TextLayout::new_with_justify(JustifyText::Left).with_no_wrap(), ), ( Text::new(format!("{value}",)), TextFont { font: font.clone(), font_size: 16.0, ..Default::default() }, TextColor(HEDZ_GREEN.into()), TextLayout::new_with_justify(JustifyText::Left).with_no_wrap(), ), ( Node { margin: UiRect::horizontal(Val::Px(5.)), ..default() }, Text::new(">".to_string()), TextFont { font, font_size: 16.0, ..Default::default() }, TextColor(HEDZ_GREEN.into()), TextLayout::new_with_justify(JustifyText::Left).with_no_wrap(), ) ], ) } fn selection_input(mut state: ResMut, keyboard: Res>) { if keyboard.just_pressed(KeyCode::ArrowUp) || keyboard.just_pressed(KeyCode::ArrowDown) { state.0 = match state.0 { ProgressBar::Music => ProgressBar::Sound, ProgressBar::Sound => ProgressBar::Music, } } } fn selection_changed( state: Res, mut query: Query<(&mut BorderColor, &ProgressBar)>, ) { if state.is_changed() { for (mut border, bar) in query.iter_mut() { border.0 = if *bar == state.0 { HEDZ_GREEN.into() } else { HEDZ_PURPLE.into() } } } }