This crate provides macros and a trait to generate disjoint query filters for Bevy queries.
This crate is primarily intended to satisfy the constraints of error B0001
("it is not possible to have two queries on the same component when one requests mutable access to it in the same system"),
but avoid the suggested (With<A>, Without<B>, Without<C>)
boilerplate in query filters.
A secondary objective is to make marker components easier to create.
Instead of Query<&mut Transform, (With<A>, Without<B>, Without<C>)
,
our Bevy queries can look like Query<&mut Transform, <A as Disjoint>::Only>
.
This is somewhat equivalent to if Rust had enum variant types and if we enforced that entities didn't have more than one variant at a time. Or put another way, this is similar to having an index where you can look up entities by the value of enum variants.
Instead of
fn complex_system(
a_query: Query<&mut Transform, (With<A>, Without<B>, Without<C>, Without<D>, Without<E>, Without<F>, Without<G>, ..., Without<Z>)>,
b_query: Query<&mut Transform, (Without<A>, With<B>, Without<C>, Without<D>, Without<E>, Without<F>, Without<G>, ..., Without<Z>)>,
...,
z_query: Query<&mut Transform, (Without<A>, Without<B>, Without<C>, Without<D>, Without<E>, Without<F>, Without<G>, ..., With<Z>)>,
) {
// ...
}
We can have
fn complex_system(
a_query: Query<&mut Transform, <A as Disjoint>::Only>,
b_query: Query<&mut Transform, <B as Disjoint>::Only>,
...,
z_query: Query<&mut Transform, <Z as Disjoint>::Only>,
) {
// ...
}
The [disjoint
] macro can be used to generate disjoint query filters for a list of types.
For example, disjoint!(A, B, C);
generates the following query filters:
<A as Disjoint>::Only
- Equivalent to:
(With<A>, Without<B>, Without<C>)
- Equivalent to:
<B as Disjoint>::Only
- Equivalent to:
(Without<A>, With<B>, Without<C>)
- Equivalent to:
<C as Disjoint>::Only
- Equivalent to:
(Without<A>, Without<B>, With<C>)
- Equivalent to:
<A as Disjoint>::Other
- Equivalent to:
(Without<A>, Or<(With<B>, With<C>)>)
- Equivalent to:
<B as Disjoint>::Other
- Equivalent to:
(Without<B>, Or<(With<A>, With<C>)>)
- Equivalent to:
<C as Disjoint>::Other
- Equivalent to:
(Without<C>, Or<(With<A>, With<B>)>)
- Equivalent to:
<A as Disjoint>::Any
- Equivalent to:
Or<(With<A>, With<B>, With<C>)>
- Equivalent to:
<B as Disjoint>::Any
- Equivalent to:
Or<(With<A>, With<B>, With<C>)>
- Equivalent to:
<C as Disjoint>::Any
- Equivalent to:
Or<(With<A>, With<B>, With<C>)>
- Equivalent to:
use bevy::prelude::*;
use bevy_djqf::{Disjoint, disjoint};
#[derive(Component, Debug, Default)]
struct A;
#[derive(Component, Debug, Default)]
struct B;
#[derive(Component, Debug, Default)]
struct C;
disjoint!(A, B, C);
fn a(
_only_a_query: Query<&mut Transform, <A as Disjoint>::Only>,
_except_a_query: Query<&mut Transform, <A as Disjoint>::Other>,
) {}
fn b(
_only_b_query: Query<&mut Transform, <B as Disjoint>::Only>,
_except_b_query: Query<&mut Transform, <B as Disjoint>::Other>,
) {}
App::new().add_systems(Update, (a, b));
Alternatively, you can generate the types at the same time using the [make_disjoint_markers
] macro,
with you providing a template macro for generating a single marker type.
use bevy::prelude::*;
use bevy_djqf::{Disjoint, make_disjoint_markers};
macro_rules! type_template {
($Name:ident) => {
#[derive(Component, Debug, Default)]
struct $Name;
};
}
make_disjoint_markers!(type_template for A, B, C);
fn a(
_only_a_query: Query<&mut Transform, <A as Disjoint>::Only>,
_except_a_query: Query<&mut Transform, <A as Disjoint>::Other>,
) {}
fn b(
_only_b_query: Query<&mut Transform, <B as Disjoint>::Only>,
_except_b_query: Query<&mut Transform, <B as Disjoint>::Other>,
) {}
App::new().add_systems(Update, (a, b));