diff --git a/crates/bevy_app/src/plugin.rs b/crates/bevy_app/src/plugin.rs index 55e1ce29a2..2609c9e504 100644 --- a/crates/bevy_app/src/plugin.rs +++ b/crates/bevy_app/src/plugin.rs @@ -21,6 +21,40 @@ use std::any::Any; /// * once the app started, it will wait for all registered [`Plugin::ready`] to return `true` /// * it will then call all registered [`Plugin::finish`] /// * and call all registered [`Plugin::cleanup`] +/// +/// ## Defining a plugin. +/// +/// Most plugins are simply functions that add configuration to an [`App`]. +/// +/// ``` +/// # use bevy_app::{App, Update}; +/// App::new().add_plugins(my_plugin).run(); +/// +/// // This function implements `Plugin`, along with every other `fn(&mut App)`. +/// pub fn my_plugin(app: &mut App) { +/// app.add_systems(Update, hello_world); +/// } +/// # fn hello_world() {} +/// ``` +/// +/// For more advanced use cases, the `Plugin` trait can be implemented manually for a type. +/// +/// ``` +/// # use bevy_app::*; +/// pub struct AccessibilityPlugin { +/// pub flicker_damping: bool, +/// // ... +/// } +/// +/// impl Plugin for AccessibilityPlugin { +/// fn build(&self, app: &mut App) { +/// if self.flicker_damping { +/// app.add_systems(PostUpdate, damp_flickering); +/// } +/// } +/// } +/// # fn damp_flickering() {} +/// ```` pub trait Plugin: Downcast + Any + Send + Sync { /// Configures the [`App`] to which this plugin is added. fn build(&self, app: &mut App); @@ -60,6 +94,12 @@ pub trait Plugin: Downcast + Any + Send + Sync { impl_downcast!(Plugin); +impl Plugin for T { + fn build(&self, app: &mut App) { + self(app); + } +} + /// A type representing an unsafe function that returns a mutable pointer to a [`Plugin`]. /// It is used for dynamically loading plugins. /// diff --git a/examples/games/game_menu.rs b/examples/games/game_menu.rs index 633ce0cc70..d315d4bddf 100644 --- a/examples/games/game_menu.rs +++ b/examples/games/game_menu.rs @@ -37,7 +37,7 @@ fn main() { .init_state::() .add_systems(Startup, setup) // Adds the plugins for each state - .add_plugins((splash::SplashPlugin, menu::MenuPlugin, game::GamePlugin)) + .add_plugins((splash::splash_plugin, menu::menu_plugin, game::game_plugin)) .run(); } @@ -51,19 +51,15 @@ mod splash { use super::{despawn_screen, GameState}; // This plugin will display a splash screen with Bevy logo for 1 second before switching to the menu - pub struct SplashPlugin; - - impl Plugin for SplashPlugin { - fn build(&self, 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::); - } + 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 @@ -125,14 +121,10 @@ mod game { // This plugin will contain the game. In this case, it's just be a screen that will // display the current settings for 5 seconds before returning to the menu - pub struct GamePlugin; - - impl Plugin for GamePlugin { - fn build(&self, app: &mut App) { - app.add_systems(OnEnter(GameState::Game), game_setup) - .add_systems(Update, game.run_if(in_state(GameState::Game))) - .add_systems(OnExit(GameState::Game), despawn_screen::); - } + pub fn game_plugin(app: &mut App) { + app.add_systems(OnEnter(GameState::Game), game_setup) + .add_systems(Update, game.run_if(in_state(GameState::Game))) + .add_systems(OnExit(GameState::Game), despawn_screen::); } // Tag component used to tag entities added on the game screen @@ -253,57 +245,50 @@ mod menu { // - a main menu with "New Game", "Settings", "Quit" // - a settings menu with two submenus and a back button // - two settings screen with a setting that can be set and a back button - pub struct MenuPlugin; - - impl Plugin for MenuPlugin { - fn build(&self, app: &mut App) { - app - // At start, the menu is not enabled. This will be changed in `menu_setup` when - // entering the `GameState::Menu` state. - // Current screen in the menu is handled by an independent state from `GameState` - .init_state::() - .add_systems(OnEnter(GameState::Menu), menu_setup) - // Systems to handle the main menu screen - .add_systems(OnEnter(MenuState::Main), main_menu_setup) - .add_systems(OnExit(MenuState::Main), despawn_screen::) - // Systems to handle the settings menu screen - .add_systems(OnEnter(MenuState::Settings), settings_menu_setup) - .add_systems( - OnExit(MenuState::Settings), - despawn_screen::, - ) - // Systems to handle the display settings screen - .add_systems( - OnEnter(MenuState::SettingsDisplay), - display_settings_menu_setup, - ) - .add_systems( - Update, - ( - setting_button:: - .run_if(in_state(MenuState::SettingsDisplay)), - ), - ) - .add_systems( - OnExit(MenuState::SettingsDisplay), - despawn_screen::, - ) - // Systems to handle the sound settings screen - .add_systems(OnEnter(MenuState::SettingsSound), sound_settings_menu_setup) - .add_systems( - Update, - setting_button::.run_if(in_state(MenuState::SettingsSound)), - ) - .add_systems( - OnExit(MenuState::SettingsSound), - despawn_screen::, - ) - // Common systems to all screens that handles buttons behavior - .add_systems( - Update, - (menu_action, button_system).run_if(in_state(GameState::Menu)), - ); - } + pub fn menu_plugin(app: &mut App) { + app + // At start, the menu is not enabled. This will be changed in `menu_setup` when + // entering the `GameState::Menu` state. + // Current screen in the menu is handled by an independent state from `GameState` + .init_state::() + .add_systems(OnEnter(GameState::Menu), menu_setup) + // Systems to handle the main menu screen + .add_systems(OnEnter(MenuState::Main), main_menu_setup) + .add_systems(OnExit(MenuState::Main), despawn_screen::) + // Systems to handle the settings menu screen + .add_systems(OnEnter(MenuState::Settings), settings_menu_setup) + .add_systems( + OnExit(MenuState::Settings), + despawn_screen::, + ) + // Systems to handle the display settings screen + .add_systems( + OnEnter(MenuState::SettingsDisplay), + display_settings_menu_setup, + ) + .add_systems( + Update, + (setting_button::.run_if(in_state(MenuState::SettingsDisplay)),), + ) + .add_systems( + OnExit(MenuState::SettingsDisplay), + despawn_screen::, + ) + // Systems to handle the sound settings screen + .add_systems(OnEnter(MenuState::SettingsSound), sound_settings_menu_setup) + .add_systems( + Update, + setting_button::.run_if(in_state(MenuState::SettingsSound)), + ) + .add_systems( + OnExit(MenuState::SettingsSound), + despawn_screen::, + ) + // Common systems to all screens that handles buttons behavior + .add_systems( + Update, + (menu_action, button_system).run_if(in_state(GameState::Menu)), + ); } // State used for the current menu screen