Tainted\\Coders

Bevy Resources

Bevy version: 0.20Last updated:
  1. Defining a resource
  2. Adding a resource
  3. Removing a resource
  4. Reading and writing resources
  5. Immutable resources
  6. Querying resource entities

A Resource is a Component which belongs to an entity with a IsResource marker component. Bevy uses that marker to ensure only a single instance of the resource in a World.

Resources are usually accessed via the Res and ResMut system parameters, but they can also be queried just like regular components, because they are.

They can do everything a normal component can do, including having relationships, using lifecycle hooks and requiring other components.

There are a few restrictions:

They are global singleton data structures that can be conveniently passed around between our systems.

Some examples of common resources are:

Defining a resource

We create resources by deriving the Resource trait. Deriving this trait also implements Component for us:

#[derive(Resource)]
struct Score(usize);

Here we only defined the resource. We need to tell Bevy how and when to initialize it.

Adding a resource

The simple way of adding a resource is to insert_resource with a valid instance:

fn main() {
  App::new()
    .add_plugins(DefaultPlugins)
    .insert_resource(Score(0))
    .run();
}

If we implement FromWorld traits on our resources then we can skip creating the instance ourself and allow Bevy to do that for us with init_resource<T>.

Any type that implements Default automatically implements FromWorld:

#[derive(Resource, Default)]
struct Score(usize);

fn main() {
  App::new()
    .add_plugins(DefaultPlugins)
    // .insert_resource(Score(0))
    .init_resource::<Score>()
    .add_systems(Update, increase_score)
    .run();
}

Resources can also be added dynamically through our systems instead. This can be useful for controlling exactly when a resource is created, or for creating resources that depend on other resources:

fn add_score(mut commands: Commands, starting_score: Res<StartingScore>) {
  commands.insert_resource(Score(starting_score.0));
}

We can also attach extra components to a resource entity with #[require(...)], and the same machinery lets us create relationships that point at resource entities:

#[derive(Resource)]
#[require(ScoreLabel)]
struct HighScore(usize);

#[derive(Component, Default)]
struct ScoreLabel;

Removing a resource

To remove a resource at runtime we can use our Commands inside any system.

fn remove_score(mut commands: Commands) {
  commands.remove_resource::<Score>();
}

Removing a resource only removes the component. The entity that held the resource stays alive and is reused if insert the resource again. Because of this, World::clear_entities also clears every resource.

Reading and writing resources

To read and write a resource's data we use the Res and ResMut system parameters:

fn increase_score(mut score: ResMut<Score>) {
  score.0 += 1;
  println!("Score: {}", score.0);
}

We should prefer to have resources initialized during the App definition. This will ensure they are available in our systems. However not all resources are known at compile time, and some may be created dynamically.

If we were creating them dynamically, and we had to use them in one of our systems, we can wrap the resource access in an Option to avoid a panic if they don't yet exist:

fn increase_score_if_present(score: Option<ResMut<Score>>) {
  if let Some(mut score) = score {
    score.0 += 1;
    println!("Score: {}", score.0);
  } else {
    println!("No score resource found.");
  }
}

When a missing resource should skip the system entirely instead of running with a branch, wrap the parameter in If:

fn increase_score_if_present_skip(If(mut score): If<ResMut<Score>>) {
  score.0 += 1;
  println!("Score: {}", score.0);
}

We can also gate a whole system with the resource_exists::<Score> run condition.

Immutable resources

Just like components, resources can be marked as immutable so they can never be mutated after they are inserted:

#[derive(Resource)]
#[component(immutable)]
struct MaxScore(usize);

Generic systems that want mutable access to resources will need to specify the kind of access they want. For example, a system that always mutates a resource needs to add that bound:

fn my_generic_system<R: Resource<Mutability = Mutable>>(mut res: ResMut<R>) {
  // ...
}

Querying resource entities

Because resources are components, we can inspect them with regular queries:

fn print_scores(scores: Query<&Score>) {
  for score in &scores {
    println!("Score: {}", score.0);
  }
}

Each resource value lives on a normal entity that also has the IsResource marker component. Bevy uses that marker to guarantee a resource type has exactly one instance.

Because resource entities are regular entities, broad queries now conflict with Res and ResMut. Narrow the query with Without<IsResource> to resolve it:

// error[B0002]: the query conflicts with reading `Score`
fn system(entities: Query<EntityMut>, score: Res<Score>) {}

// ok: resource entities are filtered out
fn system(entities: Query<EntityMut, Without<IsResource>>, score: Res<Score>) {}