pub struct Query<'world, 'state, D, F = ()>where
D: QueryData,
F: QueryFilter,{ /* private fields */ }Expand description
A system parameter that provides selective access to the Component data stored in a World.
Queries enable systems to access entity identifiers and components without requiring direct access to the World.
Its iterators and getter methods return query items, which are types containing data related to an entity.
Query is a generic data structure that accepts two type parameters:
D(query data): The type of data fetched by the query, which will be returned as the query item. Only entities that match the requested data will generate an item. Must implement theQueryDatatrait.F(query filter): An optional set of conditions that determine whether query items should be kept or discarded. This defaults tounit, which means no additional filters will be applied. Must implement theQueryFiltertrait.
§Similar parameters
Query has few sibling SystemParams, which perform additional validation:
Single- Exactly one matching query item.Option<Single>- Zero or one matching query item.Populated- At least one matching query item.
These parameters will prevent systems from running if their requirements are not met.
§System parameter declaration
A query should always be declared as a system parameter.
This section shows the most common idioms involving the declaration of Query.
§Component access
You can fetch an entity’s component by specifying a reference to that component in the query’s data parameter:
// A component can be accessed by a shared reference...
fn immutable_query(query: Query<&ComponentA>) {
// ...
}
// ...or by a mutable reference.
fn mutable_query(query: Query<&mut ComponentA>) {
// ...
}Note that components need to be behind a reference (& or &mut), or the query will not compile:
// This needs to be `&ComponentA` or `&mut ComponentA` in order to compile.
fn invalid_query(query: Query<ComponentA>) {
// ...
}§Query filtering
Setting the query filter type parameter will ensure that each query item satisfies the given condition:
// `ComponentA` data will be accessed, but only for entities that also contain `ComponentB`.
fn filtered_query(query: Query<&ComponentA, With<ComponentB>>) {
// ...
}Note that the filter is With<ComponentB>, not With<&ComponentB>. Unlike query data, With
does not require components to be behind a reference.
§QueryData or QueryFilter tuples
Using tuples, each Query type parameter can contain multiple elements.
In the following example two components are accessed simultaneously, and the query items are filtered on two conditions:
fn complex_query(
query: Query<(&mut ComponentA, &ComponentB), (With<ComponentC>, Without<ComponentD>)>
) {
// ...
}Note that this currently only works on tuples with 15 or fewer items. You may nest tuples to get around this limit:
fn nested_query(
query: Query<(&ComponentA, &ComponentB, (&mut ComponentC, &mut ComponentD))>
) {
// ...
}§Entity identifier access
You can access Entity, the entity identifier, by including it in the query data parameter:
fn entity_id_query(query: Query<(Entity, &ComponentA)>) {
// ...
}Be aware that Entity is not a component, so it does not need to be behind a reference.
§Optional component access
A component can be made optional by wrapping it into an Option. In the following example, a
query item will still be generated even if the queried entity does not contain ComponentB.
When this is the case, Option<&ComponentB>’s corresponding value will be None.
// Queried items must contain `ComponentA`. If they also contain `ComponentB`, its value will
// be fetched as well.
fn optional_component_query(query: Query<(&ComponentA, Option<&ComponentB>)>) {
// ...
}Optional components can hurt performance in some cases, so please read the performance
section to learn more about them. Additionally, if you need to declare several optional
components, you may be interested in using AnyOf.
§Disjoint queries
A system cannot contain two queries that break Rust’s mutability rules, or else it will panic
when initialized. This can often be fixed with the Without filter, which makes the queries
disjoint.
In the following example, the two queries can mutably access the same &mut Health component
if an entity has both the Player and Enemy components. Bevy will catch this and panic,
however, instead of breaking Rust’s mutability rules:
fn randomize_health(
player_query: Query<&mut Health, With<Player>>,
enemy_query: Query<&mut Health, With<Enemy>>,
) {
// ...
}Adding a Without filter will disjoint the queries. In the following example, any entity
that has both the Player and Enemy components will be excluded from both queries:
fn randomize_health(
player_query: Query<&mut Health, (With<Player>, Without<Enemy>)>,
enemy_query: Query<&mut Health, (With<Enemy>, Without<Player>)>,
) {
// ...
}An alternative solution to this problem would be to wrap the conflicting queries in
ParamSet.
§Whole Entity Access
EntityRef can be used in a query to gain read-only access to all components of an entity.
This is useful when dynamically fetching components instead of baking them into the query type.
fn all_components_query(query: Query<(EntityRef, &ComponentA)>) {
// ...
}As EntityRef can read any component on an entity, a query using it will conflict with any
mutable component access.
// `EntityRef` provides read access to *all* components on an entity. When combined with
// `&mut ComponentA` in the same query, it creates a conflict because `EntityRef` could read
// `&ComponentA` while `&mut ComponentA` attempts to modify it - violating Rust's borrowing
// rules.
fn invalid_query(query: Query<(EntityRef, &mut ComponentA)>) {
// ...
}It is strongly advised to couple EntityRef queries with the use of either With /
Without filters or ParamSets. Not only does this improve the performance and
parallelization of the system, but it enables systems to gain mutable access to other
components:
// The first query only reads entities that have `ComponentA`, while the second query only
// modifies entities that *don't* have `ComponentA`. Because neither query will access the same
// entity, this system does not conflict.
fn disjoint_query(
query_a: Query<EntityRef, With<ComponentA>>,
query_b: Query<&mut ComponentB, Without<ComponentA>>,
) {
// ...
}The fundamental rule: EntityRef’s ability to read all components means it can never
coexist with mutable access. With / Without filters can guarantee this by keeping the
queries on completely separate entities.
§Accessing query items
The following table summarizes the behavior of safe methods that can be used to get query items:
| Query methods | Effect |
|---|---|
iter[_mut] | Returns an iterator over all query items. |
iter[_mut]().for_each(),par_iter[_mut] | Runs a specified function for each query item. |
iter_many[_unique][_mut] | Iterates over query items that match a list of entities. |
iter_combinations[_mut] | Iterates over all combinations of query items. |
single[_mut] | Returns a single query item if only one exists. |
get[_mut] | Returns the query item for a specified entity. |
get_many[_unique][_mut] | Returns all query items that match a list of entities. |
There are two methods for each type of query operation: immutable and mutable (ending with _mut).
When using immutable methods, the query items returned are of type ROQueryItem, a read-only version of the query item.
In this circumstance, every mutable reference in the query fetch type parameter is substituted by a shared reference.
§Performance
Creating a Query is a low-cost constant operation. Iterating it, on the other hand, fetches
data from the world and generates items, which can have a significant computational cost.
Two systems cannot be executed in parallel if both access the same component type where at least one of the accesses is mutable. Because of this, it is recommended for queries to only fetch mutable access to components when necessary, since immutable access can be parallelized.
Query filters (With / Without) can improve performance because they narrow the kinds of
entities that can be fetched. Systems that access fewer kinds of entities are more likely to be
parallelized by the scheduler.
On the other hand, be careful using optional components (Option<&ComponentA>) and
EntityRef because they broaden the amount of entities kinds that can be accessed. This is
especially true of a query that only fetches optional components or EntityRef, as the
query would iterate over all entities in the world.
There are two types of component storage types: Table and SparseSet. Table offers
fast iteration speeds, but slower insertion and removal speeds. SparseSet is the opposite:
it offers fast component insertion and removal speeds, but slower iteration speeds.
The following table compares the computational complexity of the various methods and operations, where:
- n is the number of entities that match the query.
- r is the number of elements in a combination.
- k is the number of involved entities in the operation.
- a is the number of archetypes in the world.
- C is the binomial coefficient, used to count combinations. nCr is read as “n choose r” and is equivalent to the number of distinct unordered subsets of r elements that can be taken from a set of n elements.
| Query operation | Computational complexity |
|---|---|
iter[_mut] | O(n) |
iter[_mut]().for_each(),par_iter[_mut] | O(n) |
iter_many[_mut] | O(k) |
iter_combinations[_mut] | O(nCr) |
single[_mut] | O(a) |
get[_mut] | O(1) |
get_many | O(k) |
get_many_mut | O(k2) |
Archetype-based filtering (With, Without, Or) | O(a) |
Change detection filtering (Added, Changed, Spawned) | O(a + n) |
§Iterator::for_each
The for_each methods appear to be generally faster than for-loops when run on worlds with
high archetype fragmentation, and may enable additional optimizations like autovectorization. It
is strongly advised to only use Iterator::for_each if it tangibly improves performance.
Always profile or benchmark before and after the change!
fn system(query: Query<&ComponentA>) {
// This may result in better performance...
query.iter().for_each(|component| {
// ...
});
// ...than this. Always benchmark to validate the difference!
for component in query.iter() {
// ...
}
}Implementations§
Source§impl<'w, 's, D, F> Query<'w, 's, D, F>where
D: QueryData,
F: QueryFilter,
impl<'w, 's, D, F> Query<'w, 's, D, F>where
D: QueryData,
F: QueryFilter,
If the given entity contains the R Relationship component, returns the
target entity of that relationship.
Sourcepub fn relationship_sources<S>(
&'w self,
entity: Entity,
) -> impl Iterator<Item = Entity> + 'w
pub fn relationship_sources<S>( &'w self, entity: Entity, ) -> impl Iterator<Item = Entity> + 'w
If the given entity contains the S RelationshipTarget component, returns the
source entities stored on that component.
Sourcepub fn root_ancestor<R>(&'w self, entity: Entity) -> Entity
pub fn root_ancestor<R>(&'w self, entity: Entity) -> Entity
Recursively walks up the tree defined by the given R Relationship until
there are no more related entities, returning the “root entity” of the relationship hierarchy.
§Warning
For relationship graphs that contain loops, this could loop infinitely. If your relationship is not a tree (like Bevy’s hierarchy), be sure to stop if you encounter a duplicate entity.
Sourcepub fn iter_leaves<S>(
&'w self,
entity: Entity,
) -> impl Iterator<Item = Entity> + use<'w, 's, S, D, F>where
S: RelationshipTarget,
<D as QueryData>::ReadOnly: QueryData<Item<'w, 's> = &'w S>,
<<S as RelationshipTarget>::Collection as RelationshipSourceCollection>::SourceIter<'w>: DoubleEndedIterator,
pub fn iter_leaves<S>(
&'w self,
entity: Entity,
) -> impl Iterator<Item = Entity> + use<'w, 's, S, D, F>where
S: RelationshipTarget,
<D as QueryData>::ReadOnly: QueryData<Item<'w, 's> = &'w S>,
<<S as RelationshipTarget>::Collection as RelationshipSourceCollection>::SourceIter<'w>: DoubleEndedIterator,
Iterates all “leaf entities” as defined by the RelationshipTarget hierarchy.
§Warning
For relationship graphs that contain loops, this could loop infinitely. If your relationship is not a tree (like Bevy’s hierarchy), be sure to stop if you encounter a duplicate entity.
Examples found in repository?
198fn radio_button_scene(
199 constraint: Constraint,
200 action: RadioButtonValue,
201 label: String,
202 active: bool,
203) -> impl Scene {
204 bsn! {
205 RadioButton
206 Node {
207 align_items: AlignItems::Center,
208 justify_content: JustifyContent::Center,
209 border: UiRect::all(px(2)),
210 margin: UiRect::horizontal(px(2)),
211 }
212 BorderColor::all(if active {
213 ACTIVE_BORDER_COLOR
214 } else {
215 INACTIVE_BORDER_COLOR
216 })
217 constraint
218 action
219 Children [
220 Node {
221 width: px(100),
222 justify_content: JustifyContent::Center,
223 }
224 BackgroundColor({if active {
225 ACTIVE_INNER_COLOR
226 } else {
227 INACTIVE_INNER_COLOR
228 }})
229 Children [
230 Text(label)
231 @font_style_scene()
232 TextColor({if active {
233 ACTIVE_TEXT_COLOR
234 } else {
235 UNHOVERED_TEXT_COLOR
236 }})
237 TextLayout::justify(Justify::Center)
238 ]
239 ]
240 // Observers for updating text on hover/leave
241 on(|event: On<PointerOver>,
242 has_checked_query: Query<&Checked>,
243 child_q: Query<&Children>,
244 mut commands: Commands| {
245 if has_checked_query.contains(event.entity) {
246 return;
247 }
248
249 for text_entity in child_q.iter_leaves(event.entity) {
250 commands.entity(text_entity).insert(TextColor(HOVERED_TEXT_COLOR));
251 }
252 })
253 on(|event: On<PointerOut>,
254 has_checked_query: Query<&Checked>,
255 child_q: Query<&Children>,
256 mut commands: Commands| {
257 if has_checked_query.contains(event.entity) {
258 return;
259 }
260
261 for text_entity in child_q.iter_leaves(event.entity) {
262 commands.entity(text_entity).insert(TextColor(UNHOVERED_TEXT_COLOR));
263 }
264 })
265 }
266}
267
268/// This system updates the Bar when a new value for a constraint is selected, and marks
269/// the radio button as the one currently selected
270fn on_value_change_constraints(
271 event: On<ValueChange<Entity>>,
272 new_setting_query: Query<
273 (&Constraint, &RadioButtonValue, Entity, &Children),
274 (With<RadioButton>, Without<Checked>),
275 >,
276 previous_query: Query<
277 (&Constraint, &RadioButtonValue, Entity, &Children),
278 (With<RadioButton>, With<Checked>),
279 >,
280 child_q: Query<&Children>,
281 mut commands: Commands,
282 mut bar_node: Single<&mut Node, With<Bar>>,
283) {
284 if let Ok((constraint, value, entity, children)) = new_setting_query.get(event.value) {
285 for (previous_constraint, previous_value, previous_entity, previous_children) in
286 previous_query.iter()
287 {
288 if constraint == previous_constraint && value == previous_value {
289 // There is no change in constraint. We can exit out early.
290 return;
291 } else if constraint == previous_constraint {
292 commands.entity(previous_entity).remove::<Checked>();
293 commands
294 .entity(previous_entity)
295 .insert(BorderColor::all(INACTIVE_BORDER_COLOR));
296 // radio button entities only have one child which contains the inner background color.
297 commands
298 .entity(*previous_children.first().unwrap())
299 .insert(BackgroundColor(INACTIVE_INNER_COLOR));
300 for text_entity in child_q.iter_leaves(previous_entity) {
301 commands
302 .entity(text_entity)
303 .insert(TextColor(UNHOVERED_TEXT_COLOR));
304 }
305
306 commands.entity(entity).insert(Checked);
307 commands
308 .entity(entity)
309 .insert(BorderColor::all(ACTIVE_BORDER_COLOR));
310 commands
311 .entity(*children.first().unwrap())
312 .insert(BackgroundColor(ACTIVE_INNER_COLOR));
313 for text_entity in child_q.iter_leaves(entity) {
314 commands
315 .entity(text_entity)
316 .insert(TextColor(ACTIVE_TEXT_COLOR));
317 }
318 }
319 }
320
321 match constraint {
322 Constraint::FlexBasis => {
323 bar_node.flex_basis = value.0;
324 }
325 Constraint::Width => {
326 bar_node.width = value.0;
327 }
328 Constraint::MinWidth => {
329 bar_node.min_width = value.0;
330 }
331 Constraint::MaxWidth => {
332 bar_node.max_width = value.0;
333 }
334 }
335 }
336}Sourcepub fn iter_siblings<R>(
&'w self,
entity: Entity,
) -> impl Iterator<Item = Entity> + 'wwhere
R: Relationship,
<D as QueryData>::ReadOnly: QueryData<Item<'w, 's> = (Option<&'w R>, Option<&'w <R as Relationship>::RelationshipTarget>)>,
pub fn iter_siblings<R>(
&'w self,
entity: Entity,
) -> impl Iterator<Item = Entity> + 'wwhere
R: Relationship,
<D as QueryData>::ReadOnly: QueryData<Item<'w, 's> = (Option<&'w R>, Option<&'w <R as Relationship>::RelationshipTarget>)>,
Iterates all sibling entities that also have the R Relationship with the same target entity.
Sourcepub fn iter_descendants<S>(
&'w self,
entity: Entity,
) -> DescendantIter<'w, 's, D, F, S> ⓘ
pub fn iter_descendants<S>( &'w self, entity: Entity, ) -> DescendantIter<'w, 's, D, F, S> ⓘ
Iterates all descendant entities as defined by the given entity’s RelationshipTarget and their recursive
RelationshipTarget.
§Warning
For relationship graphs that contain loops, this could loop infinitely. If your relationship is not a tree (like Bevy’s hierarchy), be sure to stop if you encounter a duplicate entity.
Examples found in repository?
57fn move_scene_entities(
58 time: Res<Time>,
59 moved_scene: Query<Entity, With<MovedScene>>,
60 children: Query<&Children>,
61 mut transforms: Query<&mut Transform>,
62) {
63 for moved_scene_entity in &moved_scene {
64 let mut offset = 0.;
65 for entity in children.iter_descendants(moved_scene_entity) {
66 if let Ok(mut transform) = transforms.get_mut(entity) {
67 transform.translation = Vec3::new(
68 offset * ops::sin(time.elapsed_secs()) / 20.,
69 0.,
70 ops::cos(time.elapsed_secs()) / 20.,
71 );
72 offset += 0.5;
73 }
74 }
75 }
76}More examples
58fn play_animation_when_ready(
59 scene_ready: On<WorldInstanceReady>,
60 mut commands: Commands,
61 children: Query<&Children>,
62 animations_to_play: Query<&AnimationToPlay>,
63 mut players: Query<&mut AnimationPlayer>,
64) {
65 if let Ok(animation_to_play) = animations_to_play.get(scene_ready.entity) {
66 for child in children.iter_descendants(scene_ready.entity) {
67 if let Ok(mut player) = players.get_mut(child) {
68 player.play(animation_to_play.index).repeat();
69
70 commands
71 .entity(child)
72 .insert(AnimationGraphHandle(animation_to_play.graph_handle.clone()));
73 }
74 }
75 }
76}97fn play_animation(
98 trigger: On<WorldInstanceReady>,
99 mut commands: Commands,
100 children: Query<&Children>,
101 animations: Query<&PendingAnimation>,
102 mut players: Query<&mut AnimationPlayer>,
103) {
104 if let Ok(PendingAnimation((graph_handle, graph_node_index))) = animations.get(trigger.entity) {
105 for child in children.iter_descendants(trigger.entity) {
106 if let Ok(mut player) = players.get_mut(child) {
107 player.play(*graph_node_index).set_speed(0.6).repeat();
108
109 commands
110 .entity(child)
111 .insert(AnimationGraphHandle(graph_handle.clone()));
112 }
113 }
114 }
115
116 commands.entity(trigger.entity).remove::<PendingAnimation>();
117}267fn setup_scene_once_loaded(
268 scene_ready: On<WorldInstanceReady>,
269 animations: Res<Animations>,
270 foxes: Res<Foxes>,
271 mut commands: Commands,
272 children: Query<&Children>,
273 mut players: Query<&mut AnimationPlayer>,
274) {
275 for child in children.iter_descendants(scene_ready.entity) {
276 if let Ok(mut player) = players.get_mut(child) {
277 let playing_animation = player.play(animations.node_indices[0]).repeat();
278 if !foxes.sync {
279 playing_animation.seek_to(scene_ready.entity.index_u32() as f32 / 10.0);
280 }
281 commands.entity(child).insert((
282 AnimationGraphHandle(animations.graph.clone()),
283 AnimationTransitions::default(),
284 ));
285 }
286 }
287}353 fn pause_animation_frame(
354 scene_ready: On<WorldInstanceReady>,
355 children: Query<&Children>,
356 mut commands: Commands,
357 animation: Res<Animation>,
358 mut players: Query<(Entity, &mut AnimationPlayer)>,
359 ) {
360 for child in children.iter_descendants(scene_ready.entity) {
361 if let Ok((entity, mut player)) = players.get_mut(child) {
362 let mut transitions = AnimationTransitions::new();
363 transitions
364 .play(&mut player, animation.animation, Duration::ZERO)
365 .seek_to(0.5)
366 .pause();
367
368 commands
369 .entity(entity)
370 .insert(AnimationGraphHandle(animation.graph.clone()))
371 .insert(transitions);
372 }
373 }
374 }
375}
376
377mod gizmos {
378 use bevy::{color::palettes::css::*, prelude::*};
379
380 pub fn setup(mut commands: Commands) {
381 commands.spawn((
382 Camera3d::default(),
383 Transform::from_xyz(-1.0, 2.5, 6.5).looking_at(Vec3::ZERO, Vec3::Y),
384 DespawnOnExit(super::Scene::Gizmos),
385 ));
386 }
387
388 pub fn draw_gizmos(mut gizmos: Gizmos) {
389 gizmos.cube(
390 Transform::from_translation(Vec3::X * -1.75).with_scale(Vec3::splat(1.25)),
391 RED,
392 );
393 gizmos
394 .sphere(Isometry3d::from_translation(Vec3::X * -3.5), 0.75, GREEN)
395 .resolution(30_000 / 3);
396
397 gizmos.text(
398 Isometry3d::from_translation(Vec3::Y * 1.5),
399 "text gizmo",
400 0.3,
401 Vec2 { x: 0., y: 0. },
402 Color::WHITE,
403 );
404
405 // 3d grids with all variations of outer edges on or off
406 for i in 0..8 {
407 let x = 1.5 * (i % 4) as f32;
408 let y = 1.0 * (0.5 - (i / 4) as f32);
409 let mut grid = gizmos.grid_3d(
410 Isometry3d::from_translation(Vec3::new(x, y, 0.0)),
411 UVec3::new(5, 4, 3),
412 Vec3::splat(0.175),
413 Color::WHITE,
414 );
415 if i & 1 > 0 {
416 grid = grid.outer_edges_x();
417 }
418 if i & 2 > 0 {
419 grid = grid.outer_edges_y();
420 }
421 if i & 4 > 0 {
422 grid.outer_edges_z();
423 }
424 }
425 }
426}
427
428mod gltf_coordinate_conversion {
429 use bevy::{
430 color::palettes::basic::*,
431 gltf::{convert_coordinates::GltfConvertCoordinates, GltfLoaderSettings},
432 prelude::*,
433 world_serialization::WorldInstanceReady,
434 };
435
436 const CURRENT_SCENE: super::Scene = super::Scene::GltfCoordinateConversion;
437
438 pub fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
439 commands.spawn((
440 Camera3d::default(),
441 Transform::from_xyz(-4.0, 4.0, -5.0).looking_at(Vec3::ZERO, Vec3::Y),
442 DespawnOnExit(CURRENT_SCENE),
443 ));
444
445 commands.spawn((
446 DirectionalLight {
447 color: BLUE.into(),
448 ..default()
449 },
450 Transform::IDENTITY.looking_to(Dir3::Z, Dir3::Y),
451 DespawnOnExit(CURRENT_SCENE),
452 ));
453
454 commands.spawn((
455 DirectionalLight {
456 color: RED.into(),
457 ..default()
458 },
459 Transform::IDENTITY.looking_to(Dir3::X, Dir3::Y),
460 DespawnOnExit(CURRENT_SCENE),
461 ));
462
463 commands.spawn((
464 DirectionalLight {
465 color: GREEN.into(),
466 ..default()
467 },
468 Transform::IDENTITY.looking_to(Dir3::NEG_Y, Dir3::X),
469 DespawnOnExit(CURRENT_SCENE),
470 ));
471
472 commands
473 .spawn((
474 WorldAssetRoot(
475 asset_server
476 .load_builder()
477 .with_settings(|s: &mut GltfLoaderSettings| {
478 s.convert_coordinates = Some(GltfConvertCoordinates {
479 rotate_scene_entity: true,
480 rotate_meshes: true,
481 });
482 })
483 .load(GltfAssetLabel::Scene(0).from_asset("models/Faces/faces.glb")),
484 ),
485 DespawnOnExit(CURRENT_SCENE),
486 ))
487 .observe(show_aabbs);
488 }
489
490 pub fn show_aabbs(
491 scene_ready: On<WorldInstanceReady>,
492 mut commands: Commands,
493 children: Query<&Children>,
494 meshes: Query<(), With<Mesh3d>>,
495 ) {
496 for child in children
497 .iter_descendants(scene_ready.entity)
498 .filter(|&e| meshes.contains(e))
499 {
500 commands.entity(child).insert(ShowAabbGizmo {
501 color: Some(BLACK.into()),
502 });
503 }
504 }384fn play_animation(
385 trigger: On<WorldInstanceReady>,
386 mut commands: Commands,
387 args: Res<Args>,
388 children: Query<&Children>,
389 animations_to_play: Query<&AnimationToPlay>,
390 mut players: Query<&mut AnimationPlayer>,
391) {
392 if args.weights == ArgWeights::Animated
393 && let Ok(animation_to_play) = animations_to_play.get(trigger.entity)
394 {
395 for child in children.iter_descendants(trigger.entity) {
396 if let Ok(mut player) = players.get_mut(child) {
397 commands
398 .entity(child)
399 .insert(AnimationGraphHandle(animation_to_play.graph_handle.clone()));
400
401 player
402 .play(animation_to_play.index)
403 .repeat()
404 .set_speed(animation_to_play.speed);
405 }
406 }
407 }
408}
409
410fn set_weights(
411 trigger: On<WorldInstanceReady>,
412 args: Res<Args>,
413 children: Query<&Children>,
414 mut weight_components: Query<&mut MorphWeights>,
415) {
416 if let Some(weight_value) = match args.weights {
417 ArgWeights::One => Some(1.0),
418 ArgWeights::Zero => Some(0.0),
419 ArgWeights::Tiny => Some(0.00001),
420 _ => None,
421 } {
422 for child in children.iter_descendants(trigger.entity) {
423 if let Ok(mut weight_component) = weight_components.get_mut(child) {
424 weight_component.weights_mut().fill(weight_value);
425 }
426 }
427 }
428}- examples/gltf/gltf_extension_animation_graph.rs
- examples/ui/widgets/standard_widgets_observers.rs
- examples/ui/widgets/standard_widgets.rs
- examples/ui/widgets/vertical_slider.rs
- examples/3d/solari_reflections.rs
- examples/animation/animated_mesh.rs
- examples/gltf/edit_material_on_gltf.rs
- examples/3d/solari.rs
Sourcepub fn iter_descendants_depth_first<S>(
&'w self,
entity: Entity,
) -> DescendantDepthFirstIter<'w, 's, D, F, S> ⓘwhere
S: RelationshipTarget,
<D as QueryData>::ReadOnly: QueryData<Item<'w, 's> = &'w S>,
<<S as RelationshipTarget>::Collection as RelationshipSourceCollection>::SourceIter<'w>: DoubleEndedIterator,
pub fn iter_descendants_depth_first<S>(
&'w self,
entity: Entity,
) -> DescendantDepthFirstIter<'w, 's, D, F, S> ⓘwhere
S: RelationshipTarget,
<D as QueryData>::ReadOnly: QueryData<Item<'w, 's> = &'w S>,
<<S as RelationshipTarget>::Collection as RelationshipSourceCollection>::SourceIter<'w>: DoubleEndedIterator,
Iterates all descendant entities as defined by the given entity’s RelationshipTarget and their recursive
RelationshipTarget in depth-first order.
§Warning
For relationship graphs that contain loops, this could loop infinitely. If your relationship is not a tree (like Bevy’s hierarchy), be sure to stop if you encounter a duplicate entity.
Sourcepub fn iter_ancestors<R>(
&'w self,
entity: Entity,
) -> AncestorIter<'w, 's, D, F, R> ⓘ
pub fn iter_ancestors<R>( &'w self, entity: Entity, ) -> AncestorIter<'w, 's, D, F, R> ⓘ
Iterates all ancestors of the given entity as defined by the R Relationship.
§Warning
For relationship graphs that contain loops, this could loop infinitely. If your relationship is not a tree (like Bevy’s hierarchy), be sure to stop if you encounter a duplicate entity.
Examples found in repository?
152 fn check_for_cycles(
153 // We want to check every entity for cycles
154 query_to_check: Query<Entity, With<Targeting>>,
155 // Fetch the names for easier debugging.
156 name_query: Query<&Name>,
157 // The targeting_query allows us to traverse the relationship graph.
158 targeting_query: Query<&Targeting>,
159 ) -> Result<(), TargetingCycle> {
160 for initial_entity in query_to_check.iter() {
161 let mut visited = EntityHashSet::new();
162 let mut targeting_name = name_query.get(initial_entity).unwrap().clone();
163 println!("Checking for cycles starting at {targeting_name}",);
164
165 // There's all sorts of methods like this; check the `Query` docs for more!
166 // This would also be easy to do by just manually checking the `Targeting` component,
167 // and calling `query.get(targeted_entity)` on the entity that it targets in a loop.
168 for targeting in targeting_query.iter_ancestors(initial_entity) {
169 let target_name = name_query.get(targeting).unwrap();
170 println!("{targeting_name} is targeting {target_name}",);
171 targeting_name = target_name.clone();
172
173 if !visited.insert(targeting) {
174 return Err(TargetingCycle {
175 initial_entity,
176 visited,
177 });
178 }
179 }
180 }
181
182 // If we've checked all the entities and haven't found a cycle, we're good!
183 Ok(())
184 }More examples
404fn handle_drag_as_movement(
405 event: On<PointerDrag>,
406 parent_q: Query<&ChildOf>,
407 number_input_q: Query<(), With<FeathersNumberInput>>,
408 mut selections: Query<(&mut Transform, &Selection)>,
409 mouse_motion: Res<AccumulatedMouseMotion>,
410 app_status: Res<AppStatus>,
411) {
412 // If we are currently dragging the number input, do not interpret it as movement
413 // of the selection.
414 if parent_q
415 .iter_ancestors(event.entity)
416 .any(|parent| number_input_q.contains(parent))
417 {
418 return;
419 }
420 for (mut transform, selection) in &mut selections {
421 if app_status.selection != *selection {
422 continue;
423 }
424
425 let position = transform.translation;
426
427 // Convert to spherical coordinates.
428 let radius = position.length();
429 let mut theta = acos(position.y / radius);
430 let mut phi = position.z.signum() * acos(position.x * position.xz().length_recip());
431
432 // Camera movement is the inverse of object movement.
433 let (phi_factor, theta_factor) = match *selection {
434 Selection::Camera => (1.0, -1.0),
435 Selection::DecalA | Selection::DecalB => (-1.0, 1.0),
436 };
437
438 // Adjust the spherical coordinates. Clamp the inclination to (0, π).
439 phi += phi_factor * mouse_motion.delta.x * MOVE_SPEED;
440 theta = f32::clamp(
441 theta + theta_factor * mouse_motion.delta.y * MOVE_SPEED,
442 0.001,
443 PI - 0.001,
444 );
445
446 // Convert spherical coordinates back to Cartesian coordinates.
447 transform.translation =
448 radius * vec3(sin(theta) * cos(phi), cos(theta), sin(theta) * sin(phi));
449
450 // Look at the center, but preserve the previous roll angle.
451 let roll = transform.rotation.to_euler(EulerRot::YXZ).2;
452 transform.look_at(Vec3::ZERO, Vec3::Y);
453 let (yaw, pitch, _) = transform.rotation.to_euler(EulerRot::YXZ);
454 transform.rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, roll);
455 }
456}509fn handle_drag_as_movement(
510 event: On<PointerDrag>,
511 parent_q: Query<&ChildOf>,
512 number_input_q: Query<(), With<FeathersNumberInput>>,
513 mut selections: Query<(&mut Transform, &Selection)>,
514 mouse_motion: Res<AccumulatedMouseMotion>,
515 app_status: Res<AppStatus>,
516) {
517 // If we are currently dragging the number input, do not interpret it as movement
518 // of the selection.
519 if parent_q
520 .iter_ancestors(event.entity)
521 .any(|parent| number_input_q.contains(parent))
522 {
523 return;
524 }
525
526 for (mut transform, selection) in &mut selections {
527 if app_status.selection != *selection {
528 continue;
529 }
530
531 // use simple movement for the point light
532 if *selection == Selection::PointLight {
533 transform.translation +=
534 (mouse_motion.delta * Vec2::new(1.0, -1.0) * MOVE_SPEED).extend(0.0);
535 return;
536 }
537
538 let position = transform.translation;
539
540 // Convert to spherical coordinates.
541 let radius = position.length();
542 let mut theta = acos(position.y / radius);
543 let mut phi = position.z.signum() * acos(position.x * position.xz().length_recip());
544
545 // Camera movement is the inverse of object movement.
546 let (phi_factor, theta_factor) = match *selection {
547 Selection::Camera => (1.0, -1.0),
548 _ => (-1.0, 1.0),
549 };
550
551 // Adjust the spherical coordinates. Clamp the inclination to (0, π).
552 phi += phi_factor * mouse_motion.delta.x * MOVE_SPEED;
553 theta = f32::clamp(
554 theta + theta_factor * mouse_motion.delta.y * MOVE_SPEED,
555 0.001,
556 PI - 0.001,
557 );
558
559 // Convert spherical coordinates back to Cartesian coordinates.
560 transform.translation =
561 radius * vec3(sin(theta) * cos(phi), cos(theta), sin(theta) * sin(phi));
562
563 // Look at the center, but preserve the previous roll angle.
564 let roll = transform.rotation.to_euler(EulerRot::YXZ).2;
565 transform.look_at(Vec3::ZERO, Vec3::Y);
566 let (yaw, pitch, _) = transform.rotation.to_euler(EulerRot::YXZ);
567 transform.rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, roll);
568 }
569}Source§impl<'w, 's, D, F> Query<'w, 's, D, F>where
D: QueryData,
F: QueryFilter,
impl<'w, 's, D, F> Query<'w, 's, D, F>where
D: QueryData,
F: QueryFilter,
Sourcepub fn as_readonly(&self) -> Query<'_, 's, <D as QueryData>::ReadOnly, F>
pub fn as_readonly(&self) -> Query<'_, 's, <D as QueryData>::ReadOnly, F>
Returns another Query from this that fetches the read-only version of the query items.
For example, Query<(&mut D1, &D2, &mut D3), With<F>> will become Query<(&D1, &D2, &D3), With<F>>.
This can be useful when working around the borrow checker,
or reusing functionality between systems via functions that accept query types.
§See also
into_readonly for a version that consumes the Query to return one with the full 'world lifetime.
Sourcepub fn into_readonly(self) -> Query<'w, 's, <D as QueryData>::ReadOnly, F>
pub fn into_readonly(self) -> Query<'w, 's, <D as QueryData>::ReadOnly, F>
Returns another Query from this that fetches the read-only version of the query items.
For example, Query<(&mut D1, &D2, &mut D3), With<F>> will become Query<(&D1, &D2, &D3), With<F>>.
This can be useful when working around the borrow checker,
or reusing functionality between systems via functions that accept query types.
§See also
as_readonly for a version that borrows the Query instead of consuming it.
Sourcepub fn reborrow(&mut self) -> Query<'_, 's, D, F>
pub fn reborrow(&mut self) -> Query<'_, 's, D, F>
Returns a new Query reborrowing the access from this one. The current query will be unusable
while the new one exists.
§Example
For example this allows to call other methods or other systems that require an owned Query without
completely giving up ownership of it.
fn helper_system(query: Query<&ComponentA>) { /* ... */}
fn system(mut query: Query<&ComponentA>) {
helper_system(query.reborrow());
// Can still use query here:
for component in &query {
// ...
}
}Sourcepub unsafe fn reborrow_unsafe(&self) -> Query<'_, 's, D, F>
pub unsafe fn reborrow_unsafe(&self) -> Query<'_, 's, D, F>
Returns a new Query reborrowing the access from this one.
The current query will still be usable while the new one exists, but must not be used in a way that violates aliasing.
§Safety
This function makes it possible to violate Rust’s aliasing guarantees. You must make sure this call does not result in a mutable or shared reference to a component with a mutable reference.
§See also
reborrowfor the safe versions.
Sourcepub fn iter(&self) -> QueryIter<'_, 's, <D as QueryData>::ReadOnly, F> ⓘ
pub fn iter(&self) -> QueryIter<'_, 's, <D as QueryData>::ReadOnly, F> ⓘ
Returns an Iterator over the read-only query items.
This iterator is always guaranteed to return results from each matching entity once and only once. Iteration order is not guaranteed.
§Example
Here, the report_names_system iterates over the Player component of every entity that contains it:
fn report_names_system(query: Query<&Player>) {
for player in &query {
println!("Say hello to {}!", player.name);
}
}§See also
iter_mut for mutable query items.
Examples found in repository?
More examples
316fn image_copy_extract(mut commands: Commands, image_copiers: Extract<Query<&ImageCopier>>) {
317 commands.insert_resource(ImageCopiers(
318 image_copiers.iter().cloned().collect::<Vec<ImageCopier>>(),
319 ));
320}
321
322// Copies image content from render target to buffer
323fn image_copy_driver(
324 render_context: RenderContext,
325 image_copiers: Res<ImageCopiers>,
326 render_queue: Res<RenderQueue>,
327 gpu_images: Res<RenderAssets<bevy::render::texture::GpuImage>>,
328) {
329 for image_copier in image_copiers.iter() {
330 if !image_copier.enabled() {
331 continue;
332 }
333
334 let src_image = gpu_images.get(&image_copier.src_image).unwrap();
335
336 let mut encoder = render_context
337 .render_device()
338 .create_command_encoder(&CommandEncoderDescriptor::default());
339
340 let block_dimensions = src_image.texture_descriptor.format.block_dimensions();
341 let block_size = src_image
342 .texture_descriptor
343 .format
344 .block_copy_size(None)
345 .unwrap();
346
347 // Calculating correct size of image row because
348 // copy_texture_to_buffer can copy image only by rows aligned wgpu::COPY_BYTES_PER_ROW_ALIGNMENT
349 // That's why image in buffer can be little bit wider
350 // This should be taken into account at copy from buffer stage
351 let padded_bytes_per_row = RenderDevice::align_copy_bytes_per_row(
352 (src_image.texture_descriptor.size.width as usize / block_dimensions.0 as usize)
353 * block_size as usize,
354 );
355
356 encoder.copy_texture_to_buffer(
357 src_image.texture.as_image_copy(),
358 TexelCopyBufferInfo {
359 buffer: &image_copier.buffer,
360 layout: TexelCopyBufferLayout {
361 offset: 0,
362 bytes_per_row: Some(
363 std::num::NonZero::<u32>::new(padded_bytes_per_row as u32)
364 .unwrap()
365 .into(),
366 ),
367 rows_per_image: None,
368 },
369 },
370 src_image.texture_descriptor.size,
371 );
372
373 render_queue.submit(std::iter::once(encoder.finish()));
374 }
375}
376
377/// runs in render world after Render stage to send image from buffer via channel (receiver is in main world)
378fn receive_image_from_buffer(
379 image_copiers: Res<ImageCopiers>,
380 render_device: Res<RenderDevice>,
381 sender: Res<RenderWorldSender>,
382) {
383 for image_copier in image_copiers.0.iter() {
384 if !image_copier.enabled() {
385 continue;
386 }
387
388 // Finally time to get our data back from the gpu.
389 // First we get a buffer slice which represents a chunk of the buffer (which we
390 // can't access yet).
391 // We want the whole thing so use unbounded range.
392 let buffer_slice = image_copier.buffer.slice(..);
393
394 // Now things get complicated. WebGPU, for safety reasons, only allows either the GPU
395 // or CPU to access a buffer's contents at a time. We need to "map" the buffer which means
396 // flipping ownership of the buffer over to the CPU and making access legal. We do this
397 // with `BufferSlice::map_async`.
398 //
399 // The problem is that map_async is not an async function so we can't await it. What
400 // we need to do instead is pass in a closure that will be executed when the slice is
401 // either mapped or the mapping has failed.
402 //
403 // The problem with this is that we don't have a reliable way to wait in the main
404 // code for the buffer to be mapped and even worse, calling get_mapped_range or
405 // get_mapped_range_mut prematurely will cause a panic, not return an error.
406 //
407 // Using channels solves this as awaiting the receiving of a message from
408 // the passed closure will force the outside code to wait. It also doesn't hurt
409 // if the closure finishes before the outside code catches up as the message is
410 // buffered and receiving will just pick that up.
411 //
412 // It may also be worth noting that although on native, the usage of asynchronous
413 // channels is wholly unnecessary, for the sake of portability to Wasm
414 // we'll use async channels that work on both native and Wasm.
415
416 let (s, r) = crossbeam_channel::bounded(1);
417
418 // Maps the buffer so it can be read on the cpu
419 buffer_slice.map_async(MapMode::Read, move |r| match r {
420 // This will execute once the gpu is ready, so after the call to poll()
421 Ok(r) => s.send(r).expect("Failed to send map update"),
422 Err(err) => panic!("Failed to map buffer {err}"),
423 });
424
425 // In order for the mapping to be completed, one of three things must happen.
426 // One of those can be calling `Device::poll`. This isn't necessary on the web as devices
427 // are polled automatically but natively, we need to make sure this happens manually.
428 // `Maintain::Wait` will cause the thread to wait on native but not on WebGpu.
429
430 // This blocks until the gpu is done executing everything
431 render_device
432 .poll(PollType::wait_indefinitely())
433 .expect("Failed to poll device for map async");
434
435 // This blocks until the buffer is mapped
436 r.recv().expect("Failed to receive the map_async message");
437
438 // This could fail on app exit, if Main world clears resources (including receiver) while Render world still renders
439 let _ = sender.send(buffer_slice.get_mapped_range().unwrap().to_vec());
440
441 // We need to make sure all `BufferView`'s are dropped before we do what we're about
442 // to do.
443 // Unmap so that we can copy to the staging buffer in the next iteration.
444 image_copier.buffer.unmap();
445 }
446}
447
448/// CPU-side image for saving
449#[derive(Component, Deref, DerefMut)]
450struct ImageToSave(Handle<Image>);
451
452// Takes from channel image content sent from render world and saves it to disk
453fn update(
454 images_to_save: Query<&ImageToSave>,
455 receiver: Res<MainWorldReceiver>,
456 mut images: ResMut<Assets<Image>>,
457 mut scene_controller: ResMut<SceneController>,
458 mut app_exit_writer: MessageWriter<AppExit>,
459 mut file_number: Local<u32>,
460) {
461 if let SceneState::Render(n) = scene_controller.state {
462 if n < 1 {
463 // We don't want to block the main world on this,
464 // so we use try_recv which attempts to receive without blocking
465 let mut image_data = Vec::new();
466 while let Ok(data) = receiver.try_recv() {
467 // image generation could be faster than saving to fs,
468 // that's why use only last of them
469 image_data = data;
470 }
471 if !image_data.is_empty() {
472 for image in images_to_save.iter() {
473 // Fill correct data from channel to image
474 let mut img_bytes = images.get_mut(image.id()).unwrap();
475
476 // We need to ensure that this works regardless of the image dimensions
477 // If the image became wider when copying from the texture to the buffer,
478 // then the data is reduced to its original size when copying from the buffer to the image.
479 let row_bytes = img_bytes.width() as usize
480 * img_bytes.texture_descriptor.format.pixel_size().unwrap();
481 let aligned_row_bytes = RenderDevice::align_copy_bytes_per_row(row_bytes);
482 if row_bytes == aligned_row_bytes {
483 img_bytes.data.as_mut().unwrap().clone_from(&image_data);
484 } else {
485 // shrink data to original image size
486 img_bytes.data = Some(
487 image_data
488 .chunks(aligned_row_bytes)
489 .take(img_bytes.height() as usize)
490 .flat_map(|row| &row[..row_bytes.min(row.len())])
491 .cloned()
492 .collect(),
493 );
494 }
495
496 // Create RGBA Image Buffer
497 let img = match img_bytes.clone().try_into_dynamic() {
498 Ok(img) => img.to_rgba8(),
499 Err(e) => panic!("Failed to create image buffer {e:?}"),
500 };
501
502 // Prepare directory for images, test_images in bevy folder is used here for example
503 // You should choose the path depending on your needs
504 let images_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("test_images");
505 info!("Saving image to: {images_dir:?}");
506 std::fs::create_dir_all(&images_dir).unwrap();
507
508 // Choose filename starting from 000.png
509 let image_path = images_dir.join(format!("{:03}.png", file_number.deref()));
510 *file_number.deref_mut() += 1;
511
512 // Finally saving image to file, this heavy blocking operation is kept here
513 // for example simplicity, but in real app you should move it to a separate task
514 if let Err(e) = img.save(image_path) {
515 panic!("Failed to save image: {e}");
516 };
517 }
518 if scene_controller.single_image {
519 app_exit_writer.write(AppExit::Success);
520 }
521 }
522 } else {
523 // clears channel for skipped frames
524 while receiver.try_recv().is_ok() {}
525 scene_controller.state = SceneState::Render(n - 1);
526 }
527 }
528}- examples/stress_tests/many_lights.rs
- examples/ecs/one_shot_systems.rs
- examples/ui/navigation/directional_navigation.rs
- examples/showcase/loading_screen.rs
- examples/ecs/observer_propagation.rs
- examples/ecs/removal_detection.rs
- examples/stress_tests/many_cubes.rs
- examples/asset/multi_asset_sync.rs
- examples/picking/mesh_picking.rs
- examples/shader/gpu_component_array_buffer.rs
- examples/3d/mirror.rs
- examples/3d/animated_material.rs
- examples/window/screenshot.rs
- examples/3d/reflection_probes.rs
- examples/3d/depth_of_field.rs
- examples/stress_tests/many_materials.rs
- examples/ui/widgets/viewport_node.rs
- examples/3d/specular_tint.rs
- examples/2d/dynamic_mip_generation.rs
- examples/asset/asset_decompression.rs
- examples/ui/navigation/directional_navigation_overrides.rs
- examples/3d/visibility_range.rs
- examples/ecs/entity_disabling.rs
- examples/stress_tests/many_text2d.rs
- tests/3d/test_skinned_mesh_bounds.rs
- examples/ui/widgets/standard_widgets.rs
- examples/3d/anisotropy.rs
- examples/3d/pccm.rs
- examples/ecs/delayed_commands.rs
- examples/math/bounding_2d.rs
- examples/3d/irradiance_volumes.rs
- examples/3d/shadow_caster_receiver.rs
- examples/audio/soundtrack.rs
- examples/shader_advanced/compute_mesh.rs
- examples/ecs/fallible_params.rs
- examples/math/render_primitives.rs
- examples/math/custom_primitives.rs
- examples/gltf/load_gltf_extras.rs
- examples/ui/text/letter_spacing.rs
- examples/ecs/relationships.rs
- examples/gltf/query_gltf_primitives.rs
- examples/3d/mixed_lighting.rs
- examples/ui/widgets/vertical_slider.rs
- examples/3d/ssr.rs
- examples/3d/lightmaps.rs
- examples/asset/asset_saving_with_subassets.rs
- examples/stress_tests/many_components.rs
- examples/usage/character_creation.rs
- examples/3d/light_probe_blending.rs
- examples/3d/occlusion_culling.rs
- examples/3d/order_independent_transparency.rs
- examples/3d/clustered_decals.rs
- examples/window/monitor_info.rs
- examples/ecs/callbacks.rs
- examples/3d/wireframe.rs
- examples/ui/layout/size_constraints.rs
- examples/3d/light_textures.rs
- examples/camera/pan_orbit_camera_custom_input_plugin.rs
- examples/shader_advanced/custom_phase_item.rs
- examples/shader_advanced/specialized_mesh_pipeline.rs
- examples/ui/widgets/feathers_gallery.rs
Sourcepub fn iter_mut(&mut self) -> QueryIter<'_, 's, D, F> ⓘ
pub fn iter_mut(&mut self) -> QueryIter<'_, 's, D, F> ⓘ
Returns an Iterator over the query items.
This iterator is always guaranteed to return results from each matching entity once and only once. Iteration order is not guaranteed.
If the QueryData does not implement IterQueryData,
then it is not sound to yield multiple items concurrently
and the resulting QueryIter will not implement Iterator.
To iterate over the items in that case,
use the QueryIter::fetch_next() method,
which ensures only one item is alive at a time.
§Example
Here, the gravity_system updates the Velocity component of every entity that contains it:
fn gravity_system(mut query: Query<&mut Velocity>) {
const DELTA: f32 = 1.0 / 60.0;
for mut velocity in &mut query {
velocity.y -= 9.8 * DELTA;
}
}§See also
iter for read-only query items.
Examples found in repository?
304fn update_text(mut text_query: Query<&mut Text>, app_status: Res<AppStatus>) {
305 for mut text in text_query.iter_mut() {
306 *text = app_status.create_text();
307 }
308}
309
310impl AppStatus {
311 // Constructs the help text at the bottom of the screen based on the
312 // application status.
313 fn create_text(&self) -> Text {
314 let irradiance_volume_help_text = if self.irradiance_volume_present {
315 DISABLE_IRRADIANCE_VOLUME_HELP_TEXT
316 } else {
317 ENABLE_IRRADIANCE_VOLUME_HELP_TEXT
318 };
319
320 let voxels_help_text = if self.voxels_visible {
321 HIDE_VOXELS_HELP_TEXT
322 } else {
323 SHOW_VOXELS_HELP_TEXT
324 };
325
326 let rotation_help_text = if self.rotating {
327 STOP_ROTATION_HELP_TEXT
328 } else {
329 START_ROTATION_HELP_TEXT
330 };
331
332 let switch_mesh_help_text = match self.model {
333 ExampleModel::Sphere => SWITCH_TO_FOX_HELP_TEXT,
334 ExampleModel::Fox => SWITCH_TO_SPHERE_HELP_TEXT,
335 };
336
337 format!(
338 "{CLICK_TO_MOVE_HELP_TEXT}\n\
339 {voxels_help_text}\n\
340 {irradiance_volume_help_text}\n\
341 {rotation_help_text}\n\
342 {switch_mesh_help_text}"
343 )
344 .into()
345 }
346}
347
348// Rotates the camera a bit every frame.
349fn rotate_camera(
350 mut camera_query: Query<&mut Transform, With<Camera3d>>,
351 time: Res<Time>,
352 app_status: Res<AppStatus>,
353) {
354 if !app_status.rotating {
355 return;
356 }
357
358 for mut transform in camera_query.iter_mut() {
359 transform.translation = Vec2::from_angle(ROTATION_SPEED * time.delta_secs())
360 .rotate(transform.translation.xz())
361 .extend(transform.translation.y)
362 .xzy();
363 transform.look_at(Vec3::ZERO, Vec3::Y);
364 }
365}
366
367// Toggles between the unskinned sphere model and the skinned fox model if the
368// user requests it.
369fn change_main_object(
370 keyboard: Res<ButtonInput<KeyCode>>,
371 mut app_status: ResMut<AppStatus>,
372 mut sphere_query: Query<
373 &mut Visibility,
374 (With<MainObject>, With<Mesh3d>, Without<WorldAssetRoot>),
375 >,
376 mut fox_query: Query<&mut Visibility, (With<MainObject>, With<WorldAssetRoot>)>,
377) {
378 if !keyboard.just_pressed(KeyCode::Tab) {
379 return;
380 }
381 let Some(mut sphere_visibility) = sphere_query.iter_mut().next() else {
382 return;
383 };
384 let Some(mut fox_visibility) = fox_query.iter_mut().next() else {
385 return;
386 };
387
388 match app_status.model {
389 ExampleModel::Sphere => {
390 *sphere_visibility = Visibility::Hidden;
391 *fox_visibility = Visibility::Visible;
392 app_status.model = ExampleModel::Fox;
393 }
394 ExampleModel::Fox => {
395 *sphere_visibility = Visibility::Visible;
396 *fox_visibility = Visibility::Hidden;
397 app_status.model = ExampleModel::Sphere;
398 }
399 }
400}
401
402impl Default for AppStatus {
403 fn default() -> Self {
404 Self {
405 irradiance_volume_present: true,
406 rotating: true,
407 model: ExampleModel::Sphere,
408 voxels_visible: false,
409 }
410 }
411}
412
413// Turns on and off the irradiance volume as requested by the user.
414fn toggle_irradiance_volumes(
415 mut commands: Commands,
416 keyboard: Res<ButtonInput<KeyCode>>,
417 light_probe_query: Query<Entity, With<LightProbe>>,
418 mut app_status: ResMut<AppStatus>,
419 assets: Res<ExampleAssets>,
420 mut ambient_light: ResMut<GlobalAmbientLight>,
421) {
422 if !keyboard.just_pressed(KeyCode::Space) {
423 return;
424 };
425
426 let Some(light_probe) = light_probe_query.iter().next() else {
427 return;
428 };
429
430 if app_status.irradiance_volume_present {
431 commands.entity(light_probe).remove::<IrradianceVolume>();
432 ambient_light.brightness = AMBIENT_LIGHT_BRIGHTNESS * IRRADIANCE_VOLUME_INTENSITY;
433 app_status.irradiance_volume_present = false;
434 } else {
435 commands.entity(light_probe).insert(IrradianceVolume {
436 voxels: assets.irradiance_volume.clone(),
437 intensity: IRRADIANCE_VOLUME_INTENSITY,
438 ..default()
439 });
440 ambient_light.brightness = 0.0;
441 app_status.irradiance_volume_present = true;
442 }
443}
444
445fn toggle_rotation(keyboard: Res<ButtonInput<KeyCode>>, mut app_status: ResMut<AppStatus>) {
446 if keyboard.just_pressed(KeyCode::Enter) {
447 app_status.rotating = !app_status.rotating;
448 }
449}
450
451// Handles clicks on the plane that reposition the object.
452fn handle_mouse_clicks(
453 buttons: Res<ButtonInput<MouseButton>>,
454 windows: Query<&Window, With<PrimaryWindow>>,
455 cameras: Query<(&Camera, &GlobalTransform)>,
456 mut main_objects: Query<&mut Transform, With<MainObject>>,
457) {
458 if !buttons.pressed(MouseButton::Left) {
459 return;
460 }
461 let Some(mouse_position) = windows.iter().next().and_then(Window::cursor_position) else {
462 return;
463 };
464 let Some((camera, camera_transform)) = cameras.iter().next() else {
465 return;
466 };
467
468 // Figure out where the user clicked on the plane.
469 let Ok(ray) = camera.viewport_to_world(camera_transform, mouse_position) else {
470 return;
471 };
472 let Some(plane_intersection) =
473 ray.plane_intersection_point(Vec3::ZERO, InfinitePlane3d::new(Vec3::Y))
474 else {
475 return;
476 };
477 // Move all the main objects.
478 for mut transform in main_objects.iter_mut() {
479 transform.translation = vec3(
480 plane_intersection.x,
481 transform.translation.y,
482 plane_intersection.z,
483 );
484 }
485}
486
487impl FromWorld for ExampleAssets {
488 fn from_world(world: &mut World) -> Self {
489 let fox_animation =
490 world.load_asset(GltfAssetLabel::Animation(1).from_asset("models/animated/Fox.glb"));
491 let (fox_animation_graph, fox_animation_node) =
492 AnimationGraph::from_clip(fox_animation.clone());
493
494 ExampleAssets {
495 main_sphere: world.add_asset(Sphere::default().mesh().uv(32, 18)),
496 fox: world.load_asset(GltfAssetLabel::Scene(0).from_asset("models/animated/Fox.glb")),
497 main_sphere_material: world.add_asset(Color::from(SILVER)),
498 main_scene: world.load_asset(
499 GltfAssetLabel::Scene(0)
500 .from_asset("models/IrradianceVolumeExample/IrradianceVolumeExample.glb"),
501 ),
502 irradiance_volume: world.load_asset("irradiance_volumes/Example.vxgi.ktx2"),
503 fox_animation_graph: world.add_asset(fox_animation_graph),
504 fox_animation_node,
505 voxel_cube: world.add_asset(Cuboid::default()),
506 // Just use a specular map for the skybox since it's not too blurry.
507 // In reality you wouldn't do this--you'd use a real skybox texture--but
508 // reusing the textures like this saves space in the Bevy repository.
509 skybox: world.load_asset("environment_maps/pisa_specular_rgb9e5_zstd.ktx2"),
510 }
511 }
512}
513
514// Plays the animation on the fox.
515fn play_animations(
516 mut commands: Commands,
517 assets: Res<ExampleAssets>,
518 mut players: Query<(Entity, &mut AnimationPlayer), Without<AnimationGraphHandle>>,
519) {
520 for (entity, mut player) in players.iter_mut() {
521 commands
522 .entity(entity)
523 .insert(AnimationGraphHandle(assets.fox_animation_graph.clone()));
524 player.play(assets.fox_animation_node).repeat();
525 }
526}
527
528fn create_cubes(
529 image_assets: Res<Assets<Image>>,
530 mut commands: Commands,
531 irradiance_volumes: Query<(&IrradianceVolume, &GlobalTransform)>,
532 voxel_cube_parents: Query<Entity, With<VoxelCubeParent>>,
533 voxel_cubes: Query<Entity, With<VoxelCube>>,
534 example_assets: Res<ExampleAssets>,
535 mut voxel_visualization_material_assets: ResMut<Assets<VoxelVisualizationMaterial>>,
536) {
537 // If voxel cubes have already been spawned, don't do anything.
538 if !voxel_cubes.is_empty() {
539 return;
540 }
541
542 let Some(voxel_cube_parent) = voxel_cube_parents.iter().next() else {
543 return;
544 };
545
546 for (irradiance_volume, global_transform) in irradiance_volumes.iter() {
547 let Some(image) = image_assets.get(&irradiance_volume.voxels) else {
548 continue;
549 };
550
551 let resolution = image.texture_descriptor.size;
552
553 let voxel_cube_material = voxel_visualization_material_assets.add(ExtendedMaterial {
554 base: StandardMaterial::from(Color::from(RED)),
555 extension: VoxelVisualizationExtension {
556 irradiance_volume_info: VoxelVisualizationIrradianceVolumeInfo {
557 world_from_voxel: VOXEL_FROM_WORLD.inverse(),
558 voxel_from_world: VOXEL_FROM_WORLD,
559 resolution: uvec3(
560 resolution.width,
561 resolution.height,
562 resolution.depth_or_array_layers,
563 ),
564 intensity: IRRADIANCE_VOLUME_INTENSITY,
565 },
566 },
567 });
568
569 let scale = vec3(
570 1.0 / resolution.width as f32,
571 1.0 / resolution.height as f32,
572 1.0 / resolution.depth_or_array_layers as f32,
573 );
574
575 // Spawn a cube for each voxel.
576 for z in 0..resolution.depth_or_array_layers {
577 for y in 0..resolution.height {
578 for x in 0..resolution.width {
579 let uvw = (uvec3(x, y, z).as_vec3() + 0.5) * scale - 0.5;
580 let pos = global_transform.transform_point(uvw);
581 let voxel_cube = commands
582 .spawn((
583 Mesh3d(example_assets.voxel_cube.clone()),
584 MeshMaterial3d(voxel_cube_material.clone()),
585 Transform::from_scale(Vec3::splat(VOXEL_CUBE_SCALE))
586 .with_translation(pos),
587 ))
588 .insert(VoxelCube)
589 .insert(NotShadowCaster)
590 .id();
591
592 commands.entity(voxel_cube_parent).add_child(voxel_cube);
593 }
594 }
595 }
596 }
597}
598
599// Draws a gizmo showing the bounds of the irradiance volume.
600fn draw_gizmo(
601 mut gizmos: Gizmos,
602 irradiance_volume_query: Query<&GlobalTransform, With<IrradianceVolume>>,
603 app_status: Res<AppStatus>,
604) {
605 if app_status.voxels_visible {
606 for transform in irradiance_volume_query.iter() {
607 gizmos.cube(*transform, GIZMO_COLOR);
608 }
609 }
610}
611
612// Handles a request from the user to toggle the voxel visibility on and off.
613fn toggle_voxel_visibility(
614 keyboard: Res<ButtonInput<KeyCode>>,
615 mut app_status: ResMut<AppStatus>,
616 mut voxel_cube_parent_query: Query<&mut Visibility, With<VoxelCubeParent>>,
617) {
618 if !keyboard.just_pressed(KeyCode::Backspace) {
619 return;
620 }
621
622 app_status.voxels_visible = !app_status.voxels_visible;
623
624 for mut visibility in voxel_cube_parent_query.iter_mut() {
625 *visibility = if app_status.voxels_visible {
626 Visibility::Visible
627 } else {
628 Visibility::Hidden
629 };
630 }
631}More examples
280fn update_text(mut text_query: Query<&mut Text>, app_status: Res<AppStatus>) {
281 for mut text in text_query.iter_mut() {
282 *text = app_status.create_text();
283 }
284}
285
286impl TryFrom<u32> for ReflectionMode {
287 type Error = ();
288
289 fn try_from(value: u32) -> Result<Self, Self::Error> {
290 match value {
291 0 => Ok(ReflectionMode::EnvironmentMap),
292 1 => Ok(ReflectionMode::ReflectionProbe),
293 2 => Ok(ReflectionMode::GeneratedEnvironmentMap),
294 _ => Err(()),
295 }
296 }
297}
298
299impl Display for ReflectionMode {
300 fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
301 let text = match *self {
302 ReflectionMode::EnvironmentMap => "Environment map",
303 ReflectionMode::ReflectionProbe => "Reflection probe",
304 ReflectionMode::GeneratedEnvironmentMap => "Generated environment map",
305 };
306 formatter.write_str(text)
307 }
308}
309
310impl AppStatus {
311 // Constructs the help text at the bottom of the screen based on the
312 // application status.
313 fn create_text(&self) -> Text {
314 let rotation_help_text = if self.rotating {
315 STOP_ROTATION_HELP_TEXT
316 } else {
317 START_ROTATION_HELP_TEXT
318 };
319
320 format!(
321 "{}\n{}\nRoughness: {:.2}\n{}\nUp/Down arrows to change roughness",
322 self.reflection_mode,
323 rotation_help_text,
324 self.sphere_roughness,
325 REFLECTION_MODE_HELP_TEXT
326 )
327 .into()
328 }
329}
330
331// Creates the world environment map light, used as a fallback if no reflection
332// probe is applicable to a mesh.
333fn create_camera_environment_map_light(cubemaps: &Cubemaps) -> EnvironmentMapLight {
334 EnvironmentMapLight {
335 diffuse_map: cubemaps.diffuse_environment_map.clone(),
336 specular_map: cubemaps.specular_environment_map.clone(),
337 intensity: ENV_MAP_INTENSITY,
338 ..default()
339 }
340}
341
342// Rotates the camera a bit every frame.
343fn rotate_camera(
344 time: Res<Time>,
345 mut camera_query: Query<&mut Transform, With<Camera3d>>,
346 app_status: Res<AppStatus>,
347) {
348 if !app_status.rotating {
349 return;
350 }
351
352 for mut transform in camera_query.iter_mut() {
353 transform.translation = Vec2::from_angle(time.delta_secs() * PI / 5.0)
354 .rotate(transform.translation.xz())
355 .extend(transform.translation.y)
356 .xzy();
357 transform.look_at(Vec3::ZERO, Vec3::Y);
358 }
359}39fn spin(time: Res<Time>, mut query: Query<&mut Transform, With<Spin>>) {
40 for mut transform in query.iter_mut() {
41 transform.rotation *= Quat::from_rotation_z(time.delta_secs() / 5.);
42 }
43}
44
45#[derive(States, Default, Debug, Hash, PartialEq, Eq, Clone, Copy)]
46enum Test {
47 AabbSweep,
48 CircleSweep,
49 #[default]
50 RayCast,
51 AabbCast,
52 CircleCast,
53}
54
55fn update_test_state(
56 keycode: Res<ButtonInput<KeyCode>>,
57 cur_state: Res<State<Test>>,
58 mut state: ResMut<NextState<Test>>,
59) {
60 if !keycode.just_pressed(KeyCode::Space) {
61 return;
62 }
63
64 use Test::*;
65 let next = match **cur_state {
66 AabbSweep => CircleSweep,
67 CircleSweep => RayCast,
68 RayCast => AabbCast,
69 AabbCast => CircleCast,
70 CircleCast => AabbSweep,
71 };
72 state.set(next);
73}
74
75fn update_text(mut text: Single<&mut Text>, cur_state: Res<State<Test>>) {
76 if !cur_state.is_changed() {
77 return;
78 }
79
80 text.clear();
81
82 text.push_str("Intersection test:\n");
83 use Test::*;
84 for &test in &[AabbSweep, CircleSweep, RayCast, AabbCast, CircleCast] {
85 let s = if **cur_state == test { "*" } else { " " };
86 text.push_str(&format!(" {s} {test:?} {s}\n"));
87 }
88 text.push_str("\nPress space to cycle");
89}
90
91#[derive(Component)]
92enum Shape {
93 Rectangle(Rectangle),
94 Circle(Circle),
95 Triangle(Triangle2d),
96 Line(Segment2d),
97 Capsule(Capsule2d),
98 Polygon(RegularPolygon),
99}
100
101fn render_shapes(mut gizmos: Gizmos, query: Query<(&Shape, &Transform)>) {
102 let color = GRAY;
103 for (shape, transform) in query.iter() {
104 let translation = transform.translation.xy();
105 let rotation = transform.rotation.to_euler(EulerRot::YXZ).2;
106 let isometry = Isometry2d::new(translation, Rot2::radians(rotation));
107 match shape {
108 Shape::Rectangle(r) => {
109 gizmos.primitive_2d(r, isometry, color);
110 }
111 Shape::Circle(c) => {
112 gizmos.primitive_2d(c, isometry, color);
113 }
114 Shape::Triangle(t) => {
115 gizmos.primitive_2d(t, isometry, color);
116 }
117 Shape::Line(l) => {
118 gizmos.primitive_2d(l, isometry, color);
119 }
120 Shape::Capsule(c) => {
121 gizmos.primitive_2d(c, isometry, color);
122 }
123 Shape::Polygon(p) => {
124 gizmos.primitive_2d(p, isometry, color);
125 }
126 }
127 }
128}
129
130#[derive(Component)]
131enum DesiredVolume {
132 Aabb,
133 Circle,
134}
135
136#[derive(Component, Debug)]
137enum CurrentVolume {
138 Aabb(Aabb2d),
139 Circle(BoundingCircle),
140}
141
142fn update_volumes(
143 mut commands: Commands,
144 query: Query<
145 (Entity, &DesiredVolume, &Shape, &Transform),
146 Or<(Changed<DesiredVolume>, Changed<Shape>, Changed<Transform>)>,
147 >,
148) {
149 for (entity, desired_volume, shape, transform) in query.iter() {
150 let translation = transform.translation.xy();
151 let rotation = transform.rotation.to_euler(EulerRot::YXZ).2;
152 let isometry = Isometry2d::new(translation, Rot2::radians(rotation));
153 match desired_volume {
154 DesiredVolume::Aabb => {
155 let aabb = match shape {
156 Shape::Rectangle(r) => r.aabb_2d(isometry),
157 Shape::Circle(c) => c.aabb_2d(isometry),
158 Shape::Triangle(t) => t.aabb_2d(isometry),
159 Shape::Line(l) => l.aabb_2d(isometry),
160 Shape::Capsule(c) => c.aabb_2d(isometry),
161 Shape::Polygon(p) => p.aabb_2d(isometry),
162 };
163 commands.entity(entity).insert(CurrentVolume::Aabb(aabb));
164 }
165 DesiredVolume::Circle => {
166 let circle = match shape {
167 Shape::Rectangle(r) => r.bounding_circle(isometry),
168 Shape::Circle(c) => c.bounding_circle(isometry),
169 Shape::Triangle(t) => t.bounding_circle(isometry),
170 Shape::Line(l) => l.bounding_circle(isometry),
171 Shape::Capsule(c) => c.bounding_circle(isometry),
172 Shape::Polygon(p) => p.bounding_circle(isometry),
173 };
174 commands
175 .entity(entity)
176 .insert(CurrentVolume::Circle(circle));
177 }
178 }
179 }
180}
181
182fn render_volumes(mut gizmos: Gizmos, query: Query<(&CurrentVolume, &Intersects)>) {
183 for (volume, intersects) in query.iter() {
184 let color = if **intersects { AQUA } else { ORANGE_RED };
185 match volume {
186 CurrentVolume::Aabb(a) => {
187 gizmos.rect_2d(a.center(), a.half_size() * 2., color);
188 }
189 CurrentVolume::Circle(c) => {
190 gizmos.circle_2d(c.center(), c.radius(), color);
191 }
192 }
193 }
194}
195
196#[derive(Component, Deref, DerefMut, Default)]
197struct Intersects(bool);
198
199const OFFSET_X: f32 = 125.;
200const OFFSET_Y: f32 = 75.;
201
202fn setup(mut commands: Commands) {
203 commands.spawn(Camera2d);
204
205 commands.spawn((
206 Transform::from_xyz(-OFFSET_X, OFFSET_Y, 0.),
207 Shape::Circle(Circle::new(45.)),
208 DesiredVolume::Aabb,
209 Intersects::default(),
210 ));
211
212 commands.spawn((
213 Transform::from_xyz(0., OFFSET_Y, 0.),
214 Shape::Rectangle(Rectangle::new(80., 80.)),
215 Spin,
216 DesiredVolume::Circle,
217 Intersects::default(),
218 ));
219
220 commands.spawn((
221 Transform::from_xyz(OFFSET_X, OFFSET_Y, 0.),
222 Shape::Triangle(Triangle2d::new(
223 Vec2::new(-40., -40.),
224 Vec2::new(-20., 40.),
225 Vec2::new(40., 50.),
226 )),
227 Spin,
228 DesiredVolume::Aabb,
229 Intersects::default(),
230 ));
231
232 commands.spawn((
233 Transform::from_xyz(-OFFSET_X, -OFFSET_Y, 0.),
234 Shape::Line(Segment2d::from_direction_and_length(
235 Dir2::from_xy(1., 0.3).unwrap(),
236 90.,
237 )),
238 Spin,
239 DesiredVolume::Circle,
240 Intersects::default(),
241 ));
242
243 commands.spawn((
244 Transform::from_xyz(0., -OFFSET_Y, 0.),
245 Shape::Capsule(Capsule2d::new(25., 50.)),
246 Spin,
247 DesiredVolume::Aabb,
248 Intersects::default(),
249 ));
250
251 commands.spawn((
252 Transform::from_xyz(OFFSET_X, -OFFSET_Y, 0.),
253 Shape::Polygon(RegularPolygon::new(50., 6)),
254 Spin,
255 DesiredVolume::Circle,
256 Intersects::default(),
257 ));
258
259 commands.spawn((
260 Text::default(),
261 Node {
262 position_type: PositionType::Absolute,
263 top: px(12),
264 left: px(12),
265 ..default()
266 },
267 ));
268}
269
270fn draw_filled_circle(gizmos: &mut Gizmos, position: Vec2, color: Srgba) {
271 for r in [1., 2., 3.] {
272 gizmos.circle_2d(position, r, color);
273 }
274}
275
276fn draw_ray(gizmos: &mut Gizmos, ray: &RayCast2d) {
277 gizmos.line_2d(
278 ray.ray.origin,
279 ray.ray.origin + *ray.ray.direction * ray.max,
280 WHITE,
281 );
282 draw_filled_circle(gizmos, ray.ray.origin, FUCHSIA);
283}
284
285fn get_and_draw_ray(gizmos: &mut Gizmos, time: &Time) -> RayCast2d {
286 let ray = Vec2::new(ops::cos(time.elapsed_secs()), ops::sin(time.elapsed_secs()));
287 let dist = 150. + ops::sin(0.5 * time.elapsed_secs()).abs() * 500.;
288
289 let aabb_ray = Ray2d {
290 origin: ray * 250.,
291 direction: Dir2::new_unchecked(-ray),
292 };
293 let ray_cast = RayCast2d::from_ray(aabb_ray, dist - 20.);
294
295 draw_ray(gizmos, &ray_cast);
296 ray_cast
297}
298
299fn ray_cast_system(
300 mut gizmos: Gizmos,
301 time: Res<Time>,
302 mut volumes: Query<(&CurrentVolume, &mut Intersects)>,
303) {
304 let ray_cast = get_and_draw_ray(&mut gizmos, &time);
305
306 for (volume, mut intersects) in volumes.iter_mut() {
307 let toi = match volume {
308 CurrentVolume::Aabb(a) => ray_cast.aabb_intersection_at(a),
309 CurrentVolume::Circle(c) => ray_cast.circle_intersection_at(c),
310 };
311 **intersects = toi.is_some();
312 if let Some(toi) = toi {
313 draw_filled_circle(
314 &mut gizmos,
315 ray_cast.ray.origin + *ray_cast.ray.direction * toi,
316 LIME,
317 );
318 }
319 }
320}
321
322fn aabb_cast_system(
323 mut gizmos: Gizmos,
324 time: Res<Time>,
325 mut volumes: Query<(&CurrentVolume, &mut Intersects)>,
326) {
327 let ray_cast = get_and_draw_ray(&mut gizmos, &time);
328 let aabb_cast = AabbCast2d {
329 aabb: Aabb2d::new(Vec2::ZERO, Vec2::splat(15.)),
330 ray: ray_cast,
331 };
332
333 for (volume, mut intersects) in volumes.iter_mut() {
334 let toi = match *volume {
335 CurrentVolume::Aabb(a) => aabb_cast.aabb_collision_at(a),
336 CurrentVolume::Circle(_) => None,
337 };
338
339 **intersects = toi.is_some();
340 if let Some(toi) = toi {
341 gizmos.rect_2d(
342 aabb_cast.ray.ray.origin + *aabb_cast.ray.ray.direction * toi,
343 aabb_cast.aabb.half_size() * 2.,
344 LIME,
345 );
346 }
347 }
348}
349
350fn bounding_circle_cast_system(
351 mut gizmos: Gizmos,
352 time: Res<Time>,
353 mut volumes: Query<(&CurrentVolume, &mut Intersects)>,
354) {
355 let ray_cast = get_and_draw_ray(&mut gizmos, &time);
356 let circle_cast = BoundingCircleCast {
357 circle: BoundingCircle::new(Vec2::ZERO, 15.),
358 ray: ray_cast,
359 };
360
361 for (volume, mut intersects) in volumes.iter_mut() {
362 let toi = match *volume {
363 CurrentVolume::Aabb(_) => None,
364 CurrentVolume::Circle(c) => circle_cast.circle_collision_at(c),
365 };
366
367 **intersects = toi.is_some();
368 if let Some(toi) = toi {
369 gizmos.circle_2d(
370 circle_cast.ray.ray.origin + *circle_cast.ray.ray.direction * toi,
371 circle_cast.circle.radius(),
372 LIME,
373 );
374 }
375 }
376}
377
378fn get_intersection_position(time: &Time) -> Vec2 {
379 let x = ops::cos(0.8 * time.elapsed_secs()) * 250.;
380 let y = ops::sin(0.4 * time.elapsed_secs()) * 100.;
381 Vec2::new(x, y)
382}
383
384fn aabb_intersection_system(
385 mut gizmos: Gizmos,
386 time: Res<Time>,
387 mut volumes: Query<(&CurrentVolume, &mut Intersects)>,
388) {
389 let center = get_intersection_position(&time);
390 let aabb = Aabb2d::new(center, Vec2::splat(50.));
391 gizmos.rect_2d(center, aabb.half_size() * 2., YELLOW);
392
393 for (volume, mut intersects) in volumes.iter_mut() {
394 let hit = match volume {
395 CurrentVolume::Aabb(a) => aabb.intersects(a),
396 CurrentVolume::Circle(c) => aabb.intersects(c),
397 };
398
399 **intersects = hit;
400 }
401}
402
403fn circle_intersection_system(
404 mut gizmos: Gizmos,
405 time: Res<Time>,
406 mut volumes: Query<(&CurrentVolume, &mut Intersects)>,
407) {
408 let center = get_intersection_position(&time);
409 let circle = BoundingCircle::new(center, 50.);
410 gizmos.circle_2d(center, circle.radius(), YELLOW);
411
412 for (volume, mut intersects) in volumes.iter_mut() {
413 let hit = match volume {
414 CurrentVolume::Aabb(a) => circle.intersects(a),
415 CurrentVolume::Circle(c) => circle.intersects(c),
416 };
417
418 **intersects = hit;
419 }
420}- examples/shader/shader_prepass.rs
- examples/stress_tests/text_pipeline.rs
- examples/asset/asset_saving_with_subassets.rs
- examples/math/custom_primitives.rs
- examples/3d/bloom_3d.rs
- examples/app/render_recovery.rs
- examples/3d/ssr.rs
- examples/app/externally_driven_headless_renderer.rs
- examples/3d/specular_tint.rs
- examples/3d/fog_volumes.rs
- examples/ecs/contiguous_query.rs
- examples/shader/automatic_instancing.rs
- examples/ui/navigation/directional_navigation.rs
- examples/3d/parallax_mapping.rs
- examples/ui/scroll_and_overflow/overflow.rs
- examples/3d/atmosphere.rs
- examples/ui/widgets/standard_widgets_observers.rs
- examples/ui/navigation/directional_navigation_overrides.rs
- examples/3d/anisotropy.rs
- examples/math/cubic_splines.rs
- examples/3d/volumetric_fog.rs
- examples/3d/rotate_environment_map.rs
- examples/3d/camera_sub_view.rs
- examples/3d/deferred_rendering.rs
- examples/async_tasks/async_channel_pattern.rs
- examples/3d/clearcoat.rs
- examples/app/settings.rs
- examples/movement/physics_in_fixed_timestep.rs
- examples/2d/tilemap_chunk.rs
- examples/audio/soundtrack.rs
- examples/time/virtual_time.rs
- examples/3d/light_textures.rs
- examples/ui/widgets/tab_navigation.rs
- examples/3d/spotlight.rs
- examples/stress_tests/many_animated_sprites.rs
- examples/animation/animation_graph.rs
- examples/shader/array_texture.rs
- examples/audio/spatial_audio_2d.rs
- examples/asset/asset_saving.rs
- examples/ui/scroll_and_overflow/scrollbars.rs
- examples/3d/tonemapping.rs
- examples/audio/spatial_audio_3d.rs
- examples/math/render_primitives.rs
- examples/window/window_drag_move.rs
- examples/ui/widgets/standard_widgets.rs
- examples/3d/depth_of_field.rs
- examples/testbed/full_ui.rs
- examples/3d/solari.rs
- examples/3d/pcss.rs
- examples/3d/mirror.rs
- examples/usage/character_creation.rs
- examples/3d/mixed_lighting.rs
- examples/animation/animation_masks.rs
- examples/ui/styling/gradients.rs
- examples/3d/visibility_range.rs
- examples/showcase/alien_cake_addict.rs
- examples/ui/ui_transform.rs
- examples/stress_tests/many_buttons.rs
- examples/3d/clustered_decal_maps.rs
- examples/3d/contact_shadows.rs
- examples/ui/widgets/feathers_gallery.rs
Sourcepub fn iter_inner(self) -> QueryIter<'w, 's, D, F> ⓘ
pub fn iter_inner(self) -> QueryIter<'w, 's, D, F> ⓘ
Returns an Iterator over the query items, with the actual “inner” world lifetime.
This iterator is always guaranteed to return results from each matching entity once and only once. Iteration order is not guaranteed.
If the QueryData does not implement IterQueryData,
then it is not sound to yield multiple items concurrently
and the resulting QueryIter will not implement Iterator.
To iterate over the items in that case,
use the QueryIter::fetch_next() method,
which ensures only one item is alive at a time.
§Example
Here, the report_names_system iterates over the Player component of every entity
that contains it:
fn report_names_system(query: Query<&Player>) {
for player in &query {
println!("Say hello to {}!", player.name);
}
}Sourcepub fn iter_combinations<const K: usize>(
&self,
) -> QueryCombinationIter<'_, 's, <D as QueryData>::ReadOnly, F, K> ⓘ
pub fn iter_combinations<const K: usize>( &self, ) -> QueryCombinationIter<'_, 's, <D as QueryData>::ReadOnly, F, K> ⓘ
Returns a QueryCombinationIter over all combinations of K read-only query items without repetition.
This iterator is always guaranteed to return results from each unique pair of matching entities. Iteration order is not guaranteed.
§Example
fn some_system(query: Query<&ComponentA>) {
for [a1, a2] in query.iter_combinations() {
// ...
}
}§See also
iter_combinations_mutfor mutable query item combinations.iter_combinations_innerfor mutable query item combinations with the full'worldlifetime.
Sourcepub fn iter_combinations_mut<const K: usize>(
&mut self,
) -> QueryCombinationIter<'_, 's, D, F, K> ⓘwhere
D: IterQueryData,
pub fn iter_combinations_mut<const K: usize>(
&mut self,
) -> QueryCombinationIter<'_, 's, D, F, K> ⓘwhere
D: IterQueryData,
Returns a QueryCombinationIter over all combinations of K query items without repetition.
This iterator is always guaranteed to return results from each unique pair of matching entities. Iteration order is not guaranteed.
§Example
fn some_system(mut query: Query<&mut ComponentA>) {
let mut combinations = query.iter_combinations_mut();
while let Some([mut a1, mut a2]) = combinations.fetch_next() {
// mutably access components data
}
}§See also
iter_combinationsfor read-only query item combinations.iter_combinations_innerfor mutable query item combinations with the full'worldlifetime.
Examples found in repository?
122fn interact_bodies(mut query: Query<(&Mass, &GlobalTransform, &mut Acceleration)>) {
123 let mut iter = query.iter_combinations_mut();
124 while let Some([(Mass(m1), transform1, mut acc1), (Mass(m2), transform2, mut acc2)]) =
125 iter.fetch_next()
126 {
127 let delta = transform2.translation() - transform1.translation();
128 let distance_sq: f32 = delta.length_squared();
129
130 let f = GRAVITY_CONSTANT / distance_sq;
131 let force_unit_mass = delta * f;
132 acc1.0 += force_unit_mass * *m2;
133 acc2.0 -= force_unit_mass * *m1;
134 }
135}Sourcepub fn iter_combinations_inner<const K: usize>(
self,
) -> QueryCombinationIter<'w, 's, D, F, K> ⓘwhere
D: IterQueryData,
pub fn iter_combinations_inner<const K: usize>(
self,
) -> QueryCombinationIter<'w, 's, D, F, K> ⓘwhere
D: IterQueryData,
Returns a QueryCombinationIter over all combinations of K query items without repetition.
This consumes the Query to return results with the actual “inner” world lifetime.
This iterator is always guaranteed to return results from each unique pair of matching entities. Iteration order is not guaranteed.
§Example
fn some_system(query: Query<&mut ComponentA>) {
let mut combinations = query.iter_combinations_inner();
while let Some([mut a1, mut a2]) = combinations.fetch_next() {
// mutably access components data
}
}§See also
iter_combinationsfor read-only query item combinations.iter_combinations_mutfor mutable query item combinations.
Sourcepub fn iter_many<EntityList>(
&self,
entities: EntityList,
) -> QueryManyIter<'_, 's, <D as QueryData>::ReadOnly, F, <EntityList as IntoIterator>::IntoIter> ⓘ
pub fn iter_many<EntityList>( &self, entities: EntityList, ) -> QueryManyIter<'_, 's, <D as QueryData>::ReadOnly, F, <EntityList as IntoIterator>::IntoIter> ⓘ
Returns an Iterator over the read-only query items generated from an Entity list.
Items are returned in the order of the list of entities, and may not be unique if the input
doesn’t guarantee uniqueness.
In case of a nonexisting entity or mismatched component, a QueryEntityError is generated instead.
§Examples
// A component containing an entity list.
#[derive(Component)]
struct Friends {
list: Vec<Entity>,
}
fn matching_system(
friends_query: Query<&Friends>,
counter_query: Query<&Counter>,
) {
for friends in &friends_query {
for counter in counter_query.iter_many(&friends.list).matched() {
println!("Friend's counter: {}", counter.value);
}
}
}
fn unwrapping_system(
friends_query: Query<&Friends>,
counter_query: Query<&Counter>,
) {
for friends in &friends_query {
for counter in counter_query.iter_many(&friends.list).unwrapped() {
println!("Friend's counter: {}", counter.value);
}
}
}
fn error_system(
friends_query: Query<&Friends>,
counter_query: Query<&Counter>,
) -> Result<(), BevyError> {
for friends in &friends_query {
for counter_result in counter_query.iter_many(&friends.list) {
let counter = counter_result?;
println!("Friend's counter: {}", counter.value);
}
}
Ok(())
}§See also
iter_many_mutto get mutable query items.iter_many_innerto get mutable query items with the full'worldlifetime.
Examples found in repository?
337fn change_setting(
338 new_app_setting: &AppSetting,
339 app_state: &mut AppState,
340 camera: Single<(Entity, Has<OrderIndependentTransparencySettings>), With<Camera3d>>,
341 radio_group_q: Query<(&Children, &RadioGroupSetting), With<RadioGroup>>,
342 setting_q: Query<(Entity, &RadioButtonOptionValue<AppSetting>), With<RadioButton>>,
343 commands: &mut Commands,
344) {
345 let radio_group_setting = match *new_app_setting {
346 AppSetting::EnableOIT(value) => {
347 app_state.use_oit = value;
348 if app_state.use_oit {
349 commands.entity(camera.0).insert(app_state.oit_settings);
350 } else {
351 commands
352 .entity(camera.0)
353 .remove::<OrderIndependentTransparencySettings>();
354 }
355 RadioGroupSetting::EnableOIT
356 }
357 AppSetting::UseDepthPrepass(value) => {
358 app_state.use_depth_prepass = value;
359
360 if app_state.use_depth_prepass {
361 commands.entity(camera.0).insert(DepthPrepass);
362 } else {
363 commands.entity(camera.0).remove::<DepthPrepass>();
364 }
365 RadioGroupSetting::UseDepthPrepass
366 }
367 AppSetting::ChangeScene(id) => {
368 if id != app_state.current_scene_id {
369 app_state.current_scene_id = id;
370 }
371 RadioGroupSetting::ChangeScene
372 // The actual scene change is handled by scene_change_watcher()
373 }
374 };
375
376 // Update the radio group
377 for (children, group_setting) in radio_group_q.iter() {
378 if *group_setting != radio_group_setting {
379 continue;
380 }
381 for (entity, setting) in setting_q.iter_many(children).matched() {
382 if setting.0 == *new_app_setting {
383 commands.entity(entity).insert(Checked);
384 } else {
385 commands.entity(entity).remove::<Checked>();
386 }
387 }
388 }
389}Sourcepub fn iter_many_mut<EntityList>(
&mut self,
entities: EntityList,
) -> QueryManyIter<'_, 's, D, F, <EntityList as IntoIterator>::IntoIter> ⓘ
pub fn iter_many_mut<EntityList>( &mut self, entities: EntityList, ) -> QueryManyIter<'_, 's, D, F, <EntityList as IntoIterator>::IntoIter> ⓘ
Returns an iterator over the query items generated from an Entity list.
Items are returned in the order of the list of entities, and may not be unique if the input
doesn’t guarantee uniqueness.
In case of a nonexisting entity or mismatched component, a QueryEntityError is generated instead.
§Examples
#[derive(Component)]
struct Counter {
value: i32
}
#[derive(Component)]
struct Friends {
list: Vec<Entity>,
}
fn system(
friends_query: Query<&Friends>,
mut counter_query: Query<&mut Counter>,
) {
for friends in &friends_query {
let mut iter = counter_query.iter_many_mut(&friends.list).matched();
while let Some(mut counter) = iter.fetch_next() {
println!("Friend's counter: {}", counter.value);
counter.value += 1;
}
}
}§See also
iter_manyto get read-only query items.iter_many_innerto get mutable query items with the full'worldlifetime.
Sourcepub fn iter_many_inner<EntityList>(
self,
entities: EntityList,
) -> QueryManyIter<'w, 's, D, F, <EntityList as IntoIterator>::IntoIter> ⓘ
pub fn iter_many_inner<EntityList>( self, entities: EntityList, ) -> QueryManyIter<'w, 's, D, F, <EntityList as IntoIterator>::IntoIter> ⓘ
Returns an iterator over the query items generated from an Entity list.
This consumes the Query to return results with the actual “inner” world lifetime.
Items are returned in the order of the list of entities, and may not be unique if the input
doesn’t guarantee uniqueness.
In case of a nonexisting entity or mismatched component, a QueryEntityError is generated instead.
§See also
iter_manyto get read-only query items.iter_many_mutto get mutable query items.
Sourcepub fn iter_many_unique<EntityList>(
&self,
entities: EntityList,
) -> QueryManyUniqueIter<'_, 's, <D as QueryData>::ReadOnly, F, <EntityList as IntoIterator>::IntoIter> ⓘwhere
EntityList: EntitySet,
pub fn iter_many_unique<EntityList>(
&self,
entities: EntityList,
) -> QueryManyUniqueIter<'_, 's, <D as QueryData>::ReadOnly, F, <EntityList as IntoIterator>::IntoIter> ⓘwhere
EntityList: EntitySet,
Returns an Iterator over the unique read-only query items generated from an EntitySet.
Items are returned in the order of the list of entities.
In case of a nonexisting entity or mismatched component, a QueryEntityError is generated instead.
§Example
// `Friends` ensures that it only lists unique entities.
#[derive(Component)]
struct Friends {
unique_list: Vec<Entity>,
}
impl<'a> IntoIterator for &'a Friends {
type Item = &'a Entity;
type IntoIter = UniqueEntityIter<slice::Iter<'a, Entity>>;
fn into_iter(self) -> Self::IntoIter {
// SAFETY: `Friends` ensures that it unique_list contains only unique entities.
unsafe { UniqueEntityIter::from_iter_unchecked(self.unique_list.iter()) }
}
}
fn system(
friends_query: Query<&Friends>,
counter_query: Query<&Counter>,
) {
for friends in &friends_query {
for counter in counter_query.iter_many_unique(friends).matched() {
println!("Friend's counter: {:?}", counter.value);
}
}
}§See also
iter_many_unique_mutto get mutable query items.iter_many_unique_innerto get with the actual “inner” world lifetime.
Sourcepub fn iter_many_unique_mut<EntityList>(
&mut self,
entities: EntityList,
) -> QueryManyUniqueIter<'_, 's, D, F, <EntityList as IntoIterator>::IntoIter> ⓘwhere
EntityList: EntitySet,
D: IterQueryData,
pub fn iter_many_unique_mut<EntityList>(
&mut self,
entities: EntityList,
) -> QueryManyUniqueIter<'_, 's, D, F, <EntityList as IntoIterator>::IntoIter> ⓘwhere
EntityList: EntitySet,
D: IterQueryData,
Returns an iterator over the unique query items generated from an EntitySet.
Items are returned in the order of the list of entities.
In case of a nonexisting entity or mismatched component, a QueryEntityError is generated instead.
§Examples
#[derive(Component)]
struct Counter {
value: i32
}
// `Friends` ensures that it only lists unique entities.
#[derive(Component)]
struct Friends {
unique_list: Vec<Entity>,
}
impl<'a> IntoIterator for &'a Friends {
type Item = &'a Entity;
type IntoIter = UniqueEntityIter<slice::Iter<'a, Entity>>;
fn into_iter(self) -> Self::IntoIter {
// SAFETY: `Friends` ensures that it unique_list contains only unique entities.
unsafe { UniqueEntityIter::from_iter_unchecked(self.unique_list.iter()) }
}
}
fn system(
friends_query: Query<&Friends>,
mut counter_query: Query<&mut Counter>,
) {
for friends in &friends_query {
for mut counter in counter_query.iter_many_unique_mut(friends).matched() {
println!("Friend's counter: {:?}", counter.value);
counter.value += 1;
}
}
}§See also
iter_many_uniqueto get read-only query items.iter_many_unique_innerto get with the actual “inner” world lifetime.
Sourcepub fn iter_many_unique_inner<EntityList>(
self,
entities: EntityList,
) -> QueryManyUniqueIter<'w, 's, D, F, <EntityList as IntoIterator>::IntoIter> ⓘwhere
EntityList: EntitySet,
D: IterQueryData,
pub fn iter_many_unique_inner<EntityList>(
self,
entities: EntityList,
) -> QueryManyUniqueIter<'w, 's, D, F, <EntityList as IntoIterator>::IntoIter> ⓘwhere
EntityList: EntitySet,
D: IterQueryData,
Returns an iterator over the unique query items generated from an EntitySet.
This consumes the Query to return results with the actual “inner” world lifetime.
Items are returned in the order of the list of entities.
In case of a nonexisting entity or mismatched component, a QueryEntityError is generated instead.
§Examples
#[derive(Component)]
struct Counter {
value: i32
}
// `Friends` ensures that it only lists unique entities.
#[derive(Component)]
struct Friends {
unique_list: Vec<Entity>,
}
impl<'a> IntoIterator for &'a Friends {
type Item = &'a Entity;
type IntoIter = UniqueEntityIter<slice::Iter<'a, Entity>>;
fn into_iter(self) -> Self::IntoIter {
// SAFETY: `Friends` ensures that it unique_list contains only unique entities.
unsafe { UniqueEntityIter::from_iter_unchecked(self.unique_list.iter()) }
}
}
fn system(
friends_query: Query<&Friends>,
mut counter_query: Query<&mut Counter>,
) {
let friends = friends_query.single().unwrap();
for mut counter in counter_query.iter_many_unique_inner(friends).matched() {
println!("Friend's counter: {:?}", counter.value);
counter.value += 1;
}
}§See also
iter_many_uniqueto get read-only query items.iter_many_unique_mutto get mutable query items.
Sourcepub unsafe fn iter_unsafe(&self) -> QueryIter<'_, 's, D, F> ⓘwhere
D: IterQueryData,
pub unsafe fn iter_unsafe(&self) -> QueryIter<'_, 's, D, F> ⓘwhere
D: IterQueryData,
Returns an Iterator over the query items.
This iterator is always guaranteed to return results from each matching entity once and only once. Iteration order is not guaranteed.
If the QueryData does not implement IterQueryData,
then it is not sound to yield multiple items concurrently
and the resulting QueryIter will not implement Iterator.
To iterate over the items in that case,
use the QueryIter::fetch_next() method,
which ensures only one item is alive at a time.
§Safety
This function makes it possible to violate Rust’s aliasing guarantees. You must make sure this call does not result in multiple mutable references to the same component.
§See also
Sourcepub unsafe fn iter_combinations_unsafe<const K: usize>(
&self,
) -> QueryCombinationIter<'_, 's, D, F, K> ⓘwhere
D: IterQueryData,
pub unsafe fn iter_combinations_unsafe<const K: usize>(
&self,
) -> QueryCombinationIter<'_, 's, D, F, K> ⓘwhere
D: IterQueryData,
Iterates over all possible combinations of K query items without repetition.
This iterator is always guaranteed to return results from each unique pair of matching entities. Iteration order is not guaranteed.
§Safety
This allows aliased mutability. You must make sure this call does not result in multiple mutable references to the same component.
§See also
iter_combinationsanditer_combinations_mutfor the safe versions.
Sourcepub unsafe fn iter_many_unsafe<EntityList>(
&self,
entities: EntityList,
) -> QueryManyIter<'_, 's, D, F, <EntityList as IntoIterator>::IntoIter> ⓘ
pub unsafe fn iter_many_unsafe<EntityList>( &self, entities: EntityList, ) -> QueryManyIter<'_, 's, D, F, <EntityList as IntoIterator>::IntoIter> ⓘ
Returns an Iterator over the query items generated from an Entity list.
Items are returned in the order of the list of entities, and may not be unique if the input
doesnn’t guarantee uniqueness.
In case of a nonexisting entity or mismatched component, a QueryEntityError is generated instead.
§Safety
This allows aliased mutability and does not check for entity uniqueness.
You must make sure this call does not result in multiple mutable references to the same component.
Particular care must be taken when collecting the data (rather than iterating over it one item at a time) such as via Iterator::collect.
§See also
iter_many_mutto safely access the query items.
Sourcepub unsafe fn iter_many_unique_unsafe<EntityList>(
&self,
entities: EntityList,
) -> QueryManyUniqueIter<'_, 's, D, F, <EntityList as IntoIterator>::IntoIter> ⓘwhere
EntityList: EntitySet,
D: IterQueryData,
pub unsafe fn iter_many_unique_unsafe<EntityList>(
&self,
entities: EntityList,
) -> QueryManyUniqueIter<'_, 's, D, F, <EntityList as IntoIterator>::IntoIter> ⓘwhere
EntityList: EntitySet,
D: IterQueryData,
Returns an Iterator over the unique query items generated from an Entity list.
Items are returned in the order of the list of entities.
In case of a nonexisting entity or mismatched component, a QueryEntityError is generated instead.
§Safety
This allows aliased mutability. You must make sure this call does not result in multiple mutable references to the same component.
§See also
iter_many_uniqueto get read-only query items.iter_many_unique_mutto get mutable query items.iter_many_unique_innerto get with the actual “inner” world lifetime.
Sourcepub fn par_iter(&self) -> QueryParIter<'_, 's, <D as QueryData>::ReadOnly, F>
pub fn par_iter(&self) -> QueryParIter<'_, 's, <D as QueryData>::ReadOnly, F>
Returns a parallel iterator over the query results for the given World.
This parallel iterator is always guaranteed to return results from each matching entity once and only once. Iteration order and thread assignment is not guaranteed.
If the multithreaded feature is disabled, iterating with this operates identically to Iterator::for_each
on QueryIter.
This can only be called for read-only queries, see par_iter_mut for write-queries.
Note that you must use the for_each method to iterate over the
results, see par_iter_mut for an example.
Examples found in repository?
274fn check_entities_needing_specialization(
275 needs_specialization: Query<
276 Entity,
277 (
278 Or<(
279 Changed<Mesh3d>,
280 AssetChanged<Mesh3d>,
281 Changed<ImageMaterial3d>,
282 AssetChanged<ImageMaterial3d>,
283 )>,
284 With<ImageMaterial3d>,
285 ),
286 >,
287 mut par_local: Local<Parallel<Vec<Entity>>>,
288 mut entities_needing_specialization: ResMut<EntitiesNeedingSpecialization<ImageMaterial>>,
289 mut removed_mesh_3d_components: RemovedComponents<Mesh3d>,
290 mut removed_mesh_material_3d_components: RemovedComponents<ImageMaterial3d>,
291) {
292 entities_needing_specialization.changed.clear();
293 entities_needing_specialization.removed.clear();
294
295 // Gather all entities that need their specializations regenerated.
296 needs_specialization
297 .par_iter()
298 .for_each(|entity| par_local.borrow_local_mut().push(entity));
299 par_local.drain_into(&mut entities_needing_specialization.changed);
300
301 // All entities that removed their `Mesh3d` or `ImageMaterial3d` components
302 // need to have their specializations removed as well.
303 for entity in removed_mesh_3d_components
304 .read()
305 .chain(removed_mesh_material_3d_components.read())
306 {
307 entities_needing_specialization.removed.push(entity);
308 }
309}Sourcepub fn par_iter_mut(&mut self) -> QueryParIter<'_, 's, D, F>where
D: IterQueryData,
pub fn par_iter_mut(&mut self) -> QueryParIter<'_, 's, D, F>where
D: IterQueryData,
Returns a parallel iterator over the query results for the given World.
This parallel iterator is always guaranteed to return results from each matching entity once and only once. Iteration order and thread assignment is not guaranteed.
If the multithreaded feature is disabled, iterating with this operates identically to Iterator::for_each
on QueryIter.
This can only be called for mutable queries, see par_iter for read-only-queries.
§Example
Here, the gravity_system updates the Velocity component of every entity that contains it:
fn gravity_system(mut query: Query<&mut Velocity>) {
const DELTA: f32 = 1.0 / 60.0;
query.par_iter_mut().for_each(|mut velocity| {
velocity.y -= 9.8 * DELTA;
});
}Examples found in repository?
More examples
28fn move_system(mut sprites: Query<(&mut Transform, &Velocity)>) {
29 // Compute the new location of each sprite in parallel on the
30 // ComputeTaskPool
31 //
32 // This example is only for demonstrative purposes. Using a
33 // ParallelIterator for an inexpensive operation like addition on only 128
34 // elements will not typically be faster than just using a normal Iterator.
35 // See the ParallelIterator documentation for more information on when
36 // to use or not use ParallelIterator over a normal Iterator.
37 sprites
38 .par_iter_mut()
39 .for_each(|(mut transform, velocity)| {
40 transform.translation += velocity.extend(0.0);
41 });
42}
43
44// Bounce sprites outside the window
45fn bounce_system(window: Query<&Window>, mut sprites: Query<(&Transform, &mut Velocity)>) {
46 let Ok(window) = window.single() else {
47 return;
48 };
49 let width = window.width();
50 let height = window.height();
51 let left = width / -2.0;
52 let right = width / 2.0;
53 let bottom = height / -2.0;
54 let top = height / 2.0;
55 // The default batch size can also be overridden.
56 // In this case a batch size of 32 is chosen to limit the overhead of
57 // ParallelIterator, since negating a vector is very inexpensive.
58 sprites
59 .par_iter_mut()
60 .batching_strategy(BatchingStrategy::fixed(32))
61 .for_each(|(transform, mut v)| {
62 if !(left < transform.translation.x
63 && transform.translation.x < right
64 && bottom < transform.translation.y
65 && transform.translation.y < top)
66 {
67 // For simplicity, just reverse the velocity; don't use realistic bounces
68 v.0 = -v.0;
69 }
70 });
71}Sourcepub fn par_iter_inner(self) -> QueryParIter<'w, 's, D, F>where
D: IterQueryData,
pub fn par_iter_inner(self) -> QueryParIter<'w, 's, D, F>where
D: IterQueryData,
Returns a parallel iterator over the query results for the given World.
This consumes the Query to return results with the actual “inner” world lifetime.
This parallel iterator is always guaranteed to return results from each matching entity once and only once. Iteration order and thread assignment is not guaranteed.
If the multithreaded feature is disabled, iterating with this operates identically to Iterator::for_each
on QueryIter.
§Example
Here, the gravity_system updates the Velocity component of every entity that contains it:
fn gravity_system(query: Query<&mut Velocity>) {
const DELTA: f32 = 1.0 / 60.0;
query.par_iter_inner().for_each(|mut velocity| {
velocity.y -= 9.8 * DELTA;
});
}Sourcepub fn par_iter_many<EntityList>(
&self,
entities: EntityList,
) -> QueryParManyIter<'_, 's, <D as QueryData>::ReadOnly, F, <EntityList as IntoIterator>::Item>
pub fn par_iter_many<EntityList>( &self, entities: EntityList, ) -> QueryParManyIter<'_, 's, <D as QueryData>::ReadOnly, F, <EntityList as IntoIterator>::Item>
Returns a parallel iterator over the read-only query items generated from an Entity list.
In case of a nonexisting entity or mismatched component, a QueryEntityError is generated instead.
Iteration order and thread assignment is not guaranteed.
If the multithreaded feature is disabled, iterating with this operates identically to Iterator::for_each
on QueryManyIter.
This can only be called for read-only queries. To avoid potential aliasing, there is no par_iter_many_mut equivalent.
See par_iter_many_unique_mut for an alternative using EntitySet.
Note that you must use the for_each method to iterate over the
results, see par_iter_mut for an example.
Sourcepub fn par_iter_many_unique<EntityList>(
&self,
entities: EntityList,
) -> QueryParManyUniqueIter<'_, 's, <D as QueryData>::ReadOnly, F, <EntityList as IntoIterator>::Item>
pub fn par_iter_many_unique<EntityList>( &self, entities: EntityList, ) -> QueryParManyUniqueIter<'_, 's, <D as QueryData>::ReadOnly, F, <EntityList as IntoIterator>::Item>
Returns a parallel iterator over the unique read-only query items generated from an EntitySet.
Iteration order and thread assignment is not guaranteed.
In case of a nonexisting entity or mismatched component, a QueryEntityError is generated instead.
If the multithreaded feature is disabled, iterating with this operates identically to Iterator::for_each
on QueryManyUniqueIter.
This can only be called for read-only queries, see par_iter_many_unique_mut for write-queries.
Note that you must use the for_each method to iterate over the
results, see par_iter_mut for an example.
Sourcepub fn par_iter_many_unique_mut<EntityList>(
&mut self,
entities: EntityList,
) -> QueryParManyUniqueIter<'_, 's, D, F, <EntityList as IntoIterator>::Item>
pub fn par_iter_many_unique_mut<EntityList>( &mut self, entities: EntityList, ) -> QueryParManyUniqueIter<'_, 's, D, F, <EntityList as IntoIterator>::Item>
Returns a parallel iterator over the unique query items generated from an EntitySet.
Iteration order and thread assignment is not guaranteed.
In case of a nonexisting entity or mismatched component, a QueryEntityError is generated instead.
If the multithreaded feature is disabled, iterating with this operates identically to Iterator::for_each
on QueryManyUniqueIter.
This can only be called for mutable queries, see par_iter_many_unique for read-only-queries.
Note that you must use the for_each method to iterate over the
results, see par_iter_mut for an example.
Sourcepub fn contiguous_iter(
&self,
) -> Result<QueryContiguousIter<'_, 's, <D as QueryData>::ReadOnly, F>, QueryNotDenseError>
pub fn contiguous_iter( &self, ) -> Result<QueryContiguousIter<'_, 's, <D as QueryData>::ReadOnly, F>, QueryNotDenseError>
Returns a contiguous iterator over the query results for the given
World or Err with QueryNotDenseError if the query is not dense hence not contiguously
iterable.
Contiguous iteration enables getting slices of contiguously lying components (which lie in the same table), which for example may be used for simd-operations, which may accelerate an algorithm.
§Example
The following system despawns all entities which health is negative.
fn despawn_all_dead_entities(mut commands: Commands, query: Query<(Entity, &Health)>) {
for (entities, health) in query.contiguous_iter().unwrap() {
// For each entity there is one component, hence it always holds true
assert!(entities.len() == health.len());
for (entity, health) in entities.iter().zip(health.iter()) {
if health.0 < 0.0 {
commands.entity(*entity).despawn();
}
}
}
}
A mutable version: Self::contiguous_iter_mut
Examples found in repository?
215fn print_components_contiguous_iter(query: Query<CustomContiguousQuery<ComponentC, ComponentD>>) {
216 println!("Print components (contiguous_iter):");
217 for e in query.contiguous_iter().unwrap() {
218 let e: CustomContiguousQueryContiguousItem<'_, '_, _, _> = e;
219 println!("Entity: {:?}", e.entity);
220 println!("A: {:?}", e.a);
221 println!("B: {:?}", e.b);
222 println!(
223 "Generic: {:?} {:?}",
224 e.generic.generic.0, e.generic.generic.1
225 );
226 }
227}Sourcepub fn contiguous_iter_mut(
&mut self,
) -> Result<QueryContiguousIter<'_, 's, D, F>, QueryNotDenseError>where
D: ContiguousQueryData,
F: ArchetypeFilter,
pub fn contiguous_iter_mut(
&mut self,
) -> Result<QueryContiguousIter<'_, 's, D, F>, QueryNotDenseError>where
D: ContiguousQueryData,
F: ArchetypeFilter,
Returns a mutable contiguous iterator over the query results for the given
World or Err with QueryNotDenseError if the query is not dense hence not contiguously
iterable.
Contiguous iteration enables getting slices of contiguously lying components (which lie in the same table), which for example may be used for simd-operations, which may accelerate an algorithm.
§Example
The following system applies a “health decay” effect on all entities, which reduces their health by some fraction.
fn apply_health_decay(mut query: Query<(&mut Health, &HealthDecay)>) {
for (mut health, decay) in query.contiguous_iter_mut().unwrap() {
// all data slices returned by component queries are the same size
assert!(health.len() == decay.len());
// we could have used health.bypass_change_detection() to do less work.
for (health, decay) in health.iter_mut().zip(decay) {
health.0 *= decay.0;
}
}
}An immutable version: Self::contiguous_iter
Examples found in repository?
26fn apply_health_decay(mut query: Query<(&mut Health, &HealthDecay)>) {
27 // contiguous_iter_mut() would return None if query couldn't be iterated contiguously
28 for (mut health, decay) in query.contiguous_iter_mut().unwrap() {
29 // all data slices returned by component queries are the same size
30 assert!(health.len() == decay.len());
31 // we could also bypass change detection via bypass_change_detection() because we do not
32 // use it anyways.
33 for (health, decay) in health.iter_mut().zip(decay) {
34 health.0 *= decay.0;
35 }
36 }
37}Sourcepub fn contiguous_iter_inner(
self,
) -> Result<QueryContiguousIter<'w, 's, D, F>, QueryNotDenseError>where
D: ContiguousQueryData,
F: ArchetypeFilter,
pub fn contiguous_iter_inner(
self,
) -> Result<QueryContiguousIter<'w, 's, D, F>, QueryNotDenseError>where
D: ContiguousQueryData,
F: ArchetypeFilter,
Returns a contiguous iterator over the query results for the given
World or Err with QueryNotDenseError if the query is not dense hence not contiguously
iterable.
This consumes the Query to return results with the actual “inner” world lifetime.
Sourcepub fn contiguous_par_iter(
&self,
) -> Result<QueryContiguousParIter<'_, 's, <D as QueryData>::ReadOnly, F>, QueryNotDenseError>
pub fn contiguous_par_iter( &self, ) -> Result<QueryContiguousParIter<'_, 's, <D as QueryData>::ReadOnly, F>, QueryNotDenseError>
Returns a parallel iterator over contiguous query results for the given
World.
Contiguous iteration enables getting slices of contiguously laid out components that reside in the same table. These slices may for example be used for SIMD operations.
This parallel iterator is always guaranteed to return results from each matching entity once and only once. Iteration order and thread assignment is not guaranteed.
If the query isn’t contiguously iterable because it isn’t dense, this
method returns a QueryNotDenseError.
If the multithreaded feature is disabled, iterating with this operates
identically to Iterator::for_each on QueryContiguousIter.
This can only be called for read-only queries. For queries that may
write to the components they query, see Self::par_iter_mut.
Note that you must use the for_each method to iterate over the
results. See Self::contiguous_par_iter_mut for an example.
Sourcepub fn contiguous_par_iter_mut(
&mut self,
) -> Result<QueryContiguousParIter<'_, 's, D, F>, QueryNotDenseError>where
D: ContiguousQueryData,
F: ArchetypeFilter,
pub fn contiguous_par_iter_mut(
&mut self,
) -> Result<QueryContiguousParIter<'_, 's, D, F>, QueryNotDenseError>where
D: ContiguousQueryData,
F: ArchetypeFilter,
Returns a parallel iterator over contiguous query results for the given
World.
Contiguous iteration enables getting slices of contiguously laid out components that reside in the same table. These slices may for example be used for SIMD operations.
This parallel contiguous iterator is always guaranteed to return results from each matching entity once and only once. Iteration order and thread assignment is not guaranteed.
If the multithreaded feature is disabled, iterating with this operates
identically to Iterator::for_each on QueryContiguousIter.
This can only be called for mutable queries. See par_iter for
read-only queries.
§Example
Here, the gravity_system updates the Velocity component of every entity that contains it:
fn gravity_system(mut query: Query<&mut Velocity>) {
const DELTA: f32 = 1.0 / 60.0;
query.contiguous_par_iter_mut().unwrap().for_each(|mut velocities| {
for mut velocity in velocities {
velocity.y -= 9.8 * DELTA;
}
});
}Sourcepub fn contiguous_par_iter_inner(
self,
) -> Result<QueryContiguousParIter<'w, 's, D, F>, QueryNotDenseError>where
D: ContiguousQueryData,
F: ArchetypeFilter,
pub fn contiguous_par_iter_inner(
self,
) -> Result<QueryContiguousParIter<'w, 's, D, F>, QueryNotDenseError>where
D: ContiguousQueryData,
F: ArchetypeFilter,
Returns a parallel iterator over contiguous query results for the given
World. This consumes the Query to return
results with the actual “inner” world lifetime.
Contiguous iteration enables getting slices of contiguously laid out components that reside in the same table. These slices may for example be used for SIMD operations.
This parallel iterator is always guaranteed to return results from each matching entity once and only once. Iteration order and thread assignment is not guaranteed.
If the multithreaded feature is disabled, iterating with this operates
identically to Iterator::for_each on QueryContiguousIter.
Sourcepub fn get(
&self,
entity: Entity,
) -> Result<<<D as QueryData>::ReadOnly as QueryData>::Item<'_, 's>, QueryEntityError>
pub fn get( &self, entity: Entity, ) -> Result<<<D as QueryData>::ReadOnly as QueryData>::Item<'_, 's>, QueryEntityError>
Returns the read-only query item for the given Entity.
In case of a nonexisting entity or mismatched component, a QueryEntityError is returned instead.
This is always guaranteed to run in O(1) time.
§Example
Here, get is used to retrieve the exact query item of the entity specified by the SelectedCharacter resource.
fn print_selected_character_name_system(
query: Query<&Character>,
selection: Res<SelectedCharacter>
)
{
if let Ok(selected_character) = query.get(selection.entity) {
println!("{}", selected_character.name);
}
}§See also
get_mutto get a mutable query item.
Examples found in repository?
79fn attack_hits(attack: On<Attack>, name: Query<&Name>) {
80 if let Ok(name) = name.get(attack.entity) {
81 info!("Attack hit {}", name);
82 }
83}
84
85/// A callback placed on [`Armor`], checking if it absorbed all the [`Attack`] damage.
86fn block_attack(mut attack: On<Attack>, armor: Query<(&Armor, &Name)>) {
87 let (armor, name) = armor.get(attack.entity).unwrap();
88 let damage = attack.damage.saturating_sub(**armor);
89 if damage > 0 {
90 info!("🩸 {} damage passed through {}", damage, name);
91 // The attack isn't stopped by the armor. We reduce the damage of the attack, and allow
92 // it to continue on to the goblin.
93 attack.damage = damage;
94 } else {
95 info!("🛡️ {} damage blocked by {}", attack.damage, name);
96 // Armor stopped the attack, the event stops here.
97 attack.propagate(false);
98 info!("(propagation halted early)\n");
99 }
100}More examples
397fn handle_emission_type_change(
398 event: On<ValueChange<Entity>>,
399 new_value_q: Query<&RadioButtonOptionValue<AppSetting>>,
400 mut app_status: ResMut<AppStatus>,
401) {
402 let Ok(RadioButtonOptionValue(setting)) = new_value_q.get(event.value) else {
403 return;
404 };
405
406 let AppSetting::EmissiveDecals(on) = *setting;
407 app_status.emissive_decals = on;
408}469fn handle_enable_mip_generation_change(
470 event: On<ValueChange<Entity>>,
471 new_value_query: Query<&RadioButtonOptionValue<EnableMipGeneration>>,
472 mut app_status: ResMut<AppStatus>,
473) {
474 let Ok(RadioButtonOptionValue(enable_mip)) = new_value_query.get(event.value) else {
475 return;
476 };
477 app_status.enable_mip_generation = *enable_mip;
478
479 // Enabling mip generation does not trigger a request to regenerate the image.
480}
481
482/// Handles a request from the user to change the image size via the UI.
483fn handle_image_size_setting_change(
484 event: On<ValueChange<Entity>>,
485 new_value_query: Query<&RadioButtonOptionValue<ImageSizeSetting>>,
486 mut app_status: ResMut<AppStatus>,
487 mut regenerate_image_message_writer: MessageWriter<RegenerateImage>,
488) {
489 let Ok(RadioButtonOptionValue(size_setting)) = new_value_query.get(event.value) else {
490 return;
491 };
492
493 match *size_setting {
494 ImageSizeSetting::ImageWidth(image_size) => app_status.image_width = image_size,
495 ImageSizeSetting::ImageHeight(image_size) => app_status.image_height = image_size,
496 }
497
498 // Schedule the image to be regenerated.
499 regenerate_image_message_writer.write(RegenerateImage);
500}436fn handle_gizmos_enabled_change(
437 event: On<ValueChange<Entity>>,
438 new_value_query: Query<&RadioButtonOptionValue<GizmosEnabled>>,
439 mut app_status: ResMut<AppStatus>,
440 mut help_text_query: Query<&mut Text, With<HelpText>>,
441) {
442 let Ok(RadioButtonOptionValue(enabled)) = new_value_query.get(event.value) else {
443 return;
444 };
445 app_status.gizmos_enabled = *enabled;
446
447 set_help_text(&app_status, &mut help_text_query);
448}
449
450/// Handles requests from the user to toggle which object is showing.
451/// The `radio_self_update` observer handles setting the `Checked` state on the radio buttons.
452fn handle_object_to_show_change(
453 event: On<ValueChange<Entity>>,
454 new_value_query: Query<&RadioButtonOptionValue<ObjectToShow>>,
455 mut app_status: ResMut<AppStatus>,
456 mut spheres_query: Query<&mut Visibility, (With<ReflectiveSphere>, Without<ReflectivePrism>)>,
457 mut prisms_query: Query<&mut Visibility, (With<ReflectivePrism>, Without<ReflectiveSphere>)>,
458) {
459 let Ok(RadioButtonOptionValue(object_to_show)) = new_value_query.get(event.value) else {
460 return;
461 };
462 app_status.object_to_show = *object_to_show;
463
464 for mut sphere_visibility in &mut spheres_query {
465 *sphere_visibility = match app_status.object_to_show {
466 ObjectToShow::Sphere => Visibility::Inherited,
467 ObjectToShow::Prism => Visibility::Hidden,
468 }
469 }
470 for mut prism_visibility in &mut prisms_query {
471 *prism_visibility = match app_status.object_to_show {
472 ObjectToShow::Sphere => Visibility::Hidden,
473 ObjectToShow::Prism => Visibility::Inherited,
474 }
475 }
476}
477
478/// Handles requests from the user to switch the camera mode when the user clicks on one of the
479/// corresponding radio buttons.
480fn handle_camera_mode_change(
481 event: On<ValueChange<Entity>>,
482 new_value_query: Query<&RadioButtonOptionValue<CameraMode>>,
483 mut commands: Commands,
484 cameras_query: Query<(Entity, &Transform), With<Camera3d>>,
485 sphere_query: Query<&Transform, (With<ReflectiveSphere>, Without<Camera3d>)>,
486 mut help_text_query: Query<&mut Text, With<HelpText>>,
487 mut windows_query: Query<&mut CursorOptions>,
488 mut app_status: ResMut<AppStatus>,
489) {
490 let Some(sphere_transform) = sphere_query.iter().next() else {
491 return;
492 };
493
494 let Ok(RadioButtonOptionValue(camera_mode)) = new_value_query.get(event.value) else {
495 return;
496 };
497
498 app_status.camera_mode = *camera_mode;
499
500 match app_status.camera_mode {
501 CameraMode::Orbit => {
502 for (camera_entity, camera_transform) in &cameras_query {
503 // Convert from Cartesian coordinates back to spherical
504 // coordinates.
505 let relative_camera_position =
506 camera_transform.translation - sphere_transform.translation;
507 let radius = relative_camera_position.length();
508 let inclination = atan2(
509 relative_camera_position.xz().length() / radius,
510 relative_camera_position.y / radius,
511 );
512 let azimuth = atan2(
513 relative_camera_position.z * relative_camera_position.xz().length_recip(),
514 relative_camera_position.x * relative_camera_position.xz().length_recip(),
515 );
516
517 commands
518 .entity(camera_entity)
519 .remove::<FreeCamera>()
520 .insert(OrbitCamera {
521 radius,
522 inclination,
523 azimuth,
524 });
525 }
526 }
527
528 CameraMode::Free => {
529 for (camera_entity, _) in &cameras_query {
530 commands
531 .entity(camera_entity)
532 .remove::<OrbitCamera>()
533 .insert(FreeCamera::default());
534 }
535 }
536 }
537
538 set_help_text(&app_status, &mut help_text_query);
539
540 // Reset the cursor grab mode, because the free camera controller may
541 // have enabled it, and we don't want the cursor to disappear.
542 for mut cursor_options in &mut windows_query {
543 cursor_options.grab_mode = CursorGrabMode::None;
544 cursor_options.visible = true;
545 }
546}630fn handle_value_change_ssr_on(
631 event: On<ValueChange<Entity>>,
632 new_value_query: Query<&radio::RadioButtonOptionValue<SsrOn>>,
633 commands: Commands,
634 mut app_settings: ResMut<AppSettings>,
635 cameras: Query<Entity, With<Camera>>,
636) {
637 let Ok(radio::RadioButtonOptionValue(ssr_on)) = new_value_query.get(event.value) else {
638 return;
639 };
640 app_settings.ssr_on = *ssr_on;
641
642 update_views(commands, app_settings, cameras);
643}
644
645/// Update the camera views, particularly after `SsrOn` or any of the number inputs change
646fn update_views(
647 mut commands: Commands,
648 app_settings: ResMut<AppSettings>,
649 mut cameras: Query<Entity, With<Camera>>,
650) {
651 for camera in cameras.iter_mut() {
652 if app_settings.ssr_on.0 {
653 commands.entity(camera).insert(ScreenSpaceReflections {
654 min_perceptual_roughness: app_settings.min_perceptual_roughness.clone(),
655 max_perceptual_roughness: app_settings.max_perceptual_roughness.clone(),
656 edge_fadeout: app_settings.edge_fadeout.clone(),
657 ..default()
658 });
659 } else {
660 commands.entity(camera).remove::<ScreenSpaceReflections>();
661 }
662 }
663}
664
665/// Handles changes to the `DisplayedModel` radio group.
666fn handle_value_change_displayed_model(
667 event: On<ValueChange<Entity>>,
668 new_value_query: Query<&radio::RadioButtonOptionValue<DisplayedModel>>,
669 mut app_settings: ResMut<AppSettings>,
670 model_queries: ModelQueries,
671 mut visibilities: Query<&mut Visibility>,
672) {
673 let Ok(radio::RadioButtonOptionValue(displayed_model)) = new_value_query.get(event.value)
674 else {
675 return;
676 };
677 app_settings.displayed_model = *displayed_model;
678
679 for entity in model_queries.cube_models.iter() {
680 if let Ok(mut visibility) = visibilities.get_mut(entity) {
681 *visibility = if app_settings.displayed_model == DisplayedModel::Cube {
682 Visibility::Visible
683 } else {
684 Visibility::Hidden
685 };
686 }
687 }
688 for entity in model_queries.flight_helmet_models.iter() {
689 if let Ok(mut visibility) = visibilities.get_mut(entity) {
690 *visibility = if app_settings.displayed_model == DisplayedModel::FlightHelmet {
691 Visibility::Visible
692 } else {
693 Visibility::Hidden
694 };
695 }
696 }
697 for entity in model_queries.capsule_models.iter() {
698 if let Ok(mut visibility) = visibilities.get_mut(entity) {
699 *visibility = if app_settings.displayed_model == DisplayedModel::Capsules {
700 Visibility::Visible
701 } else {
702 Visibility::Hidden
703 };
704 }
705 }
706}
707
708/// Handles changes to the `DisplayedBase` radio group.
709fn handle_value_change_displayed_base(
710 event: On<ValueChange<Entity>>,
711 new_value_query: Query<&radio::RadioButtonOptionValue<DisplayedBase>>,
712 mut app_settings: ResMut<AppSettings>,
713 model_queries: ModelQueries,
714 mut visibilities: Query<&mut Visibility>,
715) {
716 let Ok(radio::RadioButtonOptionValue(displayed_base)) = new_value_query.get(event.value) else {
717 return;
718 };
719 app_settings.displayed_base = *displayed_base;
720
721 for entity in model_queries.metallic_base_models.iter() {
722 if let Ok(mut visibility) = visibilities.get_mut(entity) {
723 *visibility = if app_settings.displayed_base == DisplayedBase::Metallic {
724 Visibility::Visible
725 } else {
726 Visibility::Hidden
727 };
728 }
729 }
730 for entity in model_queries.non_metallic_base_models.iter() {
731 if let Ok(mut visibility) = visibilities.get_mut(entity) {
732 *visibility = if app_settings.displayed_base == DisplayedBase::RedPlane {
733 Visibility::Visible
734 } else {
735 Visibility::Hidden
736 };
737 }
738 }
739 for entity in model_queries.water_models.iter() {
740 if let Ok(mut visibility) = visibilities.get_mut(entity) {
741 *visibility = if app_settings.displayed_base == DisplayedBase::Water {
742 Visibility::Visible
743 } else {
744 Visibility::Hidden
745 };
746 }
747 }
748}
749
750/// Observer that handles changes to number inputs and updates state and the app accordingly.
751fn handle_value_change_number_input(
752 value_change: On<ValueChange<f32>>,
753 mut commands: Commands,
754 number_input_q: Query<&AppNumberInput, With<FeathersNumberInput>>,
755 mut app_settings: ResMut<AppSettings>,
756 cameras: Query<Entity, With<Camera>>,
757) {
758 if let Ok(app_number_input) = number_input_q.get(value_change.source) {
759 match app_number_input {
760 AppNumberInput::MinRoughnessStart => {
761 app_settings.min_perceptual_roughness.start = value_change.value;
762 }
763 AppNumberInput::MinRoughnessEnd => {
764 app_settings.min_perceptual_roughness.end = value_change.value;
765 }
766 AppNumberInput::MaxRoughnessStart => {
767 app_settings.max_perceptual_roughness.start = value_change.value;
768 }
769 AppNumberInput::MaxRoughnessEnd => {
770 app_settings.max_perceptual_roughness.end = value_change.value;
771 }
772 AppNumberInput::EdgeFadeoutStart => {
773 app_settings.edge_fadeout.start = value_change.value;
774 }
775 AppNumberInput::EdgeFadeoutEnd => {
776 app_settings.edge_fadeout.end = value_change.value;
777 }
778 }
779
780 commands
781 .entity(value_change.source)
782 .insert(NumberInputValue::F32(value_change.value));
783
784 update_views(commands, app_settings, cameras);
785 }
786}371fn handle_lighting_mode_change(
372 event: On<ValueChange<Entity>>,
373 new_value_q: Query<&RadioButtonOptionValue<LightingMode>>,
374 mut lighting_mode_changed_writer: MessageWriter<LightingModeChanged>,
375 mut app_status: ResMut<AppStatus>,
376) {
377 let Ok(RadioButtonOptionValue(new_lighting_mode)) = new_value_q.get(event.value) else {
378 return;
379 };
380
381 app_status.lighting_mode = *new_lighting_mode;
382 lighting_mode_changed_writer.write(LightingModeChanged);
383}- examples/3d/color_grading.rs
- examples/gizmos/transform_gizmo.rs
- examples/ui/navigation/directional_navigation.rs
- examples/showcase/mines.rs
- examples/animation/morph_targets.rs
- examples/3d/order_independent_transparency.rs
- examples/2d/2d_shapes.rs
- tests/3d/test_skinned_mesh_bounds.rs
- examples/usage/context_menu.rs
- examples/stress_tests/many_morph_targets.rs
- examples/showcase/game_menu.rs
- examples/3d/split_screen.rs
- examples/3d/clearcoat.rs
- examples/3d/pccm.rs
- examples/3d/occlusion_culling.rs
- examples/shader_advanced/deferred_raymarch.rs
- examples/ui/widgets/standard_widgets_observers.rs
- examples/ui/layout/display_and_visibility.rs
- examples/animation/animation_graph.rs
- examples/gltf/gltf_skinned_mesh.rs
- examples/3d/pcss.rs
- examples/2d/wireframe_2d.rs
- examples/ui/styling/box_shadow.rs
- examples/animation/animated_mesh_events.rs
- examples/gltf/gltf_extension_animation_graph.rs
- examples/ui/text/multiple_text_inputs.rs
- examples/3d/mirror.rs
- examples/ecs/relationships.rs
- examples/asset/asset_saving.rs
- examples/3d/clustered_decals.rs
- examples/animation/animation_masks.rs
- examples/picking/custom_hit_data.rs
- examples/3d/solari_reflections.rs
- examples/3d/specular_tint.rs
- examples/animation/animated_mesh.rs
- examples/ui/styling/gradients.rs
- examples/3d/visibility_range.rs
- examples/usage/character_creation.rs
- examples/3d/light_textures.rs
- examples/ui/widgets/standard_widgets.rs
- examples/ecs/observers.rs
- examples/ui/layout/ghost_nodes.rs
- examples/showcase/alien_cake_addict.rs
- examples/state/custom_transitions.rs
- examples/gltf/edit_material_on_gltf.rs
- examples/ui/navigation/directional_navigation_overrides.rs
- examples/3d/blend_modes.rs
- examples/ui/layout/size_constraints.rs
- examples/3d/solari.rs
- examples/camera/pan_orbit_camera_custom_input_plugin.rs
- examples/3d/contact_shadows.rs
- examples/shader_advanced/custom_render_phase.rs
- examples/ui/widgets/feathers_gallery.rs
- examples/ui/text/multiline_text_input.rs
Sourcepub fn get_many<const N: usize>(
&self,
entities: [Entity; N],
) -> Result<[<<D as QueryData>::ReadOnly as QueryData>::Item<'_, 's>; N], QueryEntityError>
pub fn get_many<const N: usize>( &self, entities: [Entity; N], ) -> Result<[<<D as QueryData>::ReadOnly as QueryData>::Item<'_, 's>; N], QueryEntityError>
Returns the read-only query items for the given array of Entity.
The returned query items are in the same order as the input.
In case of a nonexisting entity or mismatched component, a QueryEntityError is returned instead.
The elements of the array do not need to be unique, unlike get_many_mut.
§Examples
use bevy_ecs::prelude::*;
use bevy_ecs::query::QueryEntityError;
#[derive(Component, PartialEq, Debug)]
struct A(usize);
let mut world = World::new();
let entity_vec: Vec<Entity> = (0..3).map(|i| world.spawn(A(i)).id()).collect();
let entities: [Entity; 3] = entity_vec.try_into().unwrap();
world.spawn(A(73));
let mut query_state = world.query::<&A>();
let query = query_state.query(&world);
let component_values = query.get_many(entities).unwrap();
assert_eq!(component_values, [&A(0), &A(1), &A(2)]);
let wrong_entity = Entity::from_raw_u32(365).unwrap();
assert_eq!(
match query.get_many([wrong_entity]).unwrap_err() {
QueryEntityError::NotSpawned(error) => error.entity(),
_ => panic!(),
},
wrong_entity
);§See also
get_many_mutto get mutable query items.get_many_uniqueto only handle unique inputs.
Sourcepub fn get_many_unique<const N: usize>(
&self,
entities: UniqueEntityEquivalentArray<Entity, N>,
) -> Result<[<<D as QueryData>::ReadOnly as QueryData>::Item<'_, 's>; N], QueryEntityError>
pub fn get_many_unique<const N: usize>( &self, entities: UniqueEntityEquivalentArray<Entity, N>, ) -> Result<[<<D as QueryData>::ReadOnly as QueryData>::Item<'_, 's>; N], QueryEntityError>
Returns the read-only query items for the given UniqueEntityArray.
The returned query items are in the same order as the input.
In case of a nonexisting entity or mismatched component, a QueryEntityError is returned instead.
§Examples
use bevy_ecs::{prelude::*, query::QueryEntityError, entity::{EntitySetIterator, UniqueEntityArray, UniqueEntityVec}};
#[derive(Component, PartialEq, Debug)]
struct A(usize);
let mut world = World::new();
let entity_set: UniqueEntityVec = world.spawn_batch((0..3).map(A)).collect_set();
let entity_set: UniqueEntityArray<3> = entity_set.try_into().unwrap();
world.spawn(A(73));
let mut query_state = world.query::<&A>();
let query = query_state.query(&world);
let component_values = query.get_many_unique(entity_set).unwrap();
assert_eq!(component_values, [&A(0), &A(1), &A(2)]);
let wrong_entity = Entity::from_raw_u32(365).unwrap();
assert_eq!(
match query.get_many_unique(UniqueEntityArray::from([wrong_entity])).unwrap_err() {
QueryEntityError::NotSpawned(error) => error.entity(),
_ => panic!(),
},
wrong_entity
);§See also
get_many_unique_mutto get mutable query items.get_manyto handle inputs with duplicates.
Sourcepub fn get_mut(
&mut self,
entity: Entity,
) -> Result<<D as QueryData>::Item<'_, 's>, QueryEntityError>
pub fn get_mut( &mut self, entity: Entity, ) -> Result<<D as QueryData>::Item<'_, 's>, QueryEntityError>
Returns the query item for the given Entity.
In case of a nonexisting entity or mismatched component, a QueryEntityError is returned instead.
This is always guaranteed to run in O(1) time.
§Example
Here, get_mut is used to retrieve the exact query item of the entity specified by the PoisonedCharacter resource.
fn poison_system(mut query: Query<&mut Health>, poisoned: Res<PoisonedCharacter>) {
if let Ok(mut health) = query.get_mut(poisoned.character_id) {
health.0 -= 1;
}
}§See also
getto get a read-only query item.
Examples found in repository?
259fn on_enter_selectable(
260 event: On<PointerEnter>,
261 mut border: Query<&mut BorderColor, (With<SelectableColor>, Without<Selected>)>,
262) {
263 let Ok(mut border) = border.get_mut(event.entity) else {
264 return;
265 };
266
267 *border = BorderColor::all(HIGHLIGHT_COLOR);
268}
269
270fn on_leave_selectable(
271 event: On<PointerLeave>,
272 mut border: Query<&mut BorderColor, (With<SelectableColor>, Without<Selected>)>,
273) {
274 let Ok(mut border) = border.get_mut(event.entity) else {
275 return;
276 };
277
278 *border = BorderColor::all(NORMAL_COLOR);
279}
280
281fn on_press_selectable(
282 event: On<PointerPress>,
283 mut borders: Query<(Entity, &mut BorderColor, &BackgroundColor), With<SelectableColor>>,
284 mut draw_color: ResMut<DrawColor>,
285 mut commands: Commands,
286) {
287 if !borders.contains(event.entity) {
288 return;
289 }
290 for (entity, mut border, _) in borders.iter_mut() {
291 commands.entity(entity).remove::<Selected>();
292 *border = BorderColor::all(NORMAL_COLOR);
293 }
294 let (_, mut border, background_color) = borders.get_mut(event.entity).unwrap();
295 *border = BorderColor::all(SELECTED_COLOR);
296 commands.entity(event.entity).insert(Selected);
297
298 draw_color.0 = background_color.0;
299}More examples
444fn on_button_over(
445 over: On<PointerOver>,
446 mut buttons: Query<(&mut BorderColor, &mut BackgroundColor), With<ButtonAction>>,
447) {
448 if let Ok((mut border, mut background)) = buttons.get_mut(over.event_target()) {
449 border.set_all(HOVERED_TILE_BORDER_COLOR);
450 background.0 = BACKGROUND_COLOR;
451 }
452}
453
454fn on_button_out(
455 out: On<PointerOut>,
456 mut buttons: Query<(&mut BorderColor, &mut BackgroundColor), With<ButtonAction>>,
457) {
458 if let Ok((mut border, mut background)) = buttons.get_mut(out.event_target()) {
459 border.set_all(TILE_BORDER_COLOR);
460 background.0 = BACKGROUND_COLOR;
461 }
462}
463
464fn on_tile_over(over: On<PointerOver>, mut tiles: Query<&mut BorderColor, With<TileCell>>) {
465 if let Ok(mut border) = tiles.get_mut(over.event_target()) {
466 border.set_all(HOVERED_TILE_BORDER_COLOR);
467 }
468}
469
470fn on_tile_out(out: On<PointerOut>, mut tiles: Query<&mut BorderColor, With<TileCell>>) {
471 if let Ok(mut border) = tiles.get_mut(out.event_target()) {
472 border.set_all(TILE_BORDER_COLOR);
473 }
474}586fn on_thumb_drag_start(
587 mut on: On<PointerDragStart>,
588 mut thumb_query: Query<&mut InputScrollDragState, With<InputScrollThumb>>,
589 input: Single<&EditableText, With<MultilineInput>>,
590) {
591 on.propagate(false);
592 let Ok(mut drag) = thumb_query.get_mut(on.entity) else {
593 return;
594 };
595 drag.dragging = true;
596 drag.drag_origin = input.viewport.offset.y;
597}
598
599fn on_thumb_drag(
600 mut on: On<PointerDrag>,
601 thumb_query: Query<(&InputScrollDragState, &ChildOf), With<InputScrollThumb>>,
602 track_query: Query<&ComputedNode>,
603 mut input: Single<(&mut EditableText, &TextLayoutInfo), With<MultilineInput>>,
604) {
605 on.propagate(false);
606 let Ok((drag, ChildOf(track))) = thumb_query.get(on.entity) else {
607 return;
608 };
609 if !drag.dragging {
610 return;
611 }
612 let Ok(track_node) = track_query.get(*track) else {
613 return;
614 };
615 let track_height = track_node.size.y * track_node.inverse_scale_factor;
616 if track_height <= 0. {
617 return;
618 }
619
620 let content_height = input.1.size.y;
621 let max_offset = (content_height - input.0.viewport.size.y).max(0.);
622 let delta = on.distance.y / track_height * content_height;
623 input.0.viewport.offset.y = (drag.drag_origin + delta).clamp(0., max_offset);
624}
625
626fn on_thumb_drag_end(
627 mut on: On<PointerDragEnd>,
628 mut thumb_query: Query<&mut InputScrollDragState, With<InputScrollThumb>>,
629) {
630 on.propagate(false);
631 let Ok(mut drag) = thumb_query.get_mut(on.entity) else {
632 return;
633 };
634 drag.dragging = false;
635}79fn on_drag_viewport(drag: On<PointerDrag>, mut node_query: Query<&mut Node>) {
80 if matches!(drag.button, PointerButton::Secondary) {
81 let mut node = node_query.get_mut(drag.entity).unwrap();
82
83 if let (Val::Px(top), Val::Px(left)) = (node.top, node.left) {
84 node.left = px(left + drag.delta.x);
85 node.top = px(top + drag.delta.y);
86 };
87 }
88}
89
90fn on_drag_cuboid(drag: On<PointerDrag>, mut transform_query: Query<&mut Transform>) {
91 if matches!(drag.button, PointerButton::Primary) {
92 let mut transform = transform_query.get_mut(drag.entity).unwrap();
93 transform.rotate_y(drag.delta.x * 0.02);
94 transform.rotate_x(drag.delta.y * 0.02);
95 }
96}- examples/asset/asset_saving_with_subassets.rs
- examples/ui/text/text_input.rs
- examples/ecs/observer_propagation.rs
- examples/ui/text/ime_support.rs
- examples/picking/mesh_picking.rs
- examples/ui/images/ui_texture_slice.rs
- examples/ui/navigation/directional_navigation.rs
- examples/ui/navigation/directional_navigation_overrides.rs
- examples/gltf/update_gltf_scene.rs
- examples/animation/morph_targets.rs
- examples/usage/debug_frustum_culling.rs
- examples/ui/images/ui_texture_atlas_slice.rs
- tests/3d/test_skinned_mesh_bounds.rs
- examples/showcase/game_menu.rs
- examples/usage/context_menu.rs
- examples/usage/cooldown.rs
- examples/stress_tests/many_foxes.rs
- examples/3d/split_screen.rs
- examples/testbed/3d.rs
- examples/stress_tests/many_morph_targets.rs
- examples/ui/widgets/standard_widgets.rs
- examples/gltf/gltf_extension_animation_graph.rs
- examples/3d/solari_reflections.rs
- examples/ui/styling/gradients.rs
- examples/ui/layout/display_and_visibility.rs
- examples/ui/layout/fixed_node.rs
- examples/ui/text/multiple_text_inputs.rs
- examples/gltf/gltf_skinned_mesh.rs
- examples/3d/motion_blur.rs
- examples/picking/draggable_slider.rs
- examples/showcase/contributors.rs
- examples/ui/widgets/button.rs
- examples/ecs/hierarchy.rs
- examples/3d/mixed_lighting.rs
- examples/ui/widgets/vertical_slider.rs
- examples/testbed/full_ui.rs
- examples/ui/scroll_and_overflow/scroll.rs
- examples/picking/simple_picking.rs
- examples/3d/ssr.rs
- examples/animation/animated_mesh.rs
- examples/picking/debug_picking.rs
- examples/ui/layout/ghost_nodes.rs
- examples/showcase/alien_cake_addict.rs
- examples/animation/easing_functions.rs
- examples/ui/widgets/standard_widgets_observers.rs
- examples/ui/text/text_background_colors.rs
- examples/ui/text/system_fonts.rs
- examples/ui/ui_target_camera.rs
- examples/ui/render_ui_to_texture.rs
- examples/ui/scroll_and_overflow/drag_to_scroll.rs
- examples/camera/pan_orbit_camera_custom_input_plugin.rs
- examples/ui/ui_drag_and_drop.rs
Sourcepub fn get_inner(
self,
entity: Entity,
) -> Result<<D as QueryData>::Item<'w, 's>, QueryEntityError>
pub fn get_inner( self, entity: Entity, ) -> Result<<D as QueryData>::Item<'w, 's>, QueryEntityError>
Returns the query item for the given Entity.
This consumes the Query to return results with the actual “inner” world lifetime.
In case of a nonexisting entity or mismatched component, a QueryEntityError is returned instead.
This is always guaranteed to run in O(1) time.
§See also
Sourcepub fn get_many_mut<const N: usize>(
&mut self,
entities: [Entity; N],
) -> Result<[<D as QueryData>::Item<'_, 's>; N], QueryEntityError>where
D: IterQueryData,
pub fn get_many_mut<const N: usize>(
&mut self,
entities: [Entity; N],
) -> Result<[<D as QueryData>::Item<'_, 's>; N], QueryEntityError>where
D: IterQueryData,
Returns the query items for the given array of Entity.
The returned query items are in the same order as the input.
In case of a nonexisting entity, duplicate entities or mismatched component, a QueryEntityError is returned instead.
§Examples
use bevy_ecs::prelude::*;
use bevy_ecs::query::QueryEntityError;
#[derive(Component, PartialEq, Debug)]
struct A(usize);
let mut world = World::new();
let entities: Vec<Entity> = (0..3).map(|i| world.spawn(A(i)).id()).collect();
let entities: [Entity; 3] = entities.try_into().unwrap();
world.spawn(A(73));
let wrong_entity = Entity::from_raw_u32(57).unwrap();
let invalid_entity = world.spawn_empty().id();
let mut query_state = world.query::<&mut A>();
let mut query = query_state.query_mut(&mut world);
let mut mutable_component_values = query.get_many_mut(entities).unwrap();
for mut a in &mut mutable_component_values {
a.0 += 5;
}
let component_values = query.get_many(entities).unwrap();
assert_eq!(component_values, [&A(5), &A(6), &A(7)]);
assert_eq!(
match query
.get_many_mut([wrong_entity])
.unwrap_err()
{
QueryEntityError::NotSpawned(error) => error.entity(),
_ => panic!(),
},
wrong_entity
);
assert_eq!(
match query
.get_many_mut([invalid_entity])
.unwrap_err()
{
QueryEntityError::QueryDoesNotMatch(entity, _) => entity,
_ => panic!(),
},
invalid_entity
);
assert_eq!(
query
.get_many_mut([entities[0], entities[0]])
.unwrap_err(),
QueryEntityError::AliasedMutability(entities[0])
);§See also
get_manyto get read-only query items without checking for duplicate entities.
Examples found in repository?
16fn setup(mut commands: Commands) {
17 commands.spawn(Camera2d);
18 commands
19 .spawn((Node {
20 display: Display::Grid,
21 align_self: AlignSelf::Center,
22 justify_self: JustifySelf::Center,
23 ..Default::default()
24 }, Pickable::IGNORE, BackgroundColor(Color::srgb(0.4, 0.4, 0.4))))
25 .with_children(|parent| {
26 let tile_colors = [
27 Color::srgb(0.2, 0.2, 0.8),
28 Color::srgb(0.8, 0.2, 0.2)
29 ];
30 for column in 0..COLUMNS {
31 for row in 0..ROWS {
32 let i = column + row * COLUMNS;
33 let tile_color = tile_colors[((row % 2) + column) as usize % tile_colors.len()];
34 let tile_border_color = tile_color.darker(0.025);
35 parent
36 .spawn((
37 Node {
38 width: px(TILE_SIZE),
39 height: px(TILE_SIZE),
40 border: px(4.).all(),
41 grid_row: GridPlacement::start(row + 1),
42 grid_column: GridPlacement::start(column + 1),
43 align_items: AlignItems::Center,
44 justify_content: JustifyContent::Center,
45 ..Default::default()
46 },
47 BorderColor::all(tile_border_color),
48 BackgroundColor(tile_color),
49 Outline {
50 width: px(2.),
51 offset: Val::ZERO,
52 color: Color::NONE,
53 },
54 Pickable {
55 should_block_lower: false,
56 is_hoverable: true,
57 },
58 GlobalZIndex::default()
59 ))
60 .observe(move |on_over: On<PointerOver>, mut query: Query<(&mut BackgroundColor, &mut BorderColor)>| {
61 if let Ok((mut background_color, mut border_color)) = query.get_mut(on_over.event_target()) {
62 background_color.0 = tile_color.lighter(0.1);
63 border_color.set_all(tile_border_color.lighter(0.1));
64 }
65 })
66 .observe(move |on_out: On<PointerOut>, mut query: Query<(&mut BackgroundColor, &mut BorderColor)>| {
67 if let Ok((mut background_color, mut border_color)) = query.get_mut(on_out.event_target()) {
68 background_color.0 = tile_color;
69 border_color.set_all(tile_border_color);
70 }
71 })
72 .observe(|on_drag_start: On<PointerDragStart>, mut query: Query<(&mut Outline, &mut GlobalZIndex)>| {
73 if let Ok((mut outline, mut global_zindex, )) = query.get_mut(on_drag_start.event_target()) {
74 outline.color = Color::WHITE;
75 global_zindex.0 = 1;
76 }
77 })
78 .observe(|on_drag: On<PointerDrag>, mut query: Query<&mut UiTransform>| {
79 if let Ok(mut transform) = query.get_mut(on_drag.event_target()) {
80 transform.translation = Val2::px(on_drag.distance.x, on_drag.distance.y);
81 }
82 })
83 .observe(move |on_drag_end: On<PointerDragEnd>, mut query: Query<(&mut UiTransform, &mut Outline, &mut GlobalZIndex)>| {
84 if let Ok((mut transform, mut outline, mut global_zindex)) = query.get_mut(on_drag_end.event_target()) {
85 transform.translation = Val2::ZERO;
86 outline.color = Color::NONE;
87 global_zindex.0 = 0;
88 }
89 })
90 .observe(|on_drag_drop: On<PointerDragDrop>, mut query: Query<&mut Node>| {
91 if let Ok([mut a, mut b]) = query.get_many_mut([on_drag_drop.event_target(), on_drag_drop.dropped]) {
92 core::mem::swap(&mut a.grid_row, &mut b.grid_row);
93 core::mem::swap(&mut a.grid_column, &mut b.grid_column);
94 }
95 })
96 .with_child((Text::new(format!("{i}")), Pickable::IGNORE));
97 }
98 }
99 });
100}Sourcepub fn get_many_unique_mut<const N: usize>(
&mut self,
entities: UniqueEntityEquivalentArray<Entity, N>,
) -> Result<[<D as QueryData>::Item<'_, 's>; N], QueryEntityError>where
D: IterQueryData,
pub fn get_many_unique_mut<const N: usize>(
&mut self,
entities: UniqueEntityEquivalentArray<Entity, N>,
) -> Result<[<D as QueryData>::Item<'_, 's>; N], QueryEntityError>where
D: IterQueryData,
Returns the query items for the given UniqueEntityArray.
The returned query items are in the same order as the input.
In case of a nonexisting entity or mismatched component, a QueryEntityError is returned instead.
§Examples
use bevy_ecs::{prelude::*, query::QueryEntityError, entity::{EntitySetIterator, UniqueEntityArray, UniqueEntityVec}};
#[derive(Component, PartialEq, Debug)]
struct A(usize);
let mut world = World::new();
let entity_set: UniqueEntityVec = world.spawn_batch((0..3).map(A)).collect_set();
let entity_set: UniqueEntityArray<3> = entity_set.try_into().unwrap();
world.spawn(A(73));
let wrong_entity = Entity::from_raw_u32(57).unwrap();
let invalid_entity = world.spawn_empty().id();
let mut query_state = world.query::<&mut A>();
let mut query = query_state.query_mut(&mut world);
let mut mutable_component_values = query.get_many_unique_mut(entity_set).unwrap();
for mut a in &mut mutable_component_values {
a.0 += 5;
}
let component_values = query.get_many_unique(entity_set).unwrap();
assert_eq!(component_values, [&A(5), &A(6), &A(7)]);
assert_eq!(
match query
.get_many_unique_mut(UniqueEntityArray::from([wrong_entity]))
.unwrap_err()
{
QueryEntityError::NotSpawned(error) => error.entity(),
_ => panic!(),
},
wrong_entity
);
assert_eq!(
match query
.get_many_unique_mut(UniqueEntityArray::from([invalid_entity]))
.unwrap_err()
{
QueryEntityError::QueryDoesNotMatch(entity, _) => entity,
_ => panic!(),
},
invalid_entity
);§See also
get_many_uniqueto get read-only query items.
Sourcepub fn get_many_mut_inner<const N: usize>(
self,
entities: [Entity; N],
) -> Result<[<D as QueryData>::Item<'w, 's>; N], QueryEntityError>where
D: IterQueryData,
pub fn get_many_mut_inner<const N: usize>(
self,
entities: [Entity; N],
) -> Result<[<D as QueryData>::Item<'w, 's>; N], QueryEntityError>where
D: IterQueryData,
Returns the query items for the given array of Entity.
This consumes the Query to return results with the actual “inner” world lifetime.
The returned query items are in the same order as the input.
In case of a nonexisting entity, duplicate entities or mismatched component, a QueryEntityError is returned instead.
§See also
get_manyto get read-only query items without checking for duplicate entities.get_many_mutto get items using a mutable reference.get_many_innerto get read-only query items with the actual “inner” world lifetime.
Sourcepub fn get_many_inner<const N: usize>(
self,
entities: [Entity; N],
) -> Result<[<D as QueryData>::Item<'w, 's>; N], QueryEntityError>where
D: ReadOnlyQueryData,
pub fn get_many_inner<const N: usize>(
self,
entities: [Entity; N],
) -> Result<[<D as QueryData>::Item<'w, 's>; N], QueryEntityError>where
D: ReadOnlyQueryData,
Returns the query items for the given array of Entity.
This consumes the Query to return results with the actual “inner” world lifetime.
The returned query items are in the same order as the input.
In case of a nonexisting entity or mismatched component, a QueryEntityError is returned instead.
§See also
get_manyto get read-only query items without checking for duplicate entities.get_many_mutto get items using a mutable reference.get_many_mut_innerto get mutable query items with the actual “inner” world lifetime.
Sourcepub fn get_many_unique_inner<const N: usize>(
self,
entities: UniqueEntityEquivalentArray<Entity, N>,
) -> Result<[<D as QueryData>::Item<'w, 's>; N], QueryEntityError>where
D: IterQueryData,
pub fn get_many_unique_inner<const N: usize>(
self,
entities: UniqueEntityEquivalentArray<Entity, N>,
) -> Result<[<D as QueryData>::Item<'w, 's>; N], QueryEntityError>where
D: IterQueryData,
Returns the query items for the given UniqueEntityArray.
This consumes the Query to return results with the actual “inner” world lifetime.
The returned query items are in the same order as the input.
In case of a nonexisting entity, duplicate entities or mismatched component, a QueryEntityError is returned instead.
§See also
get_many_uniqueto get read-only query items without checking for duplicate entities.get_many_unique_mutto get items using a mutable reference.
Sourcepub unsafe fn get_unchecked(
&self,
entity: Entity,
) -> Result<<D as QueryData>::Item<'_, 's>, QueryEntityError>
pub unsafe fn get_unchecked( &self, entity: Entity, ) -> Result<<D as QueryData>::Item<'_, 's>, QueryEntityError>
Returns the query item for the given Entity.
In case of a nonexisting entity or mismatched component, a QueryEntityError is returned instead.
This is always guaranteed to run in O(1) time.
§Safety
This function makes it possible to violate Rust’s aliasing guarantees. You must make sure this call does not result in multiple mutable references to the same component.
§See also
get_mutfor the safe version.
Sourcepub fn single(
&self,
) -> Result<<<D as QueryData>::ReadOnly as QueryData>::Item<'_, 's>, QuerySingleError>
pub fn single( &self, ) -> Result<<<D as QueryData>::ReadOnly as QueryData>::Item<'_, 's>, QuerySingleError>
Returns a single read-only query item when there is exactly one entity matching the query.
If the number of query items is not exactly one, a QuerySingleError is returned instead.
§Example
fn player_scoring_system(query: Query<&PlayerScore>) {
match query.single() {
Ok(PlayerScore(score)) => {
println!("Score: {}", score);
}
Err(QuerySingleError::NoEntities(_)) => {
println!("Error: There is no player!");
}
Err(QuerySingleError::MultipleEntities(_)) => {
println!("Error: There is more than one player!");
}
}
}§See also
single_mutto get the mutable query item.
Examples found in repository?
61fn update_speed(music_controller: Query<&AudioSink, With<MyMusic>>, time: Res<Time>) {
62 let Ok(sink) = music_controller.single() else {
63 return;
64 };
65 if sink.is_paused() {
66 return;
67 }
68
69 sink.set_speed((ops::sin(time.elapsed_secs() / 5.0) + 1.0).max(0.1));
70}
71
72fn pause(
73 keyboard_input: Res<ButtonInput<KeyCode>>,
74 music_controller: Query<&AudioSink, With<MyMusic>>,
75) {
76 let Ok(sink) = music_controller.single() else {
77 return;
78 };
79
80 if keyboard_input.just_pressed(KeyCode::Space) {
81 sink.toggle_playback();
82 }
83}More examples
83fn cycle_text_background_colors(
84 time: Res<Time>,
85 children_query: Query<&Children, With<Text>>,
86 mut text_background_colors_query: Query<&mut TextBackgroundColor>,
87) {
88 let n = time.elapsed_secs() as usize;
89 let children = children_query.single().unwrap();
90
91 for (i, child) in children.iter().enumerate() {
92 text_background_colors_query.get_mut(child).unwrap().0 = PALETTE[(i + n) % PALETTE.len()];
93 }
94}476fn draw_gizmos(mut gizmos: Gizmos, spotlight: Query<(&GlobalTransform, &SpotLight, &Visibility)>) {
477 if let Ok((global_transform, spotlight, visibility)) = spotlight.single()
478 && visibility != Visibility::Hidden
479 {
480 gizmos.primitive_3d(
481 &Cone::new(7.0 * spotlight.outer_angle, 7.0),
482 Isometry3d {
483 rotation: global_transform.rotation() * Quat::from_rotation_x(FRAC_PI_2),
484 translation: global_transform.translation_vec3a() * 0.5,
485 },
486 YELLOW,
487 );
488 }
489}104fn toggle_projection(
105 keys: Res<ButtonInput<KeyCode>>,
106 mut dolly: MessageWriter<DollyZoomTrigger>,
107 cam: Query<Entity, With<PanOrbitCamera>>,
108 mut toggled: Local<bool>,
109) {
110 if keys.just_pressed(KeyCode::KeyP) {
111 *toggled = !*toggled;
112 let target_projection = if *toggled {
113 Projection::Orthographic(OrthographicProjection::default_3d())
114 } else {
115 Projection::Perspective(PerspectiveProjection::default())
116 };
117 dolly.write(DollyZoomTrigger {
118 target_projection,
119 camera: cam.single().unwrap(),
120 });
121 }
122}
123
124#[derive(Component)]
125struct ZoomStatusIndicator;
126
127fn zoom_status(zoom_through: bool) -> String {
128 format!("Zoom Through: {zoom_through}")
129}
130
131fn toggle_zoom(
132 keys: Res<ButtonInput<KeyCode>>,
133 mut cam: Query<&mut PanOrbitCamera>,
134 mut text: Query<&mut Text, With<ZoomStatusIndicator>>,
135) {
136 if keys.just_pressed(KeyCode::KeyZ) {
137 let mut editor = cam.single_mut().unwrap();
138 editor.zoom_limits.zoom_through_objects = !editor.zoom_limits.zoom_through_objects;
139 text.single_mut().unwrap().0 = zoom_status(editor.zoom_limits.zoom_through_objects);
140 }
141}
142
143fn toggle_constraint(
144 keys: Res<ButtonInput<KeyCode>>,
145 mut cam: Query<(Entity, &Transform, &mut PanOrbitCamera)>,
146 mut look_to: MessageWriter<LookToTrigger>,
147) {
148 if keys.just_pressed(KeyCode::KeyC) {
149 let (entity, transform, mut editor) = cam.single_mut().unwrap();
150 match editor.orbit_constraint {
151 OrbitConstraint::Fixed { .. } => editor.orbit_constraint = OrbitConstraint::Free,
152 OrbitConstraint::Free => {
153 editor.orbit_constraint = OrbitConstraint::Fixed {
154 up: DVec3::Y,
155 can_pass_tdc: false,
156 };
157
158 look_to.write(LookToTrigger::auto_snap_up_direction(
159 transform.forward().as_dvec3(),
160 entity,
161 &transform.rotation.as_dquat(),
162 editor.as_ref(),
163 ));
164 }
165 };
166 }
167}
168
169fn switch_direction(
170 keys: Res<ButtonInput<KeyCode>>,
171 mut look_to: MessageWriter<LookToTrigger>,
172 cam: Query<(Entity, &Transform, &PanOrbitCamera)>,
173) {
174 let (camera, transform, editor) = cam.single().unwrap();
175 if keys.just_pressed(KeyCode::Digit1) {
176 look_to.write(LookToTrigger::auto_snap_up_direction(
177 DVec3::X,
178 camera,
179 &transform.rotation.as_dquat(),
180 editor,
181 ));
182 }
183 if keys.just_pressed(KeyCode::Digit2) {
184 look_to.write(LookToTrigger::auto_snap_up_direction(
185 DVec3::Z,
186 camera,
187 &transform.rotation.as_dquat(),
188 editor,
189 ));
190 }
191 if keys.just_pressed(KeyCode::Digit3) {
192 look_to.write(LookToTrigger::auto_snap_up_direction(
193 DVec3::NEG_X,
194 camera,
195 &transform.rotation.as_dquat(),
196 editor,
197 ));
198 }
199 if keys.just_pressed(KeyCode::Digit4) {
200 look_to.write(LookToTrigger::auto_snap_up_direction(
201 DVec3::NEG_Z,
202 camera,
203 &transform.rotation.as_dquat(),
204 editor,
205 ));
206 }
207 if keys.just_pressed(KeyCode::Digit5) {
208 look_to.write(LookToTrigger::auto_snap_up_direction(
209 DVec3::Y,
210 camera,
211 &transform.rotation.as_dquat(),
212 editor,
213 ));
214 }
215 if keys.just_pressed(KeyCode::Digit6) {
216 look_to.write(LookToTrigger::auto_snap_up_direction(
217 DVec3::NEG_Y,
218 camera,
219 &transform.rotation.as_dquat(),
220 editor,
221 ));
222 }
223}190fn handle_click(
191 mouse_button_input: Res<ButtonInput<MouseButton>>,
192 camera: Single<(&Camera, &GlobalTransform)>,
193 windows: Query<&Window>,
194 mut commands: Commands,
195) {
196 let Ok(windows) = windows.single() else {
197 return;
198 };
199
200 let (camera, camera_transform) = *camera;
201 if let Some(pos) = windows
202 .cursor_position()
203 .and_then(|cursor| camera.viewport_to_world(camera_transform, cursor).ok())
204 .map(|ray| ray.origin.truncate())
205 && mouse_button_input.just_pressed(MouseButton::Left)
206 {
207 commands.trigger(ExplodeMines { pos, radius: 1.0 });
208 }
209}- examples/window/persisting_window_settings.rs
- examples/3d/tonemapping.rs
- examples/window/window_drag_move.rs
- examples/ecs/delayed_commands.rs
- examples/ecs/parallel_query.rs
- examples/3d/generate_custom_mesh.rs
- examples/camera/free_camera_controller.rs
- examples/ui/images/image_node_resizing.rs
- examples/stress_tests/bevymark.rs
- examples/3d/solari.rs
- examples/showcase/contributors.rs
- examples/stress_tests/many_cameras_lights.rs
- examples/ui/render_ui_to_texture.rs
- examples/usage/debug_frustum_culling.rs
- examples/ui/widgets/feathers_gallery.rs
Sourcepub fn single_mut(
&mut self,
) -> Result<<D as QueryData>::Item<'_, 's>, QuerySingleError>where
D: IterQueryData,
pub fn single_mut(
&mut self,
) -> Result<<D as QueryData>::Item<'_, 's>, QuerySingleError>where
D: IterQueryData,
Returns a single query item when there is exactly one entity matching the query.
If the number of query items is not exactly one, a QuerySingleError is returned instead.
§Example
fn regenerate_player_health_system(mut query: Query<&mut Health, With<Player>>) {
let mut health = query.single_mut().expect("Error: Could not find a single player.");
health.0 += 1;
}§See also
singleto get the read-only query item.
Examples found in repository?
More examples
85fn mute(
86 keyboard_input: Res<ButtonInput<KeyCode>>,
87 mut music_controller: Query<&mut AudioSink, With<MyMusic>>,
88) {
89 let Ok(mut sink) = music_controller.single_mut() else {
90 return;
91 };
92
93 if keyboard_input.just_pressed(KeyCode::KeyM) {
94 sink.toggle_mute();
95 }
96}
97
98fn volume(
99 keyboard_input: Res<ButtonInput<KeyCode>>,
100 mut music_controller: Query<&mut AudioSink, With<MyMusic>>,
101) {
102 let Ok(mut sink) = music_controller.single_mut() else {
103 return;
104 };
105
106 if keyboard_input.just_pressed(KeyCode::Equal) {
107 let current_volume = sink.volume();
108 sink.set_volume(current_volume.increase_by_percentage(10.0));
109 } else if keyboard_input.just_pressed(KeyCode::Minus) {
110 let current_volume = sink.volume();
111 sink.set_volume(current_volume.increase_by_percentage(-10.0));
112 }
113}131fn toggle_zoom(
132 keys: Res<ButtonInput<KeyCode>>,
133 mut cam: Query<&mut PanOrbitCamera>,
134 mut text: Query<&mut Text, With<ZoomStatusIndicator>>,
135) {
136 if keys.just_pressed(KeyCode::KeyZ) {
137 let mut editor = cam.single_mut().unwrap();
138 editor.zoom_limits.zoom_through_objects = !editor.zoom_limits.zoom_through_objects;
139 text.single_mut().unwrap().0 = zoom_status(editor.zoom_limits.zoom_through_objects);
140 }
141}
142
143fn toggle_constraint(
144 keys: Res<ButtonInput<KeyCode>>,
145 mut cam: Query<(Entity, &Transform, &mut PanOrbitCamera)>,
146 mut look_to: MessageWriter<LookToTrigger>,
147) {
148 if keys.just_pressed(KeyCode::KeyC) {
149 let (entity, transform, mut editor) = cam.single_mut().unwrap();
150 match editor.orbit_constraint {
151 OrbitConstraint::Fixed { .. } => editor.orbit_constraint = OrbitConstraint::Free,
152 OrbitConstraint::Free => {
153 editor.orbit_constraint = OrbitConstraint::Fixed {
154 up: DVec3::Y,
155 can_pass_tdc: false,
156 };
157
158 look_to.write(LookToTrigger::auto_snap_up_direction(
159 transform.forward().as_dvec3(),
160 entity,
161 &transform.rotation.as_dquat(),
162 editor.as_ref(),
163 ));
164 }
165 };
166 }
167}253fn get_async_loading_state(
254 state: Res<AsyncLoadingState>,
255 mut next_loading_state: ResMut<NextState<LoadingState>>,
256 mut text: Query<&mut Text, With<LoadingText>>,
257) {
258 // Load the value written by the `Future`.
259 let is_loaded = state.0.load(Ordering::Acquire);
260
261 // If loaded, change the state.
262 if is_loaded {
263 next_loading_state.set(LoadingState::Loaded);
264 if let Ok(mut text) = text.single_mut() {
265 "Loaded!".clone_into(&mut **text);
266 }
267 }
268}- examples/ui/navigation/directional_navigation.rs
- examples/ui/navigation/directional_navigation_overrides.rs
- examples/usage/cooldown.rs
- examples/ecs/entity_disabling.rs
- examples/3d/rect_light.rs
- examples/ui/widgets/virtual_keyboard.rs
- examples/camera/free_camera_controller.rs
- examples/usage/debug_frustum_culling.rs
- examples/3d/light_textures.rs
- examples/ui/scroll_and_overflow/drag_to_scroll.rs
- examples/3d/contact_shadows.rs
- examples/ui/text/multiline_text_input.rs
Sourcepub fn single_inner(
self,
) -> Result<<D as QueryData>::Item<'w, 's>, QuerySingleError>where
D: IterQueryData,
pub fn single_inner(
self,
) -> Result<<D as QueryData>::Item<'w, 's>, QuerySingleError>where
D: IterQueryData,
Returns a single query item when there is exactly one entity matching the query.
This consumes the Query to return results with the actual “inner” world lifetime.
If the number of query items is not exactly one, a QuerySingleError is returned instead.
§Example
fn regenerate_player_health_system(query: Query<&mut Health, With<Player>>) {
let mut health = query.single_inner().expect("Error: Could not find a single player.");
health.0 += 1;
}§See also
singleto get the read-only query item.single_mutto get the mutable query item.
Examples found in repository?
245fn on_changed_editable_text(
246 name_input_q: Query<&EditableText, With<NameInput>>,
247 mut character: ResMut<Character>,
248) {
249 let Ok(editable_text) = name_input_q.single_inner() else {
250 return;
251 };
252 let new_name = editable_text.value().to_string();
253 if character.name != new_name {
254 character.name = new_name;
255 character.changed_fields.push(ChangedField::Name);
256 }
257
258 // We do not need to update the ui widget view in our app because `EditableText`
259 // manages its own state internally; it updates the text the user sees automatically.
260
261 // Because character has been modified, refresh_character will run and update the other half of the "View".
262}
263
264// --- END TEXT INPUT -- //
265
266// --- START SLIDER -- //
267
268/// Creates the age slider that allows the user to input the age of the character.
269fn age_slider_row(character: &Character) -> impl Scene {
270 let age = character.age;
271 bsn! {
272 Node {
273 flex_direction: FlexDirection::Row,
274 align_items: AlignItems::Center,
275 justify_content: JustifyContent::SpaceBetween,
276 column_gap: px(10),
277 }
278 Children [
279 Node
280 Children [
281 Text::new("Age:")
282 ]
283 --
284 @age_slider(character)
285 --
286 Node {
287 width: px(30),
288 }
289 Children [
290 AgeSliderText
291 Text(format!("{}", age))
292 ]
293 ]
294 }
295}
296
297fn age_slider(character: &Character) -> impl Scene {
298 bsn! {
299 Node {
300 width: px(220),
301 border: px(5),
302 padding: UiRect::axes(px(5), px(2)),
303 }
304 AgeSlider
305 Slider {
306 track_click: TrackClick::Snap,
307 orientation: SliderOrientation::Horizontal,
308 }
309 SliderValue({character.age as f32})
310 // Move every whole number.
311 SliderPrecision(0)
312 SliderRange::new(1., 100.)
313 BackgroundColor(Color::BLACK)
314 // This observer is part of the Controller -- it reacts to the user's input!
315 on(on_value_change_age_slider)
316 on(on_pointer_over_pointer_cursor)
317 on(on_pointer_drag_start_grabbing_cursor)
318 on(on_pointer_drag_end_grab_cursor)
319 on(on_pointer_out_default_cursor)
320 Children [
321 // Visible Slider Track
322 // It is 220px in width via its parent.
323 Node {
324 height: px(5),
325 border_radius: BorderRadius::all(px(3)),
326 }
327 BackgroundColor(Color::BLACK)
328 --
329 // Invisible shorter track (does not have background color) that the
330 // SliderThumb glides on. This is so that the thumb
331 // does not go past the left and right sides of the visible slider track.
332 Node {
333 display: Display::Flex,
334 position_type: PositionType::Absolute,
335 left: px(0)
336 // Shortened by the slider thumb's width on the right side.
337 // This means that it is 200px in width.
338 right: px(20),
339 top: px(0),
340 bottom: px(0),
341 }
342 Children [
343 AgeSliderThumb
344 SliderThumb
345 Node {
346 display: Display::Flex,
347 width: px(20),
348 height: px(10),
349 position_type: PositionType::Absolute,
350 // Where the thumb is along the track will be updated by `on_value_change_age_slider`
351 left: percent((character.age as f32 - 1.) / (100. - 1.) * 100.),
352 }
353 BackgroundColor(Color::WHITE)
354 on(on_pointer_over_grab_cursor)
355 on(on_pointer_out_default_cursor)
356 on(on_pointer_drag_start_grabbing_cursor)
357 on(on_pointer_drag_end_grab_cursor)
358 ]
359 ]
360 }
361}
362
363/// A system that implements Controller logic to update the Age.
364/// This particular system updates the Model upon any change in value to the Age Slider.
365/// Sliders emit a `ValueChange<f32>` event when the user drags the slider.
366/// The value of the event is the new value of the slider.
367/// The source of the event is the `Slider` parent entity.
368fn on_value_change_age_slider(
369 event: On<ValueChange<f32>>,
370 age_slider_q: Query<(Entity, &SliderRange), With<AgeSlider>>,
371 mut age_slider_text_q: Query<&mut Text, With<AgeSliderText>>,
372 mut age_slider_thumb_q: Query<&mut Node, With<AgeSliderThumb>>,
373 mut character: ResMut<Character>,
374 mut commands: Commands,
375) {
376 let Ok((entity, slider_range)) = age_slider_q.single_inner() else {
377 return;
378 };
379 if event.source != entity {
380 return;
381 }
382
383 // Update the Model
384 // `SliderPrecision` ensures that this value is a whole number.
385 character.age = event.value as u32;
386 character.changed_fields.push(ChangedField::Age);
387
388 // Update the Widget portion of the View
389 commands
390 .entity(event.source)
391 .insert(SliderValue(character.age as f32));
392 for mut node in age_slider_thumb_q.iter_mut() {
393 node.left = percent(slider_range.thumb_position(character.age as f32) * 100.0);
394 }
395 for mut text in age_slider_text_q.iter_mut() {
396 *text = Text::new(format!("{}", character.age));
397 }
398
399 // Because character has been modified, refresh_character will run and update the other half of the "View".
400}
401
402// --- END SLIDER -- //
403
404// --- START RADIO GROUP -- //
405
406/// Creates the radio group row that allows the user to select a hat for the character.
407fn hat_type_radio_group_row(character: &Character) -> impl Scene {
408 bsn! {
409 Node {
410 flex_direction: FlexDirection::Row,
411 align_items: AlignItems::Center,
412 justify_content: JustifyContent::SpaceBetween,
413 }
414 RadioGroup
415 HatTypeRadioGroup
416 // This observer is part of the Controller -- it reacts to the user's input!
417 on(on_value_change_hat_type)
418 Children [
419 Node
420 Children [
421 Text("Hat: ")
422 ]
423 --
424 {
425 HAT_TYPES.iter()
426 .map(|hat_type| hat_type_radio_button(*hat_type, character))
427 .collect::<Vec<_>>()
428 }
429 ]
430 }
431}
432
433fn hat_type_radio_button(hat_type: HatType, character: &Character) -> Box<dyn Scene> {
434 let base_radio_button = || {
435 bsn! {
436 Node {
437 border: px(5),
438 border_radius: BorderRadius::all(px(10)),
439 padding: UiRect::axes(px(5), px(2)),
440 }
441 RadioButton
442 hat_type
443 BackgroundColor(Color::BLACK)
444 on(on_pointer_over_pointer_cursor)
445 on(on_pointer_out_default_cursor)
446 }
447 };
448 if character.hat_type == hat_type {
449 Box::new(bsn! {
450 @base_radio_button()
451 // The selected hat_type must have the `Checked` component.
452 Checked
453 Children [
454 Text::new(format!("{hat_type:?}"))
455 // The selected hat_type's text is green as opposed to white.
456 TextColor(palettes::basic::GREEN)
457 ]
458 })
459 } else {
460 Box::new(bsn! {
461 @base_radio_button()
462 Children [
463 Text(format!("{hat_type:?}"))
464 TextColor(palettes::basic::WHITE)
465 ]
466 })
467 }
468}
469
470/// This observer is part of the Controller logic.
471/// This observer will update the `Character` Resource based on a change to the Hat Type Radio Group.
472/// Radio groups emit a `ValueChange<Entity>` event when the user clicks on a radio button.
473/// The value of the event is of the clicked radio button.
474/// The source of the event is the parent radio group.
475fn on_value_change_hat_type(
476 event: On<ValueChange<Entity>>,
477 hat_type_value_q: Query<(Entity, &HatType, Has<Checked>, &Children), With<RadioButton>>,
478 hat_type_radio_group_q: Single<Entity, With<HatTypeRadioGroup>>,
479 mut character: ResMut<Character>,
480 mut commands: Commands,
481) {
482 // Ensure this value change event is for the Hat Type Radio Group
483 // Although unnecessary in this example, apps with multiple radio groups need to distinguish
484 // what the value change is for.
485 if event.source != hat_type_radio_group_q.entity() {
486 return;
487 }
488
489 let Ok((_, new_hat_type, has_checked, _)) = hat_type_value_q.get(event.value) else {
490 return;
491 };
492
493 if has_checked {
494 // The hat type has actually not changed, so we do not need to do anything.
495 return;
496 }
497
498 // Update the Model
499 character.hat_type = *new_hat_type;
500 character.changed_fields.push(ChangedField::HatType);
501
502 // Update the Widget portion of the View
503 for (button_entity, hat_type, has_checked, children) in hat_type_value_q.iter() {
504 if character.hat_type == *hat_type {
505 commands.entity(button_entity).insert(Checked);
506 // The radio button only has one child for the text and color of the button
507 commands
508 .entity(children[0])
509 .insert(TextColor(palettes::basic::GREEN.into()));
510 } else if has_checked {
511 commands.entity(button_entity).remove::<Checked>();
512 commands.entity(children[0]).insert(TextColor(Color::WHITE));
513 }
514 }
515 // Because character has been modified, refresh_character will run and update the other half of the "View".
516}
517
518// --- END RADIO GROUP -- //
519
520// --- START CHECK BOX -- //
521
522/// Creates the checkbox row that allows the user to toggle a yellow tint of the character.
523fn tint_yellow_checkbox_row(character: &Character) -> impl Scene {
524 bsn! {
525 Node {
526 flex_direction: FlexDirection::Row,
527 align_items: AlignItems::Center,
528 justify_content: JustifyContent::SpaceBetween,
529 }
530 Children [
531 Node
532 Children [
533 Text("Tint Yellow: ")
534 ]
535 --
536 @tint_yellow_checkbox(character)
537 ]
538 }
539}
540
541fn tint_yellow_checkbox(character: &Character) -> Box<dyn Scene> {
542 let base_checkbox = || {
543 bsn! {
544 Node {
545 padding: UiRect::horizontal(px(5)),
546 }
547 Checkbox
548 TintYellowCheckbox
549 BackgroundColor(Color::WHITE)
550 on(on_pointer_over_pointer_cursor)
551 on(on_pointer_out_default_cursor)
552 // This observer is part of the controller -- it reacts to the user's input!
553 on(on_value_change_tint_yellow)
554 }
555 };
556
557 if character.tint_yellow {
558 Box::new(bsn! {
559 @base_checkbox()
560 Checked
561 Children [
562 Text("X")
563 TextColor(palettes::basic::GREEN)
564 ]
565 })
566 } else {
567 Box::new(bsn! {
568 @base_checkbox()
569 Children [
570 Text(" ")
571 TextColor(palettes::basic::GREEN)
572 ]
573 })
574 }
575}
576
577/// This observer is part of the Controller logic.
578/// This observer will update the `Character` Resource based on a change to the Tint Yellow Checkbox.
579/// Checkboxes emit a `ValueChange<bool>` event when the user clicks on a checkbox.
580/// The value of the event is the value of the toggle.
581/// The source of the event is the checkbox.
582fn on_value_change_tint_yellow(
583 event: On<ValueChange<bool>>,
584 tint_yellow_checkbox_q: Query<(Entity, &Children), With<TintYellowCheckbox>>,
585 mut character: ResMut<Character>,
586 mut commands: Commands,
587) {
588 let Ok((checkbox_entity, children)) = tint_yellow_checkbox_q.single_inner() else {
589 return;
590 };
591
592 // Ensure this value change event is for the checkbox.
593 // Although unnecessary in this example, apps with multiple checkboxes need to distinguish
594 // what the value change is for.
595 if event.source != checkbox_entity {
596 return;
597 }
598
599 // Update the Model
600 character.tint_yellow = event.value;
601 character.changed_fields.push(ChangedField::TintYellow);
602
603 // Update the Widget portion of the View
604 if character.tint_yellow {
605 commands.entity(event.source).insert(Checked);
606 // The checkbox only has one child for the X and its color
607 commands.entity(children[0]).insert(Text::new("X"));
608 } else {
609 commands.entity(event.source).remove::<Checked>();
610 commands.entity(children[0]).insert(Text::new(" "));
611 }
612 // Because character has been modified, refresh_character will run and update the other half of the "View".
613}Sourcepub fn is_empty(&self) -> bool
pub fn is_empty(&self) -> bool
Returns true if there are no query items.
This is equivalent to self.iter().next().is_none(), and thus the worst case runtime will be O(n)
where n is the number of potential matches. This can be notably expensive for queries that rely
on non-archetypal filters such as Added, Changed or Spawned which must individually check
each query result for a match.
§Example
Here, the score is increased only if an entity with a Player component is present in the world:
fn update_score_system(query: Query<(), With<Player>>, mut score: ResMut<Score>) {
if !query.is_empty() {
score.0 += 1;
}
}Examples found in repository?
66fn setup(mut commands: Commands) {
67 commands.spawn(Camera2d);
68
69 commands.spawn_scene(bsn! {
70 @background()
71 on(|press: On<PointerPress>, query: Query<(), With<ContextMenu>>, mut commands: Commands| {
72 debug!("click: {}", press.pointer.position);
73
74 if query.is_empty() {
75 // Open the context menu at the pointer location if one does not exist
76 commands.trigger(OpenContextMenu {
77 pos: press.pointer.position,
78 });
79 } else {
80 // Close the context menu if it exists
81 commands.trigger(CloseContextMenus);
82 }
83 })
84 });
85}More examples
583fn play_fox_animation(
584 mut commands: Commands,
585 mut animation_players_query: Query<
586 (Entity, &mut AnimationPlayer),
587 Without<AnimationGraphHandle>,
588 >,
589 asset_server: Res<AssetServer>,
590 mut animation_graphs: ResMut<Assets<AnimationGraph>>,
591) {
592 // Only pick up animation players that don't already have an animation graph
593 // handle.
594 // This ensures that we only start playing the animation once.
595 if animation_players_query.is_empty() {
596 return;
597 }
598
599 let fox_animation = asset_server.load(GltfAssetLabel::Animation(0).from_asset(FOX_ASSET_PATH));
600 let (fox_animation_graph, fox_animation_node) =
601 AnimationGraph::from_clip(fox_animation.clone());
602 let fox_animation_graph = animation_graphs.add(fox_animation_graph);
603
604 for (entity, mut animation_player) in animation_players_query.iter_mut() {
605 commands
606 .entity(entity)
607 .insert(AnimationGraphHandle(fox_animation_graph.clone()));
608 animation_player.play(fox_animation_node).repeat();
609 }
610}814fn update_control_text(
815 mut rows: Query<(&ControlRow, &mut Text)>,
816 state: Res<DemoState>,
817 pathtracing: Query<(), With<Pathtracer>>,
818 #[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))] dlss_rr_supported: Option<
819 Res<DlssRayReconstructionSupported>,
820 >,
821 #[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))] dlss_camera: Query<
822 Has<Dlss<DlssRayReconstructionFeature>>,
823 With<SolariLighting>,
824 >,
825) {
826 for (row, mut text) in &mut rows {
827 text.0.clear();
828
829 match row {
830 ControlRow::Pause => text
831 .0
832 .push_str(if state.paused { "Resume" } else { "Pause" }),
833 ControlRow::Metallic => text.0.push_str(if state.metallic {
834 "Switch to dielectric"
835 } else {
836 "Switch to metallic"
837 }),
838 ControlRow::Presets => {
839 for (_, name, roughness) in MATERIAL_PRESETS {
840 if (roughness - state.roughness).abs() < 1e-4 {
841 text.0.push_str(&format!("[{name}] "));
842 } else {
843 text.0.push_str(&format!("{name} "));
844 }
845 }
846 }
847 ControlRow::MirrorPan => text.0.push_str(if state.pan_mirror {
848 "Stop panning"
849 } else {
850 "Pan back and forth"
851 }),
852 ControlRow::MirrorSlide => text.0.push_str(if state.slide_mirror {
853 "Stop sliding"
854 } else {
855 "Slide back and forth"
856 }),
857 ControlRow::Renderer => text.0.push_str(if pathtracing.is_empty() {
858 "Switch to reference pathtracer"
859 } else {
860 "Switch to realtime lighting - pause to let the pathtracer converge"
861 }),
862 ControlRow::Denoising => {
863 #[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
864 if dlss_rr_supported.is_some() {
865 if matches!(dlss_camera.single(), Ok(true)) {
866 text.0.push_str("Disable DLSS Ray Reconstruction");
867 } else {
868 text.0.push_str("Enable DLSS Ray Reconstruction");
869 }
870 } else {
871 text.0.push_str("DLSS Ray Reconstruction not supported");
872 }
873
874 #[cfg(any(not(feature = "dlss"), feature = "force_disable_dlss"))]
875 text.0.push_str("App not compiled with DLSS support");
876 }
877 }
878 }
879}
880
881fn update_performance_text(
882 mut text: Single<&mut Text, With<PerformanceText>>,
883 diagnostics: Res<DiagnosticsStore>,
884 pathtracing: Query<(), With<Pathtracer>>,
885 #[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))] dlss_camera: Query<
886 Has<Dlss<DlssRayReconstructionFeature>>,
887 With<SolariLighting>,
888 >,
889) {
890 text.0.clear();
891
892 if !pathtracing.is_empty() {
893 text.push_str("Pathtracer (untimed)");
894 return;
895 }
896
897 let mut total = 0.0;
898 let mut add_diagnostic = |name: &str, path: &'static str| {
899 let path = DiagnosticPath::new(path);
900 if let Some(value) = diagnostics.get(&path).and_then(Diagnostic::smoothed) {
901 text.push_str(&format!("{name:17} {value:.2} ms\n"));
902 total += value;
903 }
904 };
905
906 (add_diagnostic)(
907 "Light tiles",
908 "render/solari_lighting/presample_light_tiles/elapsed_gpu",
909 );
910 (add_diagnostic)(
911 "World cache",
912 "render/solari_lighting/world_cache/elapsed_gpu",
913 );
914 (add_diagnostic)("Lighting", "render/solari_lighting/lighting/elapsed_gpu");
915 #[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
916 if matches!(dlss_camera.single(), Ok(true)) {
917 (add_diagnostic)("DLSS-RR", "render/dlss_ray_reconstruction/elapsed_gpu");
918 }
919 text.push_str(&format!("{:17} {total:.2} ms\n", "Total"));
920}528fn create_cubes(
529 image_assets: Res<Assets<Image>>,
530 mut commands: Commands,
531 irradiance_volumes: Query<(&IrradianceVolume, &GlobalTransform)>,
532 voxel_cube_parents: Query<Entity, With<VoxelCubeParent>>,
533 voxel_cubes: Query<Entity, With<VoxelCube>>,
534 example_assets: Res<ExampleAssets>,
535 mut voxel_visualization_material_assets: ResMut<Assets<VoxelVisualizationMaterial>>,
536) {
537 // If voxel cubes have already been spawned, don't do anything.
538 if !voxel_cubes.is_empty() {
539 return;
540 }
541
542 let Some(voxel_cube_parent) = voxel_cube_parents.iter().next() else {
543 return;
544 };
545
546 for (irradiance_volume, global_transform) in irradiance_volumes.iter() {
547 let Some(image) = image_assets.get(&irradiance_volume.voxels) else {
548 continue;
549 };
550
551 let resolution = image.texture_descriptor.size;
552
553 let voxel_cube_material = voxel_visualization_material_assets.add(ExtendedMaterial {
554 base: StandardMaterial::from(Color::from(RED)),
555 extension: VoxelVisualizationExtension {
556 irradiance_volume_info: VoxelVisualizationIrradianceVolumeInfo {
557 world_from_voxel: VOXEL_FROM_WORLD.inverse(),
558 voxel_from_world: VOXEL_FROM_WORLD,
559 resolution: uvec3(
560 resolution.width,
561 resolution.height,
562 resolution.depth_or_array_layers,
563 ),
564 intensity: IRRADIANCE_VOLUME_INTENSITY,
565 },
566 },
567 });
568
569 let scale = vec3(
570 1.0 / resolution.width as f32,
571 1.0 / resolution.height as f32,
572 1.0 / resolution.depth_or_array_layers as f32,
573 );
574
575 // Spawn a cube for each voxel.
576 for z in 0..resolution.depth_or_array_layers {
577 for y in 0..resolution.height {
578 for x in 0..resolution.width {
579 let uvw = (uvec3(x, y, z).as_vec3() + 0.5) * scale - 0.5;
580 let pos = global_transform.transform_point(uvw);
581 let voxel_cube = commands
582 .spawn((
583 Mesh3d(example_assets.voxel_cube.clone()),
584 MeshMaterial3d(voxel_cube_material.clone()),
585 Transform::from_scale(Vec3::splat(VOXEL_CUBE_SCALE))
586 .with_translation(pos),
587 ))
588 .insert(VoxelCube)
589 .insert(NotShadowCaster)
590 .id();
591
592 commands.entity(voxel_cube_parent).add_child(voxel_cube);
593 }
594 }
595 }
596 }
597}Sourcepub fn contains(&self, entity: Entity) -> bool
pub fn contains(&self, entity: Entity) -> bool
Returns true if the given Entity matches the query.
This is always guaranteed to run in O(1) time.
§Example
fn targeting_system(in_range_query: Query<&InRange>, target: Res<Target>) {
if in_range_query.contains(target.entity) {
println!("Bam!")
}
}Examples found in repository?
More examples
490 pub fn show_aabbs(
491 scene_ready: On<WorldInstanceReady>,
492 mut commands: Commands,
493 children: Query<&Children>,
494 meshes: Query<(), With<Mesh3d>>,
495 ) {
496 for child in children
497 .iter_descendants(scene_ready.entity)
498 .filter(|&e| meshes.contains(e))
499 {
500 commands.entity(child).insert(ShowAabbGizmo {
501 color: Some(BLACK.into()),
502 });
503 }
504 }98fn draw_mesh_intersections(
99 pointers: Query<&PointerInteraction>,
100 untargetable: Query<Entity, Without<Shape>>,
101 mut gizmos: Gizmos,
102) {
103 for (point, normal) in pointers
104 .iter()
105 .flat_map(|interaction| interaction.iter())
106 .filter_map(|(entity, hit)| {
107 if !untargetable.contains(*entity) {
108 hit.position.zip(hit.normal)
109 } else {
110 None
111 }
112 })
113 {
114 gizmos.arrow(point, point + normal.normalize() * 0.5, Color::WHITE);
115 }
116}38fn disable_entities_on_click(
39 click: On<PointerClick>,
40 valid_query: Query<&DisableOnClick>,
41 mut commands: Commands,
42) {
43 // Windows and text are entities and can be clicked!
44 // We definitely don't want to disable the window itself,
45 // because that would cause the app to close!
46 if valid_query.contains(click.entity) {
47 // Just add the `Disabled` component to the entity to disable it.
48 // Note that the `Disabled` component is *only* added to the entity,
49 // its children are not affected.
50 commands.entity(click.entity).insert(Disabled);
51 }
52}281fn on_press_selectable(
282 event: On<PointerPress>,
283 mut borders: Query<(Entity, &mut BorderColor, &BackgroundColor), With<SelectableColor>>,
284 mut draw_color: ResMut<DrawColor>,
285 mut commands: Commands,
286) {
287 if !borders.contains(event.entity) {
288 return;
289 }
290 for (entity, mut border, _) in borders.iter_mut() {
291 commands.entity(entity).remove::<Selected>();
292 *border = BorderColor::all(NORMAL_COLOR);
293 }
294 let (_, mut border, background_color) = borders.get_mut(event.entity).unwrap();
295 *border = BorderColor::all(SELECTED_COLOR);
296 commands.entity(event.entity).insert(Selected);
297
298 draw_color.0 = background_color.0;
299}265fn spawn_box(
266 press: On<PointerPress>,
267 window: Query<(), With<Window>>,
268 camera: Single<(&Camera, &GlobalTransform)>,
269 mut commands: Commands,
270) {
271 if press.button != PointerButton::Primary {
272 return;
273 }
274 if !window.contains(press.entity) {
275 return;
276 }
277
278 let (camera, camera_transform) = camera.into_inner();
279 let Ok(click_point) = camera.viewport_to_world_2d(camera_transform, press.pointer.position)
280 else {
281 return;
282 };
283 commands.spawn((
284 Sprite::from_color(tailwind::RED_500, Vec2::new(100.0, 100.0)),
285 Transform::from_translation(click_point.extend(0.0)),
286 Pickable::default(),
287 Box,
288 ));
289}
290
291/// A component to rotate the hue of a sprite every frame.
292#[derive(Component)]
293struct RotateHue;
294
295/// Rotates the hue of each [`Sprite`] tagged with [`RotateHue`].
296fn rotate_hue(time: Res<Time>, mut sprites: Query<&mut Sprite, With<RotateHue>>) {
297 for mut sprite in sprites.iter_mut() {
298 // Make a full rotation every 2 seconds.
299 sprite.color = sprite.color.rotate_hue(time.delta_secs() * 180.0);
300 }
301}
302
303/// Starts rotating the hue of a box that has been right-clicked.
304fn start_rotate_box_hue(
305 event: On<PointerPress>,
306 boxes: Query<(), With<Box>>,
307 mut commands: Commands,
308) {
309 if event.button != PointerButton::Secondary {
310 return;
311 }
312 if !boxes.contains(event.entity) {
313 return;
314 }
315 commands.entity(event.entity).insert(RotateHue);
316}
317
318/// Stops rotating the box hue if it's right-click is released.
319fn end_rotate_box_hue_on_release(
320 event: On<PointerRelease>,
321 boxes: Query<(), (With<Box>, With<RotateHue>)>,
322 mut commands: Commands,
323) {
324 if event.button != PointerButton::Secondary {
325 return;
326 }
327 if !boxes.contains(event.entity) {
328 return;
329 }
330 commands.entity(event.entity).remove::<RotateHue>();
331}
332
333/// Stops rotating the box hue if the cursor moves off the entity.
334fn end_rotate_box_hue_on_out(
335 event: On<PointerOut>,
336 boxes: Query<(), (With<Box>, With<RotateHue>)>,
337 mut commands: Commands,
338) {
339 if !boxes.contains(event.entity) {
340 return;
341 }
342 commands.entity(event.entity).remove::<RotateHue>();
343}
344
345/// Blocks propagation of pointer press events on left-clicked boxes.
346fn stop_propagate_on_clicked_box(mut event: On<PointerPress>, boxes: Query<(), With<Box>>) {
347 if event.button != PointerButton::Primary {
348 return;
349 }
350 if !boxes.contains(event.entity) {
351 return;
352 }
353 event.propagate(false);
354}Sourcepub fn count(&self) -> usize
pub fn count(&self) -> usize
Counts the number of entities that match the query.
This is equivalent to self.iter().count() but may be more efficient in some cases.
If D::IS_ARCHETYPAL && F::IS_ARCHETYPAL is true,
this will do work proportional to the number of matched archetypes or tables, but will not iterate each entity.
If it is false, it will have to do work for each entity.
§Example
fn targeting_system(in_range_query: Query<&InRange>) {
let count = in_range_query.count();
println!("{count} targets in range!");
}Sourcepub fn transmute_lens<NewD>(&mut self) -> QueryLens<'_, NewD>where
NewD: SingleEntityQueryData,
pub fn transmute_lens<NewD>(&mut self) -> QueryLens<'_, NewD>where
NewD: SingleEntityQueryData,
Returns a QueryLens that can be used to construct a new Query giving more
restrictive access to the entities matched by the current query.
A transmute is valid only if NewD has a subset of the read, write, and required access
of the current query. A precise description of the access required by each parameter
type is given in the table below, but typical uses are to:
- Remove components, e.g.
Query<(&A, &B)>toQuery<&A>. - Retrieve an existing component with reduced or equal access, e.g.
Query<&mut A>toQuery<&A>orQuery<&T>toQuery<Ref<T>>. - Add parameters with no new access, for example adding an
Entityparameter.
Note that since filter terms are dropped, non-archetypal filters like
Added, Changed and Spawned will not be respected. To maintain or change filter
terms see Self::transmute_lens_filtered.
QueryData parameter type | Access required |
|---|---|
Entity, EntityLocation, SpawnDetails, &Archetype, Has<T>, PhantomData<T> | No access |
EntityMut | Read and write access to all components, but no required access |
EntityRef | Read access to all components, but no required access |
&T, Ref<T> | Read and required access to T |
&mut T, Mut<T> | Read, write and required access to T |
Option<T>, AnyOf<(D, ...)> | Read and write access to T, but no required access |
Tuples of query data and#[derive(QueryData)] structs | The union of the access of their subqueries |
FilteredEntityRef, FilteredEntityMut | Determined by the QueryBuilder used to construct them. Any query can be transmuted to them, and they will receive the access of the source query. When combined with other QueryData, they will receive any access of the source query that does not conflict with the other data |
transmute_lens drops filter terms, but Self::transmute_lens_filtered supports returning a QueryLens with a new
filter type - the access required by filter parameters are as follows.
QueryFilter parameter type | Access required |
|---|---|
Added<T>, Changed<T> | Read and required access to T |
With<T>, Without<T> | No access |
Or<(T, ...)> | Read access of the subqueries, but no required access |
Tuples of query filters and #[derive(QueryFilter)] structs | The union of the access of their subqueries |
§Panics
This will panic if the access required by NewD is not a subset of that required by
the original fetch D.
§Example
fn reusable_function(lens: &mut QueryLens<&A>) {
assert_eq!(lens.query().single().unwrap().0, 10);
}
// We can use the function in a system that takes the exact query.
fn system_1(mut query: Query<&A>) {
reusable_function(&mut query.as_query_lens());
}
// We can also use it with a query that does not match exactly
// by transmuting it.
fn system_2(mut query: Query<(&mut A, &B)>) {
let mut lens = query.transmute_lens::<&A>();
reusable_function(&mut lens);
}
§Examples of valid transmutes
// `&mut T` and `Mut<T>` access the same data and can be transmuted to each other,
// `&T` and `Ref<T>` access the same data and can be transmuted to each other,
// and mutable versions can be transmuted to read-only versions
assert_valid_transmute::<&mut T, &T>();
assert_valid_transmute::<&mut T, Mut<T>>();
assert_valid_transmute::<Mut<T>, &mut T>();
assert_valid_transmute::<&T, Ref<T>>();
assert_valid_transmute::<Ref<T>, &T>();
// The structure can be rearranged, or subqueries dropped
assert_valid_transmute::<(&T, &U), &T>();
assert_valid_transmute::<((&T, &U), &V), (&T, (&U, &V))>();
assert_valid_transmute::<Option<(&T, &U)>, (Option<&T>, Option<&U>)>();
// Queries with no access can be freely added
assert_valid_transmute::<
&T,
(&T, Entity, EntityLocation, &Archetype, Has<U>, PhantomData<T>),
>();
// Required access can be transmuted to optional,
// and optional access can be transmuted to other optional access
assert_valid_transmute::<&T, Option<&T>>();
assert_valid_transmute::<AnyOf<(&mut T, &mut U)>, Option<&T>>();
// Note that removing subqueries from `AnyOf` will result
// in an `AnyOf` where all subqueries can yield `None`!
assert_valid_transmute::<AnyOf<(&T, &U, &V)>, AnyOf<(&T, &U)>>();
assert_valid_transmute::<EntityMut, Option<&mut T>>();
// Anything can be transmuted to `FilteredEntityRef` or `FilteredEntityMut`
// This will create a `FilteredEntityMut` that only has read access to `T`
assert_valid_transmute::<&T, FilteredEntityMut>();
// This will create a `FilteredEntityMut` that has no access to `T`,
// read access to `U`, and write access to `V`.
assert_valid_transmute::<(&mut T, &mut U, &mut V), (&mut T, &U, FilteredEntityMut)>();
// `Added<T>` and `Changed<T>` filters have the same access as `&T` data
// Remember that they are only evaluated on the transmuted query, not the original query!
assert_valid_transmute_filtered::<Entity, Changed<T>, &T, ()>();
assert_valid_transmute_filtered::<&mut T, (), &T, Added<T>>();
// Nested inside of an `Or` filter, they have the same access as `Option<&T>`.
assert_valid_transmute_filtered::<Option<&T>, (), Entity, Or<(Changed<T>, With<U>)>>();Sourcepub fn transmute_lens_inner<NewD>(self) -> QueryLens<'w, NewD>where
NewD: SingleEntityQueryData,
pub fn transmute_lens_inner<NewD>(self) -> QueryLens<'w, NewD>where
NewD: SingleEntityQueryData,
Returns a QueryLens that can be used to construct a new Query giving more restrictive
access to the entities matched by the current query.
This consumes the Query to return results with the actual “inner” world lifetime.
See Self::transmute_lens for a description of allowed transmutes.
§Panics
This will panic if NewD is not a subset of the original fetch D
§Example
fn reusable_function(mut lens: QueryLens<&A>) {
assert_eq!(lens.query().single().unwrap().0, 10);
}
// We can use the function in a system that takes the exact query.
fn system_1(query: Query<&A>) {
reusable_function(query.into_query_lens());
}
// We can also use it with a query that does not match exactly
// by transmuting it.
fn system_2(query: Query<(&mut A, &B)>) {
let mut lens = query.transmute_lens_inner::<&A>();
reusable_function(lens);
}
§See also
transmute_lensto convert to a lens using a mutable borrow of theQuery.
Sourcepub fn transmute_lens_filtered<NewD, NewF>(
&mut self,
) -> QueryLens<'_, NewD, NewF>where
NewD: SingleEntityQueryData,
NewF: QueryFilter,
pub fn transmute_lens_filtered<NewD, NewF>(
&mut self,
) -> QueryLens<'_, NewD, NewF>where
NewD: SingleEntityQueryData,
NewF: QueryFilter,
Equivalent to Self::transmute_lens but also includes a QueryFilter type.
See Self::transmute_lens for a description of allowed transmutes.
Note that the lens will iterate the same tables and archetypes as the original query. This means that
additional archetypal query terms like With and Without
will not necessarily be respected and non-archetypal terms like Added,
Changed and Spawned will only be respected if they
are in the type signature.
Sourcepub fn transmute_lens_filtered_inner<NewD, NewF>(
self,
) -> QueryLens<'w, NewD, NewF>where
NewD: SingleEntityQueryData,
NewF: QueryFilter,
pub fn transmute_lens_filtered_inner<NewD, NewF>(
self,
) -> QueryLens<'w, NewD, NewF>where
NewD: SingleEntityQueryData,
NewF: QueryFilter,
Equivalent to Self::transmute_lens_inner but also includes a QueryFilter type.
This consumes the Query to return results with the actual “inner” world lifetime.
See Self::transmute_lens for a description of allowed transmutes.
Note that the lens will iterate the same tables and archetypes as the original query. This means that
additional archetypal query terms like With and Without
will not necessarily be respected and non-archetypal terms like Added,
Changed and Spawned will only be respected if they
are in the type signature.
§See also
transmute_lens_filteredto convert to a lens using a mutable borrow of theQuery.
Sourcepub fn as_query_lens(&mut self) -> QueryLens<'_, D>where
D: SingleEntityQueryData,
pub fn as_query_lens(&mut self) -> QueryLens<'_, D>where
D: SingleEntityQueryData,
Gets a QueryLens with the same accesses as the existing query
Sourcepub fn into_query_lens(self) -> QueryLens<'w, D>where
D: SingleEntityQueryData,
pub fn into_query_lens(self) -> QueryLens<'w, D>where
D: SingleEntityQueryData,
Gets a QueryLens with the same accesses as the existing query
§See also
as_query_lensto convert to a lens using a mutable borrow of theQuery.
Sourcepub fn join<'a, OtherD, NewD>(
&'a mut self,
other: &'a mut Query<'_, '_, OtherD>,
) -> QueryLens<'a, NewD>where
OtherD: QueryData,
NewD: SingleEntityQueryData,
pub fn join<'a, OtherD, NewD>(
&'a mut self,
other: &'a mut Query<'_, '_, OtherD>,
) -> QueryLens<'a, NewD>where
OtherD: QueryData,
NewD: SingleEntityQueryData,
Returns a QueryLens that can be used to get a query with the combined fetch.
For example, this can take a Query<&A> and a Query<&B> and return a Query<(&A, &B)>.
The returned query will only return items with both A and B. Note that since filters
are dropped, non-archetypal filters like Added, Changed and Spawned will not be respected.
To maintain or change filter terms see Self::join_filtered.
§Example
fn system(
mut transforms: Query<&Transform>,
mut players: Query<&Player>,
mut enemies: Query<&Enemy>
) {
let mut players_transforms: QueryLens<(&Transform, &Player)> = transforms.join(&mut players);
for (transform, player) in &players_transforms.query() {
// do something with a and b
}
let mut enemies_transforms: QueryLens<(&Transform, &Enemy)> = transforms.join(&mut enemies);
for (transform, enemy) in &enemies_transforms.query() {
// do something with a and b
}
}
§Panics
This will panic if NewD is not a subset of the union of the original fetch Q and OtherD.
§Allowed Transmutes
Like transmute_lens the query terms can be changed with some restrictions.
See Self::transmute_lens for more details.
Sourcepub fn join_inner<OtherD, NewD>(
self,
other: Query<'w, '_, OtherD>,
) -> QueryLens<'w, NewD>where
OtherD: QueryData,
NewD: SingleEntityQueryData,
pub fn join_inner<OtherD, NewD>(
self,
other: Query<'w, '_, OtherD>,
) -> QueryLens<'w, NewD>where
OtherD: QueryData,
NewD: SingleEntityQueryData,
Returns a QueryLens that can be used to get a query with the combined fetch.
This consumes the Query to return results with the actual “inner” world lifetime.
For example, this can take a Query<&A> and a Query<&B> and return a Query<(&A, &B)>.
The returned query will only return items with both A and B. Note that since filters
are dropped, non-archetypal filters like Added, Changed and Spawned will not be respected.
To maintain or change filter terms see Self::join_filtered.
§Panics
This will panic if NewD is not a subset of the union of the original fetch Q and OtherD.
§Allowed Transmutes
Like transmute_lens the query terms can be changed with some restrictions.
See Self::transmute_lens for more details.
§See also
Sourcepub fn join_filtered<'a, OtherD, OtherF, NewD, NewF>(
&'a mut self,
other: &'a mut Query<'_, '_, OtherD, OtherF>,
) -> QueryLens<'a, NewD, NewF>
pub fn join_filtered<'a, OtherD, OtherF, NewD, NewF>( &'a mut self, other: &'a mut Query<'_, '_, OtherD, OtherF>, ) -> QueryLens<'a, NewD, NewF>
Equivalent to Self::join but also includes a QueryFilter type.
Note that the lens with iterate a subset of the original queries’ tables
and archetypes. This means that additional archetypal query terms like
With and Without will not necessarily be respected and non-archetypal
terms like Added, Changed and Spawned will only be respected if they
are in the type signature.
Sourcepub fn join_filtered_inner<OtherD, OtherF, NewD, NewF>(
self,
other: Query<'w, '_, OtherD, OtherF>,
) -> QueryLens<'w, NewD, NewF>
pub fn join_filtered_inner<OtherD, OtherF, NewD, NewF>( self, other: Query<'w, '_, OtherD, OtherF>, ) -> QueryLens<'w, NewD, NewF>
Equivalent to Self::join_inner but also includes a QueryFilter type.
This consumes the Query to return results with the actual “inner” world lifetime.
Note that the lens with iterate a subset of the original queries’ tables
and archetypes. This means that additional archetypal query terms like
With and Without will not necessarily be respected and non-archetypal
terms like Added, Changed and Spawned will only be respected if they
are in the type signature.
§See also
join_filteredto join using a mutable borrow of theQuery.
Trait Implementations§
Source§impl<D, F> Clone for Query<'_, '_, D, F>where
D: ReadOnlyQueryData,
F: QueryFilter,
impl<D, F> Clone for Query<'_, '_, D, F>where
D: ReadOnlyQueryData,
F: QueryFilter,
impl<D, F> Copy for Query<'_, '_, D, F>where
D: ReadOnlyQueryData,
F: QueryFilter,
Source§impl<'w, 'q, Q, F> From<&'q mut Query<'w, '_, Q, F>> for QueryLens<'q, Q, F>where
Q: SingleEntityQueryData,
F: QueryFilter,
impl<'w, 'q, Q, F> From<&'q mut Query<'w, '_, Q, F>> for QueryLens<'q, Q, F>where
Q: SingleEntityQueryData,
F: QueryFilter,
Source§impl<'w, 's, Q, F> From<&'s mut QueryLens<'w, Q, F>> for Query<'s, 's, Q, F>where
Q: QueryData,
F: QueryFilter,
impl<'w, 's, Q, F> From<&'s mut QueryLens<'w, Q, F>> for Query<'s, 's, Q, F>where
Q: QueryData,
F: QueryFilter,
Source§impl<'w, 's, D, F> IntoIterator for Query<'w, 's, D, F>where
D: IterQueryData,
F: QueryFilter,
impl<'w, 's, D, F> IntoIterator for Query<'w, 's, D, F>where
D: IterQueryData,
F: QueryFilter,
Source§impl<'w, 's, D, F> IntoIterator for &'w Query<'_, 's, D, F>where
D: QueryData,
F: QueryFilter,
impl<'w, 's, D, F> IntoIterator for &'w Query<'_, 's, D, F>where
D: QueryData,
F: QueryFilter,
Source§impl<'w, 's, D, F> IntoIterator for &'w mut Query<'_, 's, D, F>where
D: IterQueryData,
F: QueryFilter,
impl<'w, 's, D, F> IntoIterator for &'w mut Query<'_, 's, D, F>where
D: IterQueryData,
F: QueryFilter,
impl<'w, 's, D, F> ReadOnlySystemParam for Query<'w, 's, D, F>where
D: ReadOnlyQueryData + 'static,
F: QueryFilter + 'static,
Source§impl<D, F> SystemParam for Query<'_, '_, D, F>where
D: QueryData + 'static,
F: QueryFilter + 'static,
impl<D, F> SystemParam for Query<'_, '_, D, F>where
D: QueryData + 'static,
F: QueryFilter + 'static,
Source§type State = QueryState<D, F>
type State = QueryState<D, F>
Source§type Item<'w, 's> = Query<'w, 's, D, F>
type Item<'w, 's> = Query<'w, 's, D, F>
Self, instantiated with new lifetimes. Read moreSource§fn init_state(world: &mut World) -> <Query<'_, '_, D, F> as SystemParam>::State
fn init_state(world: &mut World) -> <Query<'_, '_, D, F> as SystemParam>::State
State.Source§fn init_access(
state: &<Query<'_, '_, D, F> as SystemParam>::State,
system_meta: &mut SystemMeta,
system_access: &mut SystemAccess,
world: &mut World,
)
fn init_access( state: &<Query<'_, '_, D, F> as SystemParam>::State, system_meta: &mut SystemMeta, system_access: &mut SystemAccess, world: &mut World, )
Source§unsafe fn get_param<'w, 's>(
state: &'s mut <Query<'_, '_, D, F> as SystemParam>::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
change_tick: Tick,
) -> Result<<Query<'_, '_, D, F> as SystemParam>::Item<'w, 's>, SystemParamValidationError>
unsafe fn get_param<'w, 's>( state: &'s mut <Query<'_, '_, D, F> as SystemParam>::State, system_meta: &SystemMeta, world: UnsafeWorldCell<'w>, change_tick: Tick, ) -> Result<<Query<'_, '_, D, F> as SystemParam>::Item<'w, 's>, SystemParamValidationError>
SystemParamFunction. Read moreSource§fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World)
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World)
SystemParam’s state.
This is used to apply Commands during ApplyDeferred.Source§fn queue(
state: &mut Self::State,
system_meta: &SystemMeta,
world: DeferredWorld<'_>,
)
fn queue( state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld<'_>, )
ApplyDeferred.Source§impl<'w, 's, D, F> SystemParamBuilder<Query<'w, 's, D, F>> for QueryState<D, F>where
D: QueryData + 'static,
F: QueryFilter + 'static,
impl<'w, 's, D, F> SystemParamBuilder<Query<'w, 's, D, F>> for QueryState<D, F>where
D: QueryData + 'static,
F: QueryFilter + 'static,
Source§fn build(self, world: &mut World) -> QueryState<D, F>
fn build(self, world: &mut World) -> QueryState<D, F>
World access used by this SystemParam
and creates a new instance of this param’s State.Source§fn build_state(self, world: &mut World) -> SystemState<P>
fn build_state(self, world: &mut World) -> SystemState<P>
SystemState from a SystemParamBuilder.
To create a system, call SystemState::build_system on the result.Source§fn build_system<Marker, In, Out, Func>(
self,
func: Func,
) -> IntoBuilderSystem<Marker, In, Out, Func, Self>where
Self: 'static,
Func: SystemParamFunction<Marker, Param = P>,
fn build_system<Marker, In, Out, Func>(
self,
func: Func,
) -> IntoBuilderSystem<Marker, In, Out, Func, Self>where
Self: 'static,
Func: SystemParamFunction<Marker, Param = P>,
Source§impl<'w, 's, D, F, T> SystemParamBuilder<Query<'w, 's, D, F>> for QueryParamBuilder<T>
impl<'w, 's, D, F, T> SystemParamBuilder<Query<'w, 's, D, F>> for QueryParamBuilder<T>
Source§fn build(self, world: &mut World) -> QueryState<D, F>
fn build(self, world: &mut World) -> QueryState<D, F>
World access used by this SystemParam
and creates a new instance of this param’s State.Source§fn build_state(self, world: &mut World) -> SystemState<P>
fn build_state(self, world: &mut World) -> SystemState<P>
SystemState from a SystemParamBuilder.
To create a system, call SystemState::build_system on the result.Source§fn build_system<Marker, In, Out, Func>(
self,
func: Func,
) -> IntoBuilderSystem<Marker, In, Out, Func, Self>where
Self: 'static,
Func: SystemParamFunction<Marker, Param = P>,
fn build_system<Marker, In, Out, Func>(
self,
func: Func,
) -> IntoBuilderSystem<Marker, In, Out, Func, Self>where
Self: 'static,
Func: SystemParamFunction<Marker, Param = P>,
Auto Trait Implementations§
impl<'world, 'state, D, F = ()> !RefUnwindSafe for Query<'world, 'state, D, F>
impl<'world, 'state, D, F = ()> !UnwindSafe for Query<'world, 'state, D, F>
impl<'world, 'state, D, F> Freeze for Query<'world, 'state, D, F>where
&'state QueryState<D, F>: Freeze,
impl<'world, 'state, D, F> Send for Query<'world, 'state, D, F>where
&'state QueryState<D, F>: Send,
impl<'world, 'state, D, F> Sync for Query<'world, 'state, D, F>where
&'state QueryState<D, F>: Sync,
impl<'world, 'state, D, F> Unpin for Query<'world, 'state, D, F>where
&'state QueryState<D, F>: Unpin,
impl<'world, 'state, D, F> UnsafeUnpin for Query<'world, 'state, D, F>where
&'state QueryState<D, F>: UnsafeUnpin,
Blanket Implementations§
Source§impl<T, U> AsBindGroupShaderType<U> for T
impl<T, U> AsBindGroupShaderType<U> for T
Source§fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
T ShaderType for self. When used in AsBindGroup
derives, it is safe to assume that all images in self exist.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
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> ConditionalSend for Twhere
T: Send,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
impl<S, T> Duplex<S> for Twhere
T: FromSample<S> + ToSample<S>,
impl<T> EntitySet for T
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
impl<T> HitDataExtra for T
Source§impl<T> Identity for Twhere
T: ?Sized,
impl<T> Identity for Twhere
T: ?Sized,
Source§impl<T> InitializeFromFunction<T> for T
impl<T> InitializeFromFunction<T> for T
Source§fn initialize_from_function(f: fn() -> T) -> T
fn initialize_from_function(f: fn() -> T) -> T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoResult<T> for T
impl<T> IntoResult<T> for T
Source§fn into_result(self) -> Result<T, RunSystemError>
fn into_result(self) -> Result<T, RunSystemError>
Source§impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
fn into_sample(self) -> T
Source§impl<T> PatchTemplate for Twhere
T: Template,
impl<T> PatchTemplate for Twhere
T: Template,
Source§fn patch_template<F>(func: F) -> TemplatePatch<F, T>
fn patch_template<F>(func: F) -> TemplatePatch<F, T>
Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
impl<T> Settings for T
Source§impl<Ret> SpawnIfAsync<(), Ret> for Ret
impl<Ret> SpawnIfAsync<(), Ret> for Ret
Source§impl<T, O> SuperFrom<T> for Owhere
O: From<T>,
impl<T, O> SuperFrom<T> for Owhere
O: From<T>,
Source§fn super_from(input: T) -> O
fn super_from(input: T) -> O
Source§impl<T, O, M> SuperInto<O, M> for Twhere
O: SuperFrom<T, M>,
impl<T, O, M> SuperInto<O, M> for Twhere
O: SuperFrom<T, M>,
Source§fn super_into(self) -> O
fn super_into(self) -> O
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.Source§impl<T> Template for T
impl<T> Template for T
Source§fn build_template(
&self,
_context: &mut TemplateContext<'_, '_>,
) -> Result<<T as Template>::Output, BevyError>
fn build_template( &self, _context: &mut TemplateContext<'_, '_>, ) -> Result<<T as Template>::Output, BevyError>
entity context to produce a Template::Output.Source§fn clone_template(&self) -> T
fn clone_template(&self) -> T
Clone.Source§impl<T, U> ToSample<U> for Twhere
U: FromSample<T>,
impl<T, U> ToSample<U> for Twhere
U: FromSample<T>,
fn to_sample_(self) -> U
Source§impl<T> TypeData for T
impl<T> TypeData for T
Source§fn clone_type_data(&self) -> Box<dyn TypeData>
fn clone_type_data(&self) -> Box<dyn TypeData>
self.