Expand description

An implementation of trait queries for the bevy game engine.

Before using this crate, you should be familiar with bevy: https://bevyengine.org/. The current published version depends on bevy 0.8, although there is a branch on github that supports the upcoming version.

This crate is implementation of the following RFC: https://github.com/bevyengine/rfcs/pull/39.

Note on reliability

This crate is experimental, and not battle-tested. It seems to work in my personal testing, but it very well could contain undefined behavior. Use with caution (and miri!).

If you find a bug, please open an issue.

Overview

bevy-trait-query extends the capabilities of bevy by allowing you to query for components implementing a trait.

use bevy::prelude::*;
use bevy_trait_query::{impl_trait_query, RegisterExt};

// Some trait that we wish to use in queries.
pub trait Tooltip: 'static {
    fn tooltip(&self) -> &str;
}

// Add the necessary impls for querying.
impl_trait_query!(Tooltip);

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

impl Tooltip for Person {
    fn tooltip(&self) -> &str {
        &self.0
    }
}

#[derive(Component)]
struct Monster;

impl Tooltip for Monster {
    fn tooltip(&self) -> &str {
        "Run!"
    }
}

fn main() {
    App::new()
        // We must register each trait impl, otherwise they are invisible to the game engine.
        .register_component_as::<dyn Tooltip, Person>()
        .register_component_as::<dyn Tooltip, Monster>()
        .add_startup_system(setup)
        .add_system(show_tooltip)
        .add_system(show_all_tooltips)
}

fn setup(mut commands: Commands) {
    commands.spawn().insert(Person("Fourier".to_owned()));
    commands.spawn().insert(Monster);
}

use bevy_trait_query::One;
fn show_tooltip(
    // Query for entities with exactly one component implementing the trait.
    query: Query<One<&dyn Tooltip>>,
    // ...
) {
    for tt in &query {
        let mouse_hovered = {
            // ...
        };
        if mouse_hovered {
            println!("{}", tt.tooltip());
        }
    }
}

use bevy_trait_query::All;
fn show_all_tooltips(
    // Query that returns all trait impls for each entity.
    query: Query<All<&dyn Tooltip>>,
) {
    for tooltips in &query {
        // Loop over all tooltip impls for this entity.
        for tt in tooltips {
            let mouse_hovered = {
                // ...
            };
            if mouse_hovered {
                println!("{}", tt.tooltip());
            }
        }
    }
}

Performance

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

Concrete typeOneAll
1 match16.931 µs29.692 µs63.095 µs
2 matches17.508 µs-101.88 µs
1-2 matches-28.840 µs83.035 µs

On the nightly branch, performance is comparable to concrete queries:

Concrete typeOneAll
1 match17.017 µs20.432 µs61.896 µs
2 matches17.560 µs-90.160 µs
1-2 matches-22.247 µs75.418 µs

Modules

Macros

Structs

WorldQuery adapter that fetches all implementations of a given trait for an entity.
Query adapter for entities with a single trait impl.
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