//! This example will display a simple menu using Bevy UI where you can start a new game, //! change some settings or quit. There is no actual game, it will just display the current //! settings for 5 seconds before going back to the menu. use bevy::prelude::*; const TEXT_COLOR: Color = Color::srgb(0.9, 0.9, 0.9); // Enum that will be used as a global state for the game #[derive(Clone, Copy, Default, Eq, PartialEq, Debug, Hash, States)] enum GameState { #[default] Splash, Menu, Game, } // One of the two settings that can be set through the menu. It will be a resource in the app #[derive(Resource, Debug, Component, PartialEq, Eq, Clone, Copy)] enum DisplayQuality { Low, Medium, High, } // One of the two settings that can be set through the menu. It will be a resource in the app #[derive(Resource, Debug, Component, PartialEq, Eq, Clone, Copy)] struct Volume(u32); fn main() { App::new() .add_plugins(DefaultPlugins) // Insert as resource the initial value for the settings resources .insert_resource(DisplayQuality::Medium) .insert_resource(Volume(7)) // Declare the game state, whose starting value is determined by the `Default` trait .init_state::() .add_systems(Startup, setup) // Adds the plugins for each state .add_plugins((splash::splash_plugin, menu::menu_plugin, game::game_plugin)) .run(); } fn setup(mut commands: Commands) { commands.spawn(Camera2dBundle::default()); } mod splash { use bevy::prelude::*; use super::{despawn_screen, GameState}; // This plugin will display a splash screen with Bevy logo for 1 second before switching to the menu pub fn splash_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(GameState::Splash), splash_setup) // While in this state, run the `countdown` system .add_systems(Update, countdown.run_if(in_state(GameState::Splash))) // When exiting the state, despawn everything that was spawned for this screen .add_systems(OnExit(GameState::Splash), despawn_screen::); } // Tag component used to tag entities added on the splash screen #[derive(Component)] struct OnSplashScreen; // Newtype to use a `Timer` for this screen as a resource #[derive(Resource, Deref, DerefMut)] struct SplashTimer(Timer); fn splash_setup(mut commands: Commands, asset_server: Res) { let icon = asset_server.load("branding/icon.png"); // Display the logo commands .spawn(( NodeBundle { style: Style { align_items: AlignItems::Center, justify_content: JustifyContent::Center, width: Val::Percent(100.0), height: Val::Percent(100.0), ..default() }, ..default() }, OnSplashScreen, )) .with_children(|parent| { parent.spawn(ImageBundle { style: Style { // This will set the logo to be 200px wide, and auto adjust its height width: Val::Px(200.0), ..default() }, image: UiImage::new(icon), ..default() }); }); // Insert the timer as a resource commands.insert_resource(SplashTimer(Timer::from_seconds(1.0, TimerMode::Once))); } // Tick the timer, and change state when finished fn countdown( mut game_state: ResMut>, time: Res