Tainted\\Coders

Run a plugin conditionally

Bevy version: 0.18Last updated:

Sometimes your plugins might depend on other plugins running. Trying to include a plugin twice will cause an error.

This is a major sore spot for the ecosystem in general and is being worked on. There are two main ideas being discussed to solve this:

  1. Async plugin loading where plugins can be loaded and unloaded at runtime.
  2. Plugin dependencies where plugins can specify what other plugins they depend on and Bevy will automatically load them.

Work is still being done so for now your main alternative is to conditionally add your plugin during app setup.

As long as your plugins impl Plugin and are not just a basic function you can check if they have been added:

#[derive(Resource, Default)]
pub struct MousePosition(Vec2);

pub(crate) fn plugin(app: &mut App) {
  app
    .init_resource::<MousePosition>()
    .init_resource::<ButtonInput<KeyCode>>()
    .add_systems(Update, handle_keyboard_input);

  if !app.is_plugin_added::<PhysicsPlugin>() {
    app.add_plugins(PhysicsPlugin);
  }
}

Plugins are statically configured when your App is built so there is no real way to add or remove them from your app during runtime.

You can however use run conditions or some other logic to have them run when your game is in a certain state.

use bevy::prelude::*;

#[derive(Debug, Clone, Eq, PartialEq, Hash, Default, States)]
enum GameState {
  #[default]
  MainMenu,
  Game,
}

fn system_a() {
  println!("System A");
}

fn system_b() {
  println!("System B");
}

fn main() {
  App::new()
    .add_plugins(DefaultPlugins)
    .add_systems(Update, system_a.run_if(in_state(GameState::MainMenu)))
    .add_systems(Update, system_b.run_if(in_state(GameState::Game)))
    .run();
}