From 5fc0706c106e66b01922cd14aab29d3d8245d9d3 Mon Sep 17 00:00:00 2001 From: "Elijah C. Voigt" Date: Mon, 26 Feb 2024 20:07:20 -0800 Subject: [PATCH] Saving my place Adding a little 'just_pressed' helper for system conditionals Replaces that lambda I kept using all over the place --- src/audio.rs | 3 +- src/display3d.rs | 4 +- src/game.rs | 8 +- src/intro.rs | 6 +- src/main.rs | 12 ++- src/menu.rs | 214 +++++++++++++++++++++++++++++++++++++++++------ src/tutorial.rs | 4 +- 7 files changed, 205 insertions(+), 46 deletions(-) diff --git a/src/audio.rs b/src/audio.rs index b26a51c..3c105f6 100644 --- a/src/audio.rs +++ b/src/audio.rs @@ -29,8 +29,7 @@ impl Plugin for AudioPlugin { play_audio.run_if(any_component_added::), audio_trigger.run_if(on_event::()), control_volume.run_if(resource_changed::()), - toggle_volume - .run_if(|keys: Res>| -> bool { keys.just_pressed(KeyCode::M) }), + toggle_volume.run_if(just_pressed(KeyCode::M)), ), ); } diff --git a/src/display3d.rs b/src/display3d.rs index 868f59c..641175a 100644 --- a/src/display3d.rs +++ b/src/display3d.rs @@ -84,9 +84,7 @@ impl Plugin for Display3dPlugin { setup_capture_piece.run_if(any_component_changed::>), capture_piece.run_if(any_with_component::()), skip_animation - .run_if(|keys: Res>| -> bool { - keys.just_pressed(KeyCode::Return) - }) + .run_if(just_pressed(KeyCode::Return)) .run_if(in_state(GameState::Play)), ), ) diff --git a/src/game.rs b/src/game.rs index 5cf6b12..5c577a8 100644 --- a/src/game.rs +++ b/src/game.rs @@ -24,17 +24,13 @@ impl Plugin for GamePlugin { .run_if(on_event::()) .after(handle_selection), set_side.run_if(any_component_changed::), - cancel_place.run_if(|buttons: Res>| -> bool { - buttons.just_pressed(MouseButton::Right) - }), + cancel_place.run_if(just_pressed(MouseButton::Right)), handle_selection.run_if(on_event::()), show_valid_moves.run_if(any_component_added::), hide_valid_moves.run_if(any_component_removed::()), manage_score.run_if(any_component_added::), check_endgame.run_if(resource_changed::()), - reset_game.run_if(|keys: Res>| -> bool { - keys.just_pressed(KeyCode::R) - }), + reset_game.run_if(just_pressed(KeyCode::R)), ), ) .add_systems(OnEnter(GameState::Endgame), set_endgame) diff --git a/src/intro.rs b/src/intro.rs index 6448278..7f7249d 100644 --- a/src/intro.rs +++ b/src/intro.rs @@ -23,11 +23,7 @@ impl Plugin for IntroPlugin { // Started when the TextScrollAnimation component is added to the parent entity // Updated for as long as there is scrolling text manage_scroll_text_animation.run_if( - any_component_added::.or_else( - |keys: Res>| -> bool { - keys.just_pressed(KeyCode::Return) - }, - ), + any_component_added::.or_else(just_pressed(KeyCode::Return)), ), // Play intro manages playing the intro of each individual paragraph // Runs every time the TextScroll component (managed by manage_scroll_text_animation) is updated diff --git a/src/main.rs b/src/main.rs index 84cc1e1..6f2107e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,7 @@ mod tweak; mod ui; use bevy::winit::WinitWindows; -use std::time::Duration; +use std::{hash::Hash, time::Duration}; use winit::window::Icon; use crate::prelude::*; @@ -162,3 +162,13 @@ fn set_window_icon( window.set_window_icon(Some(icon.clone())); } } + + +pub(crate) fn just_pressed(button: T) -> impl FnMut(Res>) -> bool + Clone +where + T: Copy + Eq + Hash + Send + Sync + 'static +{ + Box::new(move |buttons: Res>| -> bool { + buttons.just_pressed(button) + }) +} \ No newline at end of file diff --git a/src/menu.rs b/src/menu.rs index 4a10d7b..31b333f 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -1,7 +1,7 @@ -use bevy::ecs::system::EntityCommands; - use crate::prelude::*; +use self::tutorial::TutorialState; + pub(crate) struct MenuPlugin; impl Plugin for MenuPlugin { @@ -16,6 +16,10 @@ impl Plugin for MenuPlugin { .add_systems( Update, manage_state_entities::().run_if(state_changed::()), + ) + .add_systems( + Update, + set_menu_state.run_if(just_pressed(KeyCode::Escape)) ); } } @@ -29,6 +33,15 @@ enum MenuState { 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"); @@ -51,8 +64,8 @@ fn init_play_menu(mut commands: Commands) { }, )) .with_children(|parent| { + // Title parent.spawn(( - MenuState::Play, TextBundle::from_section( "M A R T I A N C H E S S", TextStyle { @@ -62,10 +75,11 @@ fn init_play_menu(mut commands: Commands) { }, ), )); + + // Continue button parent .spawn(( - GameState::Play, - MenuState::None, + ButtonAction::MenuState(MenuState::None), ButtonBundle { style: Style { padding: UiRect::all(Val::Px(5.0)), @@ -78,8 +92,6 @@ fn init_play_menu(mut commands: Commands) { )) .with_children(|parent| { parent.spawn(( - GameState::Play, - MenuState::None, TextBundle::from_section( "Continue", TextStyle { @@ -91,10 +103,37 @@ fn init_play_menu(mut commands: Commands) { )); }); + // 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(( - GameState::Credits, - MenuState::None, + ButtonAction::GameState(GameState::Credits), ButtonBundle { style: Style { padding: UiRect::all(Val::Px(5.0)), @@ -107,8 +146,6 @@ fn init_play_menu(mut commands: Commands) { )) .with_children(|parent| { parent.spawn(( - GameState::Credits, - MenuState::None, TextBundle::from_section( "Credits", TextStyle { @@ -120,8 +157,11 @@ fn init_play_menu(mut commands: Commands) { )); }); + // Quit button parent - .spawn((ButtonBundle { + .spawn(( + ButtonAction::Quit, + ButtonBundle { style: Style { padding: UiRect::all(Val::Px(5.0)), margin: UiRect::all(Val::Px(5.0)), @@ -140,32 +180,75 @@ fn init_play_menu(mut commands: Commands) { }, ),)); }); + }); +} +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(( - tutorial::TutorialState::Intro, // Marks the button to start the tutorial - GameState::Play, // Marks the button to be ignored during tutorial step cleanup - MenuState::None, + ButtonAction::MenuState(MenuState::None), ButtonBundle { style: Style { padding: UiRect::all(Val::Px(5.0)), margin: UiRect::all(Val::Px(5.0)), - position_type: PositionType::Absolute, - top: Val::Px(0.0), - right: Val::Px(0.0), ..default() }, background_color: Color::ORANGE.with_a(0.5).into(), - visibility: Visibility::Hidden, ..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( - "Tutorial", + "Restart", TextStyle { color: Color::BLACK, - font_size: 16.0, + font_size: 32.0, ..default() }, ),)); @@ -173,10 +256,89 @@ fn init_play_menu(mut commands: Commands) { }); } -fn init_tutorial_menu(mut commands: Commands) { - error!("Tutorial Menu"); -} - fn init_endgame_menu(mut commands: Commands) { - error!("Endgame Menu"); + 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") + } +} \ No newline at end of file diff --git a/src/tutorial.rs b/src/tutorial.rs index 299ca4d..fc89f75 100644 --- a/src/tutorial.rs +++ b/src/tutorial.rs @@ -27,9 +27,7 @@ impl Plugin for TutorialPlugin { // A piece is de-selected .or_else(any_component_removed::()) // TEMP: The user hits 'enter' - .or_else(|keys: Res>| -> bool { - keys.just_pressed(KeyCode::Return) - }), + .or_else(just_pressed(KeyCode::Return)), ), ), ),