Let's say you have a trait that you want to implement for some of your components.
# use *;
#
/// Components that display a message when hovered.
In order to be useful within bevy, you'll want to be able to query for this trait.
# use *;
// Just add this attribute...
// ...and now you can use your trait in queries.
# assert_is_system;
Since Rust unfortunately lacks any kind of reflection, it is necessary to register each component with the trait when the app gets built.
# use *;
# use *;
#
#
#
#
;
;
/* ...trait implementations omitted for brevity... */
#
#
#
#
#
#
;
#
#
#
Unlike queries for concrete types, it's possible for an entity to have multiple components that match a trait query.
# use *;
# use *;
#
#
#
#
#
# ;
#
#
# ;
#
#
#
#
#
#
#
#
Alternatively, if you expect to only have component implementing the trait for each entity,
you can use the filter One
. This has significantly better performance than iterating
over all trait impls.
# use *;
# use *;
#
#
#
#
use One;
# assert_is_system;
Trait queries support basic change detection filtration.
- queries requesting shared access yield
ReadTraits
which is similar toRef
- queries requesting exclusive access yield
WriteTraits
which is similar toMut
To get all the components that implement the target trait, and have also changed in some way since the last tick, you can:
# use bevy::prelude::*;
# use bevy_trait_query::*;
#
# #[bevy_trait_query::queryable]
# pub trait Tooltip {
# fn tooltip(&self) -> &str;
# }
#
fn show_tooltips(
tooltips_query: Query<All<&dyn Tooltip>>
// tooltips_query: Query<&dyn Tooltip> // <-- equivalent to line above
// ...
) {
// Iterate over all entities with at least one component implementing `Tooltip`
for entity_tooltips in &tooltips_query {
// Iterate over each component for the current entity that changed since the last time the system was run.
for tooltip in entity_tooltips.iter_changed() {
println!("Changed Tooltip: {}", tooltip.tooltip());
}
}
}
Similar to iter_changed
, we have iter_added
to detect entities which have had a trait-implementing component added since the last tick.
If you know you have only one component that implements the target trait,
you can use OneAdded
or OneChanged
which behave more like the typical
bevy
Added
/Changed
filters:
# use bevy::prelude::*;
# use bevy_trait_query::*;
#
# #[bevy_trait_query::queryable]
# pub trait Tooltip {
# fn tooltip(&self) -> &str;
# }
#
fn show_tooltips(
tooltips_query: Query<One<&dyn Tooltip>, OneChanged<dyn Tooltip>>
// ...
) {
// Iterate over each entity that has one tooltip implementing component that has also changed
for tooltip in &tooltips_query {
println!("Changed Tooltip: {}", tooltip.tooltip());
}
}
Note in the above example how OneChanged
does not take a reference to the trait object!
Performance
The performance of trait queries is quite competitive. Here are some benchmarks for simple cases:
Concrete type | One<dyn Trait> |
All<dyn Trait> |
|
---|---|---|---|
1 match | 8.395 µs | 28.174 µs | 81.027 µs |
2 matches | 8.473 µs | - | 106.47 µs |
1-2 matches | - | 14.619 µs | 92.876 µs |