Update menus

This commit is contained in:
fluo10 2025-05-18 15:34:40 +09:00
parent 614e1fc865
commit f1cc49caf8
4 changed files with 180 additions and 2 deletions

View file

@ -5,8 +5,9 @@ use bevy::prelude::*;
#[derive(Clone, Copy, Default, Eq, PartialEq, Debug, Hash, States)]
enum AppState {
MainView,
#[default]
Loading,
MainView,
Menu,
List,
Graph
@ -36,11 +37,15 @@ fn main() {
.insert_resource(ViewerMode::PokerTip2D)
.init_state::<AppState>()
.add_systems(Startup, setup)
.add_plugins(((plugins::main_menu::menu_plugin, plugins::main_view::main_view_plugin)))
.add_plugins((plugins::loading::loading_plugin, plugins::main_menu::menu_plugin, plugins::main_view::main_view_plugin))
.run();
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2d);
}
// Generic system that takes a component as a parameter, and will despawn all entities with that component

View file

@ -0,0 +1,59 @@
use bevy::prelude::*;
use crate::{despawn_screen, AppState};
// This plugin will display a splash screen with Bevy logo for 1 second before switching to the menu
pub fn loading_plugin(app: &mut App) {
// As this plugin is managing the splash screen, it will focus on the state `GameState::Splash`
app
// When entering the state, spawn everything needed for this screen
.add_systems(OnEnter(AppState::Loading), loading_setup)
// While in this state, run the `countdown` system
.add_systems(Update, countdown.run_if(in_state(AppState::Loading)))
// When exiting the state, despawn everything that was spawned for this screen
.add_systems(OnExit(AppState::Loading), despawn_screen::<OnLoadingScreen>);
}
// Tag component used to tag entities added on the splash screen
#[derive(Component)]
struct OnLoadingScreen;
// Newtype to use a `Timer` for this screen as a resource
#[derive(Resource, Deref, DerefMut)]
struct LoadingTimer(Timer);
fn loading_setup(mut commands: Commands, asset_server: Res<AssetServer>) {
let icon = asset_server.load("textures/Game Icons/wrench.png");
// Display the logo
commands.spawn((
Node {
align_items: AlignItems::Center,
justify_content: JustifyContent::Center,
width: Val::Percent(100.0),
height: Val::Percent(100.0),
..default()
},
OnLoadingScreen,
children![(
ImageNode::new(icon),
Node {
// This will set the logo to be 200px wide, and auto adjust its height
width: Val::Px(200.0),
..default()
},
)],
));
// Insert the timer as a resource
commands.insert_resource(LoadingTimer(Timer::from_seconds(1.0, TimerMode::Once)));
}
// Tick the timer, and change state when finished
fn countdown(
mut game_state: ResMut<NextState<AppState>>,
time: Res<Time>,
mut timer: ResMut<LoadingTimer>,
) {
if timer.tick(time.delta()).finished() {
game_state.set(AppState::MainView);
}
}

View file

@ -0,0 +1,113 @@
use bevy::{
app::AppExit,
color::palettes::css::CRIMSON,
ecs::spawn::{SpawnIter, SpawnWith},
prelude::*,
};
use crate::{
despawn_screen,
themes::dark::{self, NORMAL_BUTTON},
DisplayQuality,
AppState,
Volume,
};
pub fn main_view_plugin(app: &mut App) {
app
.add_systems(OnEnter(AppState::MainView), main_view_setup)
.add_systems(OnExit(AppState::MainView), despawn_screen::<OnMainViewScreen>)
.add_systems(
Update,
(menu_action, button_system).run_if(in_state(AppState::MainView))
)
;
}
#[derive(Component)]
struct OnMainViewScreen;
#[derive(Component)]
struct SelectedOption;
#[derive(Component)]
enum MainViewButtonAction {
OpenMainMenu,
}
fn button_system(
mut interaction_query: Query<(&Interaction, &mut BackgroundColor, Option<&SelectedOption>),(Changed<Interaction>, With<Button>)>
) {
for (interaction, mut background_color, selected) in &mut interaction_query {
*background_color = match (*interaction, selected) {
(Interaction::Pressed, _) | (_, Some(_)) => dark::PRESSED_BUTTON.into(),
(Interaction::Hovered, None) => dark::HOVERED_BUTTON.into(),
(Interaction::None, None) => dark::NORMAL_BUTTON.into(),
}
}
}
fn main_view_setup(mut commands: Commands, asset_server: Res<AssetServer>) {
let header_node = Node {
width: Val::Percent(100.0),
height: Val::Px(20.0),
justify_content: JustifyContent::SpaceBetween,
align_items: AlignItems::Center,
..default()
};
let body_node = Node{
width: Val::Percent(100.0),
height: Val::Auto,
..default()
};
let wrench_icon = asset_server.load("textures/Game Icons/wrench.png");
commands.spawn((
Node {
width: Val::Percent(100.0),
height: Val::Percent(100.0),
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
..default()
},
OnMainViewScreen,
children![(
header_node,
children![(
Button,
Node{
width: Val::Px(30.0),
..default()
},
MainViewButtonAction::OpenMainMenu,
children![(
ImageNode::new(wrench_icon),
Node::default()
)
]
)]
)]
)
);
}
fn menu_action(
interaction_query: Query<
(&Interaction, &MainViewButtonAction),
(Changed<Interaction>, With<Button>),
>,
mut app_exit_events: EventWriter<AppExit>,
mut game_state: ResMut<NextState<AppState>>,
) {
for (interaction, menu_button_action) in &interaction_query {
if *interaction == Interaction::Pressed {
match menu_button_action {
MainViewButtonAction::OpenMainMenu => {
game_state.set(AppState::Menu);
}
}
}
}
}

View file

@ -1,2 +1,3 @@
pub mod loading;
pub mod main_menu;
pub mod main_view;