|
| 1 | +use bevy::{ |
| 2 | + ecs::{ |
| 3 | + component::Component, |
| 4 | + query::{Fetch, FilterFetch}, |
| 5 | + }, |
| 6 | + prelude::*, |
| 7 | +}; |
| 8 | +use std::{fmt::Debug, marker::PhantomData}; |
| 9 | + |
| 10 | +/// This examples illustrates the usage of `Fetch` and `FilterFetch` derive macros, that allow |
| 11 | +/// defining custom query and filter types. |
| 12 | +/// |
| 13 | +/// White regular tuple queries work great in most of simple scenarios, using custom queries |
| 14 | +/// declared as named structs can bring the following advantages: |
| 15 | +/// - They help to avoid destructuring or using `q.0, q.1, ...` access pattern |
| 16 | +/// - Adding, removing components or changing items order with structs greatly reduces maintenance |
| 17 | +/// burden, as you don't need to update statements that destructure tuples, care abort order |
| 18 | +/// of elements, etc. Instead, you can just add or remove places where a certain element is used |
| 19 | +/// - Named structs enable the composition pattern, that makes query types easier to re-use |
| 20 | +/// - They allow to go over the limit of 15 components that exists for query tuples |
| 21 | +/// |
| 22 | +/// For more details on the `Fetch` and `FilterFetch` derive macros, see their documentation. |
| 23 | +fn main() { |
| 24 | + App::new() |
| 25 | + .add_startup_system(spawn) |
| 26 | + .add_system(print_components.system().label("print_components")) |
| 27 | + .add_system( |
| 28 | + print_components_readonly |
| 29 | + .system() |
| 30 | + .label("print_components_readonly") |
| 31 | + .after("print_components"), |
| 32 | + ) |
| 33 | + .add_system( |
| 34 | + print_components_tuple |
| 35 | + .system() |
| 36 | + .after("print_components_readonly"), |
| 37 | + ) |
| 38 | + .run(); |
| 39 | +} |
| 40 | + |
| 41 | +#[derive(Debug)] |
| 42 | +struct ComponentA; |
| 43 | +#[derive(Debug)] |
| 44 | +struct ComponentB; |
| 45 | +#[derive(Debug)] |
| 46 | +struct ComponentC; |
| 47 | +#[derive(Debug)] |
| 48 | +struct ComponentD; |
| 49 | +#[derive(Debug)] |
| 50 | +struct ComponentZ; |
| 51 | + |
| 52 | +#[derive(Fetch)] |
| 53 | +struct MutQuery<'w, T: Component + Debug, P: Component + Debug> { |
| 54 | + entity: Entity, |
| 55 | + a: Mut<'w, ComponentA>, |
| 56 | + b: Option<Mut<'w, ComponentB>>, |
| 57 | + nested: NestedQuery<'w>, |
| 58 | + generic: GenericQuery<'w, T, P>, |
| 59 | + #[filter(QueryFilter<T, P>)] |
| 60 | + filter: bool, |
| 61 | +} |
| 62 | + |
| 63 | +// If you want to declare a read-only query that uses nested `Fetch` structs, you need to |
| 64 | +// specify `readonly` attribute for the corresponding fields. This will generate static assertions |
| 65 | +// that those members implement `ReadOnlyFetch`. |
| 66 | +#[derive(Fetch)] |
| 67 | +struct ReadOnlyNumQuery<'w, T: Component, P: Component> { |
| 68 | + entity: Entity, |
| 69 | + a: &'w ComponentA, |
| 70 | + b: &'w ComponentB, |
| 71 | + #[readonly] |
| 72 | + nested: NestedQuery<'w>, |
| 73 | + #[readonly] |
| 74 | + generic: GenericQuery<'w, T, P>, |
| 75 | + #[filter(QueryFilter<T, P>)] |
| 76 | + filter: bool, |
| 77 | +} |
| 78 | + |
| 79 | +#[derive(Fetch, Debug)] |
| 80 | +struct NestedQuery<'w> { |
| 81 | + c: &'w ComponentC, |
| 82 | + d: Option<&'w ComponentD>, |
| 83 | +} |
| 84 | + |
| 85 | +#[derive(Fetch, Debug)] |
| 86 | +struct GenericQuery<'w, T: Component, P: Component> { |
| 87 | + generic: (&'w T, &'w P), |
| 88 | +} |
| 89 | + |
| 90 | +#[derive(FilterFetch)] |
| 91 | +struct QueryFilter<T: Component, P: Component> { |
| 92 | + _c: With<ComponentC>, |
| 93 | + _d: With<ComponentD>, |
| 94 | + _or: Or<(Added<ComponentC>, Changed<ComponentD>, Without<ComponentZ>)>, |
| 95 | + _generic_tuple: (With<T>, With<P>), |
| 96 | + _tp: PhantomData<(T, P)>, |
| 97 | +} |
| 98 | + |
| 99 | +fn spawn(mut commands: Commands) { |
| 100 | + commands |
| 101 | + .spawn() |
| 102 | + .insert(ComponentA) |
| 103 | + .insert(ComponentB) |
| 104 | + .insert(ComponentC) |
| 105 | + .insert(ComponentD); |
| 106 | +} |
| 107 | + |
| 108 | +fn print_components( |
| 109 | + mut query: Query<MutQuery<ComponentC, ComponentD>, QueryFilter<ComponentC, ComponentD>>, |
| 110 | +) { |
| 111 | + println!("Print components:"); |
| 112 | + for e in query.iter_mut() { |
| 113 | + println!("Entity: {:?}", e.entity); |
| 114 | + println!("A: {:?}", e.a); |
| 115 | + println!("B: {:?}", e.b); |
| 116 | + println!("Nested: {:?}", e.nested); |
| 117 | + println!("Generic: {:?}", e.generic); |
| 118 | + println!("Filter: {:?}", e.filter); |
| 119 | + } |
| 120 | + println!(); |
| 121 | +} |
| 122 | + |
| 123 | +fn print_components_readonly( |
| 124 | + query: Query<ReadOnlyNumQuery<ComponentC, ComponentD>, QueryFilter<ComponentC, ComponentD>>, |
| 125 | +) { |
| 126 | + println!("Print components (read-only):"); |
| 127 | + for e in query.iter() { |
| 128 | + println!("Entity: {:?}", e.entity); |
| 129 | + println!("A: {:?}", e.a); |
| 130 | + println!("B: {:?}", e.b); |
| 131 | + println!("Nested: {:?}", e.nested); |
| 132 | + println!("Generic: {:?}", e.generic); |
| 133 | + println!("Filter: {:?}", e.filter); |
| 134 | + } |
| 135 | + println!(); |
| 136 | +} |
| 137 | + |
| 138 | +type NestedTupleQuery<'w> = (&'w ComponentC, &'w ComponentD); |
| 139 | +type GenericTupleQuery<'w, T, P> = (&'w T, &'w P); |
| 140 | + |
| 141 | +fn print_components_tuple( |
| 142 | + query: Query< |
| 143 | + ( |
| 144 | + Entity, |
| 145 | + &ComponentA, |
| 146 | + &ComponentB, |
| 147 | + NestedTupleQuery, |
| 148 | + GenericTupleQuery<ComponentC, ComponentD>, |
| 149 | + ), |
| 150 | + ( |
| 151 | + With<ComponentC>, |
| 152 | + With<ComponentD>, |
| 153 | + Or<(Added<ComponentC>, Changed<ComponentD>, Without<ComponentZ>)>, |
| 154 | + ), |
| 155 | + >, |
| 156 | +) { |
| 157 | + println!("Print components (tuple):"); |
| 158 | + for (entity, a, b, nested, (generic_c, generic_d)) in query.iter() { |
| 159 | + println!("Entity: {:?}", entity); |
| 160 | + println!("A: {:?}", a); |
| 161 | + println!("B: {:?}", b); |
| 162 | + println!("Nested: {:?} {:?}", nested.0, nested.1); |
| 163 | + println!("Generic: {:?} {:?}", generic_c, generic_d); |
| 164 | + } |
| 165 | +} |
0 commit comments