Bevy Version: | 0.14 | (current) |
---|
Plugins
Relevant official examples:
plugin
,
plugin_group
.
As your project grows, it can be useful to make it more modular. You can split it into "plugins".
Plugins are simply collections of things to be added to the App Builder. Think of this as a way to add things to the app from multiple places, like different Rust files/modules or crates.
The simplest way to create a plugin is by just writing a Rust function
that takes &mut App
:
fn my_plugin(app: &mut App) {
app.init_resource::<MyCustomResource>();
app.add_systems(Update, (
do_some_things,
do_other_things,
));
}
An alternative way is by creating a struct
and implementing the Plugin
trait:
struct MyPlugin;
impl Plugin for MyPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<MyOtherResource>();
app.add_event::<MyEvent>();
app.add_systems(Startup, plugin_init);
app.add_systems(Update, my_system);
}
}
The benefit of using a struct
is that you could extend it with configuration
parameters or generics if you want to make your plugin configurable.
Either way, you get &mut
access to the App
, so you can add whatever
you want to it, just like you can do from your fn main()
.
You can now add your plugins to your App
from elsewhere (most commonly
fn main()
). Bevy will just call your plugin implementation above. In effect,
everything the plugin adds will be flattened into your App
alongside
everything that is already there.
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins((
my_plugin, // the `fn`-based plugin
MyPlugin, // the `struct`-based plugin
))
.run();
}
For internal organization in your own project, the main value of plugins
comes from not having to declare all your Rust types and functions as
pub
, just so they can be accessible from fn main
to be added to the
app builder. Plugins let you add things to your app from multiple
different places, like separate Rust files / modules.
You can decide how plugins fit into the architecture of your game.
Some suggestions:
- Create plugins for different states.
- Create plugins for various sub-systems, like physics or input handling.
Plugin Groups
Plugin groups register multiple plugins at once. Bevy's DefaultPlugins
and MinimalPlugins
are examples of this.
To create your own plugin group, implement the PluginGroup
trait:
use bevy::app::PluginGroupBuilder;
struct MyPluginGroup;
impl PluginGroup for MyPluginGroup {
fn build(self) -> PluginGroupBuilder {
PluginGroupBuilder::start::<Self>()
.add(FooPlugin)
.add(BarPlugin)
}
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(MyPluginGroup)
.run();
}
When adding a plugin group to the app, you can disable some plugins while keeping the rest.
For example, if you want to manually set up logging (with your own tracing
subscriber), you can disable Bevy's LogPlugin
:
App::new()
.add_plugins(
DefaultPlugins.build()
.disable::<bevy::log::LogPlugin>()
)
.run();
Note that this simply disables the functionality, but it cannot actually remove the code to avoid binary bloat. The disabled plugins still have to be compiled into your program.
If you want to slim down your build, you should look at disabling Bevy's default cargo features, or depending on the various Bevy sub-crates individually.
Plugin Configuration
Plugins are also a convenient place to store settings/configuration that are used during initialization/startup. For settings that can be changed at runtime, it is recommended that you put them in resources instead.
struct MyGameplayPlugin {
/// Should we enable dev hacks?
enable_dev_hacks: bool,
}
impl Plugin for MyGameplayPlugin {
fn build(&self, app: &mut App) {
// add our gameplay systems
app.add_systems(Update, (
health_system,
movement_system,
));
// ...
// if "dev mode" is enabled, add some hacks
if self.enable_dev_hacks {
app.add_systems(Update, (
player_invincibility,
free_camera,
));
}
}
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(MyGameplayPlugin {
// change to true for dev testing builds
enable_dev_hacks: false,
})
.run();
}
Plugins that are added using Plugin Groups can also be
configured. Many of Bevy's DefaultPlugins
work this way.
use bevy::window::WindowResolution;
App::new()
.add_plugins(DefaultPlugins.set(
// here we configure the main window
WindowPlugin {
primary_window: Some(Window {
resolution: WindowResolution::new(800.0, 600.0),
// ...
..Default::default()
}),
..Default::default()
}
))
.run();
Publishing Crates
Plugins give you a nice way to publish Bevy-based libraries for other people to easily include into their projects.
Bevy offers some official guidance for good practices when you develop plugins you want to publish for other people to use. You can read it here.
Don't forget to submit an entry to Bevy Assets on the official website, so that people can find your plugin more easily. You can do this by making a PR in the Github repo.
If you are interested in supporting bleeding-edge Bevy (main), see here for advice.