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 they 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 life-cycle hooks, and the everything else a component can normally do.
The only limitation they have is that you cannot change the storage type of a resource.
It's special because 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 derives Component.
#[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>:
#[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) {
commands.insert_resource(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>();
}
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(mut score: Option<ResMut<Score>>) {
if let Some(mut score) = score.as_deref_mut() {
score.0 += 1;
println!("Score: {}", score.0);
} else {
println!("No score resource found.");
}
}