pub struct Query<T>where
T: QueryTuple,{ /* private fields */ }
Expand description
Queries quickly find entities that match a list of conditions, and are at the core of many Flecs features like systems, observers, tooling and serialization.
Flecs queries can do anything from returning entities that match a simple list of components, to matching complex patterns against entity graphs.
See the Flecs Query Manual for in-depth documentation of queries.
They can be either:
- cached, which means they are stored in the world and can be retrieved by name or entity. They don’t go out of scope until explicitly destroyed. They are slower to create than uncached queries, but faster to iterate.
- uncached, which means they are created on the fly and are only valid for the duration of the query, scope. They are faster to create than cached queries, but slower to iterate.
§Safety
Queries are reference counted and won’t cause any lifetime issues or dangling references. You need to ensure that you’re holding no query objects anymore when the world is destroyed. This will otherwise panic.
§See also
Implementations§
Source§impl<T> Query<T>where
T: QueryTuple,
impl<T> Query<T>where
T: QueryTuple,
Sourcepub unsafe fn new_from(query: NonNull<ecs_query_t>) -> Self
pub unsafe fn new_from(query: NonNull<ecs_query_t>) -> Self
wraps the query pointer in a new query
§Safety
this is unsafe due to the fact that the type of the query is not checked.
the user is responsible for ensuring that the query is of the correct type.
if not possible, only use .iter
functions that do not pass in the components in the callback
§Arguments
query
- The query pointer to wrap
§See also
- C++ API:
query::query
Sourcepub fn destruct(self)
pub fn destruct(self)
Destroy a query and its resources.
If the query is used as the parent of subqueries, those subqueries will be orphaned and must be deinitialized as well.
§See also
- C++ API:
query_base::destruct
Examples found in repository?
75fn main() {
76 let world = World::new();
77
78 // Register components in order so that id for First is lower than Third
79 world.component::<First>();
80 world.component::<Second>();
81 world.component::<Third>();
82
83 // Grouped query
84 let query = world
85 .query::<(&Position,)>()
86 .group_by::<Group>()
87 // Callback invoked when a new group is created
88 .on_group_create(Some(callback_group_create))
89 // Callback invoked when a group is deleted
90 .on_group_delete(Some(callback_group_delete))
91 .build();
92
93 // Create entities in 6 different tables with 3 group ids
94 world
95 .entity()
96 .add::<(Group, Third)>()
97 .set(Position { x: 1.0, y: 1.0 });
98 world
99 .entity()
100 .add::<(Group, Second)>()
101 .set(Position { x: 2.0, y: 2.0 });
102 world
103 .entity()
104 .add::<(Group, First)>()
105 .set(Position { x: 3.0, y: 3.0 });
106
107 world
108 .entity()
109 .add::<(Group, Third)>()
110 .set(Position { x: 4.0, y: 4.0 })
111 .add::<Tag>();
112 world
113 .entity()
114 .add::<(Group, Second)>()
115 .set(Position { x: 5.0, y: 5.0 })
116 .add::<Tag>();
117 world
118 .entity()
119 .add::<(Group, First)>()
120 .set(Position { x: 6.0, y: 6.0 })
121 .add::<Tag>();
122
123 println!();
124
125 // The query cache now looks like this:
126 // - group First:
127 // - table [Position, (Group, First)]
128 // - table [Position, Tag, (Group, First)]
129 //
130 // - group Second:
131 // - table [Position, (Group, Second)]
132 // - table [Position, Tag, (Group, Second)]
133 //
134 // - group Third:
135 // - table [Position, (Group, Third)]
136 // - table [Position, Tag, (Group, Third)]
137 //
138
139 query.run_iter(|it, (pos,)| {
140 let group = world.entity_from_id(it.group_id());
141 let ctx = unsafe { &*(query.group_context(group) as *mut GroupCtx) };
142 println!(
143 "Group: {:?} - Table: [{:?}] - Counter: {}",
144 group.path().unwrap(),
145 it.archetype(),
146 ctx.counter
147 );
148
149 for i in it.iter() {
150 println!(" [{:?}]", pos[i]);
151 }
152
153 println!();
154 });
155
156 // Deleting the query will call the on_group_deleted callback
157 query.destruct();
158
159 // Output:
160 // Group created: "Third"
161 // Group created: "Second"
162 // Group created: "First"
163 //
164 // Group: "::First" - Table: [Position, (Group,First)] - Counter: 3
165 // [Position { x: 3.0, y: 3.0 }]
166 //
167 // Group: "::First" - Table: [Position, Tag, (Group,First)] - Counter: 3
168 // [Position { x: 6.0, y: 6.0 }]
169 //
170 // Group: "::Second" - Table: [Position, (Group,Second)] - Counter: 2
171 // [Position { x: 2.0, y: 2.0 }]
172 //
173 // Group: "::Second" - Table: [Position, Tag, (Group,Second)] - Counter: 2
174 // [Position { x: 5.0, y: 5.0 }]
175 //
176 // Group: "::Third" - Table: [Position, (Group,Third)] - Counter: 1
177 // [Position { x: 1.0, y: 1.0 }]
178 //
179 // Group: "::Third" - Table: [Position, Tag, (Group,Third)] - Counter: 1
180 // [Position { x: 4.0, y: 4.0 }]
181 //
182 // Group deleted: "Second"
183 // Group deleted: "First"
184 // Group deleted: "Third"
185}
Sourcepub fn is_changed(&self) -> bool
pub fn is_changed(&self) -> bool
Returns whether the query data changed since the last iteration.
This operation must be invoked before obtaining the iterator, as this will reset the changed state.
§Returns
The operation will return true
after:
- new entities have been matched with
- matched entities were deleted
- matched components were changed
Otherwise, it will return false
.
§See also
TableIter::is_changed()
- C++ API:
query_base::changed
Examples found in repository?
25fn main() {
26 let world = World::new();
27
28 // Make Dirty inheritable so that queries can match it on prefabs
29 world
30 .component::<Dirty>()
31 .add_trait::<(flecs::OnInstantiate, flecs::Inherit)>();
32 //todo v4 bug flecs core
33
34 // Create a query that just reads a component. We'll use this query for
35 // change tracking. Change tracking for a query is automatically enabled
36 // when query::changed() is called.
37 // Each query has its own private dirty state which is reset only when the
38 // query is iterated.
39
40 let query_read = world.query::<&Position>().set_cached().build();
41
42 // Create a query that writes the component based on a Dirty state.
43 let query_write = world
44 .query::<(&Dirty, &mut Position)>()
45 .term_at(0)
46 .up_type::<flecs::IsA>() // Only match Dirty from prefab
47 .instanced() // Instanced iteration is faster (see example)
48 .build();
49
50 // Create two prefabs with a Dirty component. We can use this to share a
51 // single Dirty value for all entities in a table.
52 let prefab_dirty_false = world
53 .prefab_named("prefab_dirty_false")
54 .set(Dirty { value: false });
55
56 let prefab_dirty_true = world
57 .prefab_named("prefab_dirty_true")
58 .set(Dirty { value: true });
59
60 // Create instances of p1 and p2. Because the entities have different
61 // prefabs, they end up in different tables.
62 world
63 .entity_named("e1_dirty_false")
64 .is_a_id(prefab_dirty_false)
65 .set(Position { x: 10.0, y: 20.0 });
66
67 world
68 .entity_named("e2_dirty_false")
69 .is_a_id(prefab_dirty_false)
70 .set(Position { x: 30.0, y: 40.0 });
71
72 world
73 .entity_named("e3_dirty_true")
74 .is_a_id(prefab_dirty_true)
75 .set(Position { x: 40.0, y: 50.0 });
76
77 world
78 .entity_named("e4_dirty_true")
79 .is_a_id(prefab_dirty_true)
80 .set(Position { x: 50.0, y: 60.0 });
81
82 // We can use the changed() function on the query to check if any of the
83 // tables it is matched with has changed. Since this is the first time that
84 // we check this and the query is matched with the tables we just created,
85 // the function will return true.
86 println!();
87 println!("query_read.is_changed(): {}", query_read.is_changed());
88 println!();
89
90 // The changed state will remain true until we have iterated each table.
91 query_read.run(|mut iter| {
92 while iter.next() {
93 // With the it.changed() function we can check if the table we're
94 // currently iterating has changed since last iteration.
95 // Because this is the first time the query is iterated, all tables
96 // will show up as changed.
97 println!(
98 "iiter.is_changed() for table [{}]: {}",
99 iter.archetype().unwrap(),
100 iter.is_changed()
101 );
102 }
103 });
104
105 // Now that we have iterated all tables, the dirty state is reset.
106 println!();
107 println!("query_read.is_changed(): {:?}", query_read.is_changed());
108 println!();
109
110 // Iterate the write query. Because the Position term is InOut (default)
111 // iterating the query will write to the dirty state of iterated tables.
112 query_write.run_iter(|mut it, (dirty, pos)| {
113 println!("iterate table [{}]", it.archetype().unwrap());
114
115 // Because we enforced that Dirty is a shared component, we can check
116 // a single value for the entire table.
117 if !dirty[0].value {
118 // If the dirty flag is false, skip the table. This way the table's
119 // dirty state is not updated by the query.
120 it.skip();
121 println!("iter.skip() for table [{}]", it.archetype().unwrap());
122 return;
123 }
124
125 // For all other tables the dirty state will be set.
126 for i in it.iter() {
127 pos[i].x += 1.0;
128 pos[i].y += 1.0;
129 }
130 });
131
132 // One of the tables has changed, so q_read.changed() will return true
133 println!();
134 println!("query_read.is_changed(): {}", query_read.is_changed());
135 println!();
136
137 // When we iterate the read query, we'll see that one table has changed.
138 query_read.run(|mut iter| {
139 while iter.next() {
140 println!(
141 "iter.is_changed() for table [{}]: {}",
142 iter.archetype().unwrap(),
143 iter.is_changed()
144 );
145 }
146 });
147 println!();
148
149 // Output:
150 // query_read.is_changed(): true
151 //
152 // iiter.is_changed() for table [Position, (Identifier,Name), (IsA,prefab_dirty_false)]: true
153 // iiter.is_changed() for table [Position, (Identifier,Name), (IsA,prefab_dirty_true)]: true
154 //
155 // query_read.is_changed(): false
156 //
157 // iterate table [Position, (Identifier,Name), (IsA,prefab_dirty_false)]
158 // iter.skip() for table [Position, (Identifier,Name), (IsA,prefab_dirty_false)]
159 // iterate table [Position, (Identifier,Name), (IsA,prefab_dirty_true)]
160 //
161 // query_read.is_changed(): true
162 //
163 // iter.is_changed() for table [Position, (Identifier,Name), (IsA,prefab_dirty_false)]: false
164 // iter.is_changed() for table [Position, (Identifier,Name), (IsA,prefab_dirty_true)]: true
165}
Sourcepub fn group_info(
&self,
group_id: impl Into<Entity>,
) -> *const ecs_query_group_info_t
pub fn group_info( &self, group_id: impl Into<Entity>, ) -> *const ecs_query_group_info_t
Sourcepub fn group_context(&self, group_id: impl Into<Entity>) -> *mut c_void
pub fn group_context(&self, group_id: impl Into<Entity>) -> *mut c_void
Get context for group
§Arguments
group_id
- The group id to get context for
§Returns
Returns a (void) pointer to the group context
§See also
- C++ API:
query_base::group_ctx
Examples found in repository?
75fn main() {
76 let world = World::new();
77
78 // Register components in order so that id for First is lower than Third
79 world.component::<First>();
80 world.component::<Second>();
81 world.component::<Third>();
82
83 // Grouped query
84 let query = world
85 .query::<(&Position,)>()
86 .group_by::<Group>()
87 // Callback invoked when a new group is created
88 .on_group_create(Some(callback_group_create))
89 // Callback invoked when a group is deleted
90 .on_group_delete(Some(callback_group_delete))
91 .build();
92
93 // Create entities in 6 different tables with 3 group ids
94 world
95 .entity()
96 .add::<(Group, Third)>()
97 .set(Position { x: 1.0, y: 1.0 });
98 world
99 .entity()
100 .add::<(Group, Second)>()
101 .set(Position { x: 2.0, y: 2.0 });
102 world
103 .entity()
104 .add::<(Group, First)>()
105 .set(Position { x: 3.0, y: 3.0 });
106
107 world
108 .entity()
109 .add::<(Group, Third)>()
110 .set(Position { x: 4.0, y: 4.0 })
111 .add::<Tag>();
112 world
113 .entity()
114 .add::<(Group, Second)>()
115 .set(Position { x: 5.0, y: 5.0 })
116 .add::<Tag>();
117 world
118 .entity()
119 .add::<(Group, First)>()
120 .set(Position { x: 6.0, y: 6.0 })
121 .add::<Tag>();
122
123 println!();
124
125 // The query cache now looks like this:
126 // - group First:
127 // - table [Position, (Group, First)]
128 // - table [Position, Tag, (Group, First)]
129 //
130 // - group Second:
131 // - table [Position, (Group, Second)]
132 // - table [Position, Tag, (Group, Second)]
133 //
134 // - group Third:
135 // - table [Position, (Group, Third)]
136 // - table [Position, Tag, (Group, Third)]
137 //
138
139 query.run_iter(|it, (pos,)| {
140 let group = world.entity_from_id(it.group_id());
141 let ctx = unsafe { &*(query.group_context(group) as *mut GroupCtx) };
142 println!(
143 "Group: {:?} - Table: [{:?}] - Counter: {}",
144 group.path().unwrap(),
145 it.archetype(),
146 ctx.counter
147 );
148
149 for i in it.iter() {
150 println!(" [{:?}]", pos[i]);
151 }
152
153 println!();
154 });
155
156 // Deleting the query will call the on_group_deleted callback
157 query.destruct();
158
159 // Output:
160 // Group created: "Third"
161 // Group created: "Second"
162 // Group created: "First"
163 //
164 // Group: "::First" - Table: [Position, (Group,First)] - Counter: 3
165 // [Position { x: 3.0, y: 3.0 }]
166 //
167 // Group: "::First" - Table: [Position, Tag, (Group,First)] - Counter: 3
168 // [Position { x: 6.0, y: 6.0 }]
169 //
170 // Group: "::Second" - Table: [Position, (Group,Second)] - Counter: 2
171 // [Position { x: 2.0, y: 2.0 }]
172 //
173 // Group: "::Second" - Table: [Position, Tag, (Group,Second)] - Counter: 2
174 // [Position { x: 5.0, y: 5.0 }]
175 //
176 // Group: "::Third" - Table: [Position, (Group,Third)] - Counter: 1
177 // [Position { x: 1.0, y: 1.0 }]
178 //
179 // Group: "::Third" - Table: [Position, Tag, (Group,Third)] - Counter: 1
180 // [Position { x: 4.0, y: 4.0 }]
181 //
182 // Group deleted: "Second"
183 // Group deleted: "First"
184 // Group deleted: "Third"
185}
Trait Implementations§
Source§impl<'a, T> QueryAPI<'a, (), T> for Query<T>where
T: QueryTuple,
impl<'a, T> QueryAPI<'a, (), T> for Query<T>where
T: QueryTuple,
Source§fn entity(&self) -> EntityView<'_>
fn entity(&self) -> EntityView<'_>
Source§fn each(&self, func: impl FnMut(T::TupleType<'_>))
fn each(&self, func: impl FnMut(T::TupleType<'_>))
Source§fn each_entity(&self, func: impl FnMut(EntityView<'_>, T::TupleType<'_>))
fn each_entity(&self, func: impl FnMut(EntityView<'_>, T::TupleType<'_>))
Source§fn each_iter(
&self,
func: impl FnMut(TableIter<'_, false, P>, usize, T::TupleType<'_>),
)where
P: ComponentId,
fn each_iter(
&self,
func: impl FnMut(TableIter<'_, false, P>, usize, T::TupleType<'_>),
)where
P: ComponentId,
Source§fn find(
&self,
func: impl FnMut(T::TupleType<'_>) -> bool,
) -> Option<EntityView<'a>>
fn find( &self, func: impl FnMut(T::TupleType<'_>) -> bool, ) -> Option<EntityView<'a>>
Source§fn find_entity(
&self,
func: impl FnMut(EntityView<'_>, T::TupleType<'_>) -> bool,
) -> Option<EntityView<'a>>
fn find_entity( &self, func: impl FnMut(EntityView<'_>, T::TupleType<'_>) -> bool, ) -> Option<EntityView<'a>>
Source§fn find_iter(
&self,
func: impl FnMut(TableIter<'_, false, P>, usize, T::TupleType<'_>) -> bool,
) -> Option<EntityView<'a>>where
P: ComponentId,
fn find_iter(
&self,
func: impl FnMut(TableIter<'_, false, P>, usize, T::TupleType<'_>) -> bool,
) -> Option<EntityView<'a>>where
P: ComponentId,
Source§fn run_iter(
&self,
func: impl FnMut(TableIter<'_, false, P>, T::TupleSliceType<'_>),
)where
P: ComponentId,
fn run_iter(
&self,
func: impl FnMut(TableIter<'_, false, P>, T::TupleSliceType<'_>),
)where
P: ComponentId,
run()
Read moreSource§fn run(&self, func: impl FnMut(TableIter<'_, true, P>))where
P: ComponentId,
fn run(&self, func: impl FnMut(TableIter<'_, true, P>))where
P: ComponentId,
Source§fn run_each<FuncEach>(
&self,
func: impl FnMut(TableIter<'_, true, P>),
func_each: FuncEach,
)where
P: ComponentId,
FuncEach: FnMut(T::TupleType<'_>),
fn run_each<FuncEach>(
&self,
func: impl FnMut(TableIter<'_, true, P>),
func_each: FuncEach,
)where
P: ComponentId,
FuncEach: FnMut(T::TupleType<'_>),
Source§fn run_each_entity<FuncEachEntity>(
&self,
func: impl FnMut(TableIter<'_, true, P>),
func_each: FuncEachEntity,
)
fn run_each_entity<FuncEachEntity>( &self, func: impl FnMut(TableIter<'_, true, P>), func_each: FuncEachEntity, )
Source§fn each_term(&self, func: impl FnMut(&TermRef<'_>))
fn each_term(&self, func: impl FnMut(&TermRef<'_>))
each_term
iterator accepts a function that is invoked for each term
in the query. The following function signature is valid: Read moreSource§fn term(&self, index: usize) -> TermRef<'_>
fn term(&self, index: usize) -> TermRef<'_>
Source§fn field_count(&self) -> i8
fn field_count(&self) -> i8
Source§fn term_count(&self) -> u32
fn term_count(&self) -> u32
Source§fn to_string(&self) -> String
fn to_string(&self) -> String
fn find_var(&self, name: &str) -> Option<i32>
fn plan(&self) -> String
fn iterable(&self) -> QueryIter<'_, P, T>
fn iter_stage(&'a self, stage: impl WorldProvider<'a>) -> QueryIter<'a, P, T>
Source§fn first_entity(&mut self) -> Option<EntityView<'a>>
fn first_entity(&mut self) -> Option<EntityView<'a>>
Source§fn set_group_id(&mut self, group_id: impl Into<Entity>) -> QueryIter<'_, P, T>
fn set_group_id(&mut self, group_id: impl Into<Entity>) -> QueryIter<'_, P, T>
Source§fn set_group<Group: ComponentId>(&mut self) -> QueryIter<'_, P, T>
fn set_group<Group: ComponentId>(&mut self) -> QueryIter<'_, P, T>
Source§fn set_var(
&mut self,
var_id: i32,
value: impl Into<Entity>,
) -> QueryIter<'_, P, T>
fn set_var( &mut self, var_id: i32, value: impl Into<Entity>, ) -> QueryIter<'_, P, T>
Source§fn set_var_table(
&mut self,
var_id: i32,
table: impl IntoTableRange,
) -> QueryIter<'_, P, T>
fn set_var_table( &mut self, var_id: i32, table: impl IntoTableRange, ) -> QueryIter<'_, P, T>
Source§fn set_var_expr(
&mut self,
name: &str,
value: impl Into<Entity>,
) -> QueryIter<'_, P, T>
fn set_var_expr( &mut self, name: &str, value: impl Into<Entity>, ) -> QueryIter<'_, P, T>
Source§fn set_var_table_expr(
&mut self,
name: &str,
table: impl IntoTableRange,
) -> QueryIter<'_, P, T>
fn set_var_table_expr( &mut self, name: &str, table: impl IntoTableRange, ) -> QueryIter<'_, P, T>
Source§impl<'a, T> WorldProvider<'a> for Query<T>where
T: QueryTuple,
impl<'a, T> WorldProvider<'a> for Query<T>where
T: QueryTuple,
impl<T> IterOperations for Query<T>where
T: QueryTuple,
Auto Trait Implementations§
impl<T> Freeze for Query<T>
impl<T> RefUnwindSafe for Query<T>where
T: RefUnwindSafe,
impl<T> !Send for Query<T>
impl<T> !Sync for Query<T>
impl<T> Unpin for Query<T>where
T: Unpin,
impl<T> UnwindSafe for Query<T>where
T: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<'a, T> Doc<'a> for T
impl<'a, T> Doc<'a> for T
Source§fn set_doc_name(&self, name: &str) -> &Self
fn set_doc_name(&self, name: &str) -> &Self
flecs_doc
only.Source§fn set_doc_brief(&self, brief: &str) -> &Self
fn set_doc_brief(&self, brief: &str) -> &Self
flecs_doc
only.Source§fn set_doc_detail(&self, detail: &str) -> &Self
fn set_doc_detail(&self, detail: &str) -> &Self
flecs_doc
only.Source§fn set_doc_link(&self, link: &str) -> &Self
fn set_doc_link(&self, link: &str) -> &Self
flecs_doc
only.Source§fn set_doc_color(&self, color: &str) -> &Self
fn set_doc_color(&self, color: &str) -> &Self
flecs_doc
only.