Tainted\\Coders

Bevy Plugins

Bevy version: 0.16Last updated:

Bevy uses an architecture that lets you organize your game into encapsulated features called plugins.

A plugin is any function that takes an App and modifies it with the plugins behavior. 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);
}

These 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.

The Plugin trait

Usually we prefer to use 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: &App) -> bool {
    info!("Time to clean up")
    true
  }

  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:

  1. We add our plugin to the App with add_plugins
  2. Our plugin has its build method called
  3. Bevy eventually calls ready on our plugin
  4. Bevy internally polls to ensure all plugins succeeded
  5. Finally, Bevy calls cleanup on our plugin.

Plugin ordering and dependencies

Plugins are run in the order they are added to the App.

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:

PluginDescription
DiagnosticsPluginAdds core diagnostics
FrameCountPluginAdds frame counting functionality
HierarchyPluginHandles Parent and Children components
InputPluginAdds keyboard and mouse input
LogPluginAdds logging to apps
PanicHandlerPluginAdds sensible panic handling
ScheduleRunnerPluginConfigures an App to run its Schedule according to a given RunMode
TaskPoolPluginSetup of default task pools for multithreading
TimePluginAdds time functionality
TransformPluginHandles Transform components
TypeRegistrationPluginRegisters types for reflection (dynamic lookup of types at runtime)

Then depending on the features you enable (all enabled by default) you have more plugins that are added:

PluginFeatureDescription
AccessibilityPluginbevy_windowAdds non-GUI accessibility functionality
AnimationPluginbevy_animationAdds animation support
AssetPluginbevy_assetAdds asset server and resources to load assets
AudioPluginbevy_audioAdds support for using sound assets
DevToolsPluginbevy_dev_toolsEnables developer tools in an App
CiTestingPluginbevy_ci_testingHelps instrument continuous integration
CorePipelinePluginbevy_core_pipelineThe core rendering pipeline
DebugAssetPlugindebug_asset_serverAdds stuff that helps debugging your assets
GltfPluginbevy_gltfAdds support for loading gltf models
GilrsPluginbevy_gilrsAdds support for gamepad inputs
GizmoPluginbevy_gizmosProvides an immediate mode drawing api for visual debugging
GltfPluginbevy_gltfAllows loading gltf based assets
ImagePluginbevy_renderAdds the Image asset and prepares them to render on your GPU
PbrPluginbevy_pbrAdds physical based rendering with StandardMaterial etc
PipelinedRenderingPluginbevy_renderEnables pipelined rendering which makes rendering multithreaded
RenderPluginbevy_renderSets up rendering backend powered by wgpu crate
ScenePluginbevy_sceneLoading and saving collections of entities and components to files
SpritePluginbevy_spriteHandling of sprites (images on our entities)
TextPluginbevy_textSupports loading fonts and rendering text
UiPluginbevy_uiAdds support for UI layouts (flex, grid, etc)
WindowPluginbevy_windowProvides an interface to create and manage Window components
WinitPluginbevy_winitInterface to create operating system windows (to actually display our game)