Crate bevy_trait_query

source ·
Expand description

Lets say you have a trait that you wanna implement for some of your components.

/// Components that display a message when hovered.
pub trait Tooltip {
    /// Text displayed when hovering over an entity with this trait.
    fn tooltip(&self) -> &str;
}

In order to be useful within bevy, you’ll want to be able to query for this trait.


// Just add this attribute...
#[bevy_trait_query::queryable]
pub trait Tooltip {
    fn tooltip(&self) -> &str;
}

// ...and now you can use your trait in queries.
fn show_tooltips_system(
    tooltips: Query<&dyn Tooltip>,
    // ...
) {
    // ...
}

Since Rust unfortunately lacks any kind of reflection, it is necessary to register each component with the trait when the app gets built.

#[derive(Component)]
struct Player(String);

#[derive(Component)]
enum Villager {
    Farmer,
    // ...
}

#[derive(Component)]
struct Monster;

/* ...trait implementations omitted for brevity... */

struct TooltipPlugin;

impl Plugin for TooltipPlugin {
    fn build(&self, app: &mut App) {
        // We must import this trait in order to register our components.
        // If we don't register them, they will be invisible to the game engine.
        use bevy_trait_query::RegisterExt;

        app
            .register_component_as::<dyn Tooltip, Player>()
            .register_component_as::<dyn Tooltip, Villager>()
            .register_component_as::<dyn Tooltip, Monster>()
            .add_system(show_tooltips);
    }
}

Unlike queries for concrete types, it’s possible for an entity to have multiple components that match a trait query.


fn show_tooltips(
    tooltips: Query<&dyn Tooltip>,
    // ...
) {
    // Iterate over each entity that has tooltips.
    for entity_tooltips in &tooltips {
        // Iterate over each component implementing `Tooltip` for the current entity.
        for tooltip in entity_tooltips {
            println!("Tooltip: {}", tooltip.tooltip());
        }
    }

    // If you instead just want to iterate over all tooltips, you can do:
    for tooltip in tooltips.iter().flatten() {
        println!("Tooltip: {}", tooltip.tooltip());
    }
}

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 bevy_trait_query::One;

fn show_tooltips(
    tooltips: Query<One<&dyn Tooltip>>,
    // ...
) {
    for tooltip in &tooltips {
        println!("Tooltip: {}", tooltip.tooltip());
    }
}

Performance

The performance of trait queries is quite competitive. Here are some benchmarks for simple cases:

Concrete typeOneAll
1 match16.135 µs31.441 µs63.273 µs
2 matches17.501 µs-102.83 µs
1-2 matches-16.959 µs82.179 µs

Modules

Structs

WorldQuery adapter that fetches all implementations of a given trait for an entity.
[WorldQuery] adapter that fetches entities with exactly one component implementing a trait.
Read-access to all components implementing a trait for a given entity.
Write-access to all components implementing a trait for a given entity.

Traits

Extension methods for registering components with trait queries.
Marker for traits that can be used in queries.

Attribute Macros

When added to a trait declaration, generates the impls required to use that trait in queries.