Plugins

One of Bevy's core principles is modularity. All Bevy engine features are implemented as plugins. This includes internal features like the renderer, but games themselves are also implemented as plugins! This empowers developers to pick and choose which features they want. Don't need a UI? Don't register the UiPlugin . Want to build a headless server? Don't register the RenderPlugin .

This also means you are free to replace any components you don't like. If you feel the need, you are welcome to build your own UiPlugin , but consider contributing it back to Bevy if you think it would be useful!

However, most developers don't need a custom experience and just want the "full engine" experience with no hassle. For this, Bevy provides a set of "default plugins".

Bevy's Default Plugins

Lets make our app more interesting by adding the "default Bevy plugins".

add_default_plugins() adds the features most people expect from an engine, such as a 2D / 3D renderer, asset loading, a UI system, windows, and input.
fn main() {
    App::build()
        .add_default_plugins()
        .add_startup_system(add_people.system())
        .add_system(hello_world.system())
        .add_system(greet_people.system())
        .run();
}

Once again run cargo run.

You should hopefully notice two things:

  • A window should pop up. This is because we now have WindowPlugin , which defines the window interface (but doesn't actually know how to make windows), and WinitPlugin which uses the winit library to create a window using your OS's native window api.
  • Your console is now full of "hello" messages: This is because add_default_plugins() adds an "event loop" to our application. Our App's ECS Schedule now runs in a loop once per "frame". We will resolve the console spam in a moment.

Note that add_default_plugins() is equivalent to the following:

fn main() {
    App::build()
        .add_plugin(CorePlugin::default())
        .add_plugin(InputPlugin::default())
        .add_plugin(WindowPlugin::default())
        /* more plugins omitted for brevity */
        .run();
}

You are free to use whatever approach suits you!

Creating your first plugin

For better organization, lets move all of our "hello" logic to a plugin. To create a plugin we just need to implement the Plugin interface. Add the following code to your main.rs file:

pub struct HelloPlugin;

impl Plugin for HelloPlugin {
    fn build(&self, app: &mut AppBuilder) {
        // add things to your app here
    }
}

Then register the plugin in your App like this:

fn main() {
    App::build()
        .add_default_plugins()
        .add_plugin(HelloPlugin)
        .add_startup_system(add_people.system())
        .add_system(hello_world.system())
        .add_system(greet_people.system())
        .run();
}

Now all thats left is to move our systems into HelloPlugin, which is just a matter of cut and paste. The app variable in our plugin's build() function is the same builder type we use in our main() function:

impl Plugin for HelloPlugin {
    fn build(&self, app: &mut AppBuilder) {
        app.add_startup_system(add_people.system())
            .add_system(hello_world.system())
            .add_system(greet_people.system());
    }
}

fn main() {
    App::build()
        .add_default_plugins()
        .add_plugin(HelloPlugin)
        .run();
}

Try running the app again. It should do exactly what it did before. In the next section, we'll fix the "hello" spam using Resources.