Bevy Plugins
Bevy enables us to break up our game into smaller features using plugins.
A plugin is any function that takes an &mut App and modifies it. These functions can do anything in your normal App definition, even adding other plugins.
fn plugin(app: &mut App) {
app.add_system(some_plugin_system);
}
fn main() {
App::new().add_plugins(plugin);
}
Plugins are useful for bundling up all the setup and runtime behavior of a feature into something we can toggle on and off. Plugins encapsulate the complexity of the feature into something we can "plug-into" our app.
By performing the necessary setup such as adding systems, resources and events to your game, each plugin is responsible for injecting its behavior into your game loop.
Plugins are how third party crates add functionality to Bevy. For example, avian has a plugin that adds physics to your games.
The Plugin trait
Usually we prefer using simple functions, but if your plugin has additional life-cycle requirements you can implement the Plugin trait and define the life-cycle methods you are interested in.
pub struct CameraPlugin;
impl Plugin for CameraPlugin {
fn cleanup(&self, _app: &mut App) {
info!("Time to clean up");
}
fn build(&self, app: &mut App) {
app.add_systems(Startup, initialize_camera);
}
}
fn initialize_camera(mut commands: Commands) {
commands.spawn(Camera2d);
}
Plugin life-cycle
Each Plugin will go through a life-cycle of:
- We add our plugin to the
Appwithadd_plugins - Our plugin has its
buildmethod called - Bevy eventually calls
readyon our plugin - Bevy internally polls to ensure all plugins succeeded
- Finally, Bevy calls
cleanupon our plugin.
Plugin ordering and dependencies
Plugins are run in the order they are added to the App. They are also defined during the app's definition phase before the app starts running. They cannot be changed at runtime.
Ideally a plugin would fully encapsulate its dependencies, but that's not always possible. Plugins that have dependencies do not currently have a good way to ensure those dependencies.
Bevy will also panic (by default) if you try and add the same plugin to your app more than once. You can work around this by checking if is_plugin_added before adding it.
fn plugin(app: &mut App) {
if !app.is_plugin_added::<physics::PhysicsPlugin>() {
app.add_plugins(physics::PhysicsPlugin);
}
if !app.is_plugin_added::<bevy::input::InputPlugin>() {
app.add_plugins(bevy::input::InputPlugin);
}
}
This is a good practice for testing so that the test for your plugin can run without running the entire app.
Plugin configuration
If your plugin becomes complicated enough to demand configuration you can add fields to the struct that implements Plugin.
pub struct CameraPlugin {
debug: bool,
}
impl Plugin for CameraPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, initialize_camera);
if self.debug {
// Do something
}
}
}
fn main() {
App::new()
.add_plugins(CameraPlugin { debug: true })
}
Plugin groups
Having plugins call other plugins is powerful and leads to a hierarchy of plugin dependencies. This can make it hard to configure.
Collections of plugins with a complicated setup can use the PluginGroup trait which allow us to group related plugins together and then configure them later.
This can be great choice for library authors writing plugins that others can add to their game.
pub struct GamePlugins;
impl PluginGroup for GamePlugins {
fn build(self) -> PluginGroupBuilder {
PluginGroupBuilder::start::<Self>()
.add(CameraPlugin::default())
.add(PhysicsPlugin::default())
.add(LogicPlugin)
}
}
This will let us (or anyone consuming your plugins) configure exactly how the set of plugins runs in the context of our app:
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(
game::GamePlugins
.build()
.disable::<physics::PhysicsPlugin>()
)
.run();
}
The default plugins
Bevy includes DefaultPlugins in the bevy::prelude which gives us all of the obvious things our game would need:
| Plugin | Description |
|---|---|
| DiagnosticsPlugin | Adds core diagnostics |
| DlssInitPlugin | Initializes DLSS support if available |
| FrameCountPlugin | Adds frame counting functionality |
| InputPlugin | Adds keyboard and mouse input |
| PanicHandlerPlugin | Adds sensible panic handling |
| ScheduleRunnerPlugin | Configures an App to run its Schedule according to a given RunMode |
| TaskPoolPlugin | Setup of default task pools for multi-threading |
| TimePlugin | Adds time functionality |
| TransformPlugin | Handles Transform components |
Then depending on the features you enable (all enabled by default) you have more plugins that are added:
| Plugin | Feature | Description |
|---|---|---|
| AccessibilityPlugin | bevy_window | Adds non-GUI accessibility functionality |
| AnimationPlugin | bevy_animation | Adds animation support |
| AntiAliasPlugin | bevy_anti_alias | Adds multi-sample anti-aliasing (MSAA) |
| AssetPlugin | bevy_asset | Adds asset server and resources to load assets |
| AudioPlugin | bevy_audio | Adds support for using sound assets |
| DefaultPickingPlugins | bevy_picking | Adds picking functionality |
| DevToolsPlugin | bevy_dev_tools | Enables developer tools in an App |
| CameraPlugin | bevy_camera | Adds 2D and 3D camera components and systems |
| CiTestingPlugin | bevy_ci_testing | Helps instrument continuous integration |
| CorePipelinePlugin | bevy_core_pipeline | The core rendering pipeline |
| GltfPlugin | bevy_gltf | Adds support for loading gltf models |
| GilrsPlugin | bevy_gilrs | Adds support for gamepad inputs |
| GizmoPlugin | bevy_gizmos | Provides an immediate mode drawing api for visual debugging |
| GizmoRenderPlugin | bevy_gizmos_render | Sends gizmos to the renderer |
| HotPatchPlugin | hotpatching | Enables hot-patching of assets |
| ImagePlugin | bevy_render | Adds the Image asset and prepares them to render on your GPU |
| LightPlugin | bevy_light | Adds light components and systems |
| LogPlugin | bevy_log | Adds logging to apps |
| MeshPlugin | bevy_mesh | Adds the Mesh asset and prepares them to render on the GPU |
| PbrPlugin | bevy_pbr | Adds physical based rendering with StandardMaterial etc |
| PostProcessingPlugin | bevy_post_process | Adds post processing effects |
| PipelinedRenderingPlugin | bevy_render | Adds pipelined rendering |
| RenderPlugin | bevy_render | Sets up rendering backend powered by wgpu crate |
| ScenePlugin | bevy_scene | Loading and saving collections of entities and components to files |
| SpritePlugin | bevy_sprite | Handling of sprites (images on our entities) |
| SpriteRenderPlugin | bevy_sprite_render | Adds support for sending sprites to the renderer |
| StatesPlugin | bevy_state | Adds state management for Apps |
| TerminalCtrlCHandlerPlugin | std | Handles Ctrl-C signals in terminal applications |
| TextPlugin | bevy_text | Supports loading fonts and rendering text |
| UiPlugin | bevy_ui | Adds support for UI layouts (flex, grid, etc) |
| UiRenderPlugin | bevy_ui_render | Adds support for sending UI nodes to renderer |
| WebAssetPlugin | bevy_asset | Adds the http and https asset sources to an app |
| WindowPlugin | bevy_window | Provides an interface to create and manage Window components |
| WinitPlugin | bevy_winit | Interface to create operating system windows (to actually display our game) |
The minimal plugins
Instead of DefaultPlugins, Bevy also provides MinimalPlugins which only includes the bare essentials to get an app running:
TaskPoolPluginFrameCountPluginTimePluginScheduleRunnerPluginCiTestingPlugin(with featurebevy_ci_testing)
This can be especially useful during tests to setup an app without any rendering concerns.