Bevy Resources
Resources are used to hold shared data not specific to any single entity.
A Resource is actually a Component which belongs to a singleton entity. This was a new change in 0.19. Previously resources required special handling compared to components.
This means they can be queried as regular old components or via the Res and ResMut system parameters. They are also able to have relationships, use lifecycle hooks and observers, require other components, and do everything else a component can normally do.
There are a few restrictions:
- Resources must be
Send + Sync, because they are components. If you need to store!Sendstate, use non-send data instead (NonSend,NonSendMut, andApp::insert_non_send). - You cannot change the storage type of a resource. Resources always use
SparseSetstorage, and Bevy does not intend to expose this as a performance lever. - A resource can only have one instance of its type in each
World.
They are global singleton data structures that can be conveniently passed around between your systems.
Some examples of common resources are:
- Game settings
- Handles to your assets
- Scores
Defining a resource
We create resources by deriving the Resource trait. Deriving this trait also implements Component for us:
#[derive(Resource)]
struct Score(usize);
This will only define the resource and make it available to be added to our App. We have to tell Bevy how and when to actually initialize the resource.
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 either Default or 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 your 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));
}
Removing a resource
To remove a resource at runtime you can use your Commands inside any system.
fn remove_score(mut commands: Commands) {
commands.remove_resource::<Score>();
}
Removing a resource only removes the component. The resource entity itself stays alive and is reused if you 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.
If we were dynamically creating them, we can use 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);
}
You 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);
Because of this, APIs like ResMut, World::resource_mut, and World::get_resource_mut require Resource<Mutability = Mutable>. Generic code 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, so you should insert and remove resources through the resource API rather than spawning or despawning the entity yourself.
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>) {}
IsResource lives in bevy::ecs::resource and is not part of the prelude.
You can also attach extra components to a resource entity with #[require(...)], and the same machinery lets you create relationships that point at resource entities:
#[derive(Resource)]
#[require(ScoreLabel)]
struct HighScore(usize);
#[derive(Component, Default)]
struct ScoreLabel;
Any Entity fields on a resource are now mapped automatically, so you no longer need to derive MapEntities for them.