Bevy Resources
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:
- 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). - We 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 our systems.
Some examples of common resources are:
- Game settings
- Storing
Handle<T>to our 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);
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>) {}