Migrate from Query::single and friends to Single (#15872)

# Objective

- closes #15866

## Solution

- Simply migrate where possible.

## Testing

- Expect that CI will do most of the work. Examples is another way of
testing this, as most of the work is in that area.
---

## Notes
For now, this PR doesn't migrate `QueryState::single` and friends as for
now, this look like another issue. So for example, QueryBuilders that
used single or `World::query` that used single wasn't migrated. If there
is a easy way to migrate those, please let me know.

Most of the uses of `Query::single` were removed, the only other uses
that I found was related to tests of said methods, so will probably be
removed when we remove `Query::single`.
This commit is contained in:
Pablo Reinhardt 2024-10-13 17:32:06 -03:00 committed by GitHub
parent 3d6b24880e
commit d96a9d15f6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
83 changed files with 352 additions and 483 deletions

View file

@ -67,8 +67,8 @@ pub fn run_condition_yes_with_query(criterion: &mut Criterion) {
group.warm_up_time(core::time::Duration::from_millis(500)); group.warm_up_time(core::time::Duration::from_millis(500));
group.measurement_time(core::time::Duration::from_secs(3)); group.measurement_time(core::time::Duration::from_secs(3));
fn empty() {} fn empty() {}
fn yes_with_query(query: Query<&TestBool>) -> bool { fn yes_with_query(query: Single<&TestBool>) -> bool {
query.single().0 query.0
} }
for amount in 0..21 { for amount in 0..21 {
let mut schedule = Schedule::default(); let mut schedule = Schedule::default();

View file

@ -800,8 +800,8 @@ impl App {
/// commands.spawn(A); /// commands.spawn(A);
/// } /// }
/// ///
/// fn validate(query: Query<(&A, &B, &C)>) { /// fn validate(query: Option<Single<(&A, &B, &C)>>) {
/// let (a, b, c) = query.single(); /// let (a, b, c) = query.unwrap().into_inner();
/// assert_eq!(b, &B(0)); /// assert_eq!(b, &B(0));
/// assert_eq!(c, &C(0)); /// assert_eq!(c, &C(0));
/// } /// }
@ -863,8 +863,8 @@ impl App {
/// commands.spawn(A); /// commands.spawn(A);
/// } /// }
/// ///
/// fn validate(query: Query<(&A, &B, &C)>) { /// fn validate(query: Option<Single<(&A, &B, &C)>>) {
/// let (a, b, c) = query.single(); /// let (a, b, c) = query.unwrap().into_inner();
/// assert_eq!(b, &B(0)); /// assert_eq!(b, &B(0));
/// assert_eq!(c, &C(2)); /// assert_eq!(c, &C(2));
/// } /// }
@ -928,8 +928,8 @@ impl App {
/// commands.spawn(A); /// commands.spawn(A);
/// } /// }
/// ///
/// fn validate(query: Query<(&A, &B, &C)>) { /// fn validate(query: Option<Single<(&A, &B, &C)>>) {
/// let (a, b, c) = query.single(); /// let (a, b, c) = query.unwrap().into_inner();
/// assert_eq!(b, &B(0)); /// assert_eq!(b, &B(0));
/// assert_eq!(c, &C(0)); /// assert_eq!(c, &C(0));
/// } /// }
@ -993,8 +993,8 @@ impl App {
/// commands.spawn(A); /// commands.spawn(A);
/// } /// }
/// ///
/// fn validate(query: Query<(&A, &B, &C)>) { /// fn validate(query: Option<Single<(&A, &B, &C)>>) {
/// let (a, b, c) = query.single(); /// let (a, b, c) = query.unwrap().into_inner();
/// assert_eq!(b, &B(0)); /// assert_eq!(b, &B(0));
/// assert_eq!(c, &C(2)); /// assert_eq!(c, &C(2));
/// } /// }

View file

@ -1206,7 +1206,7 @@ mod tests {
Mut, NonSendMut, Ref, ResMut, TicksMut, CHECK_TICK_THRESHOLD, MAX_CHANGE_AGE, Mut, NonSendMut, Ref, ResMut, TicksMut, CHECK_TICK_THRESHOLD, MAX_CHANGE_AGE,
}, },
component::{Component, ComponentTicks, Tick}, component::{Component, ComponentTicks, Tick},
system::{IntoSystem, Query, System}, system::{IntoSystem, Single, System},
world::World, world::World,
}; };
@ -1236,12 +1236,12 @@ mod tests {
#[test] #[test]
fn change_expiration() { fn change_expiration() {
fn change_detected(query: Query<Ref<C>>) -> bool { fn change_detected(query: Option<Single<Ref<C>>>) -> bool {
query.single().is_changed() query.unwrap().is_changed()
} }
fn change_expired(query: Query<Ref<C>>) -> bool { fn change_expired(query: Option<Single<Ref<C>>>) -> bool {
query.single().is_changed() query.unwrap().is_changed()
} }
let mut world = World::new(); let mut world = World::new();

View file

@ -328,7 +328,7 @@ mod tests {
}, },
system::{ system::{
Commands, In, IntoSystem, Local, NonSend, NonSendMut, ParamSet, Query, Res, ResMut, Commands, In, IntoSystem, Local, NonSend, NonSendMut, ParamSet, Query, Res, ResMut,
Resource, StaticSystemParam, System, SystemState, Resource, Single, StaticSystemParam, System, SystemState,
}, },
world::{EntityMut, FromWorld, World}, world::{EntityMut, FromWorld, World},
}; };
@ -1157,12 +1157,15 @@ mod tests {
world.insert_resource(A(42)); world.insert_resource(A(42));
world.spawn(B(7)); world.spawn(B(7));
let mut system_state: SystemState<(Res<A>, Query<&B>, ParamSet<(Query<&C>, Query<&D>)>)> = let mut system_state: SystemState<(
SystemState::new(&mut world); Res<A>,
Option<Single<&B>>,
ParamSet<(Query<&C>, Query<&D>)>,
)> = SystemState::new(&mut world);
let (a, query, _) = system_state.get(&world); let (a, query, _) = system_state.get(&world);
assert_eq!(*a, A(42), "returned resource matches initial value"); assert_eq!(*a, A(42), "returned resource matches initial value");
assert_eq!( assert_eq!(
*query.single(), **query.unwrap(),
B(7), B(7),
"returned component matches initial value" "returned component matches initial value"
); );
@ -1180,16 +1183,16 @@ mod tests {
world.insert_resource(A(42)); world.insert_resource(A(42));
world.spawn(B(7)); world.spawn(B(7));
let mut system_state: SystemState<(ResMut<A>, Query<&mut B>)> = let mut system_state: SystemState<(ResMut<A>, Option<Single<&mut B>>)> =
SystemState::new(&mut world); SystemState::new(&mut world);
// The following line shouldn't compile because the parameters used are not ReadOnlySystemParam // The following line shouldn't compile because the parameters used are not ReadOnlySystemParam
// let (a, query) = system_state.get(&world); // let (a, query) = system_state.get(&world);
let (a, mut query) = system_state.get_mut(&mut world); let (a, query) = system_state.get_mut(&mut world);
assert_eq!(*a, A(42), "returned resource matches initial value"); assert_eq!(*a, A(42), "returned resource matches initial value");
assert_eq!( assert_eq!(
*query.single_mut(), **query.unwrap(),
B(7), B(7),
"returned component matches initial value" "returned component matches initial value"
); );
@ -1203,21 +1206,22 @@ mod tests {
let mut world = World::default(); let mut world = World::default();
let entity = world.spawn(A(1)).id(); let entity = world.spawn(A(1)).id();
let mut system_state: SystemState<Query<&A, Changed<A>>> = SystemState::new(&mut world); let mut system_state: SystemState<Option<Single<&A, Changed<A>>>> =
SystemState::new(&mut world);
{ {
let query = system_state.get(&world); let query = system_state.get(&world);
assert_eq!(*query.single(), A(1)); assert_eq!(**query.unwrap(), A(1));
} }
{ {
let query = system_state.get(&world); let query = system_state.get(&world);
assert!(query.get_single().is_err()); assert!(query.is_none());
} }
world.entity_mut(entity).get_mut::<A>().unwrap().0 = 2; world.entity_mut(entity).get_mut::<A>().unwrap().0 = 2;
{ {
let query = system_state.get(&world); let query = system_state.get(&world);
assert_eq!(*query.single(), A(2)); assert_eq!(**query.unwrap(), A(2));
} }
} }

View file

@ -1384,7 +1384,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// * `&mut T` -> `&T` /// * `&mut T` -> `&T`
/// * `&mut T` -> `Ref<T>` /// * `&mut T` -> `Ref<T>`
/// * [`EntityMut`](crate::world::EntityMut) -> [`EntityRef`](crate::world::EntityRef) /// * [`EntityMut`](crate::world::EntityMut) -> [`EntityRef`](crate::world::EntityRef)
/// ///
/// [`EntityLocation`]: crate::entity::EntityLocation /// [`EntityLocation`]: crate::entity::EntityLocation
/// [`&Archetype`]: crate::archetype::Archetype /// [`&Archetype`]: crate::archetype::Archetype
#[track_caller] #[track_caller]

View file

@ -1214,18 +1214,17 @@ pub trait SystemBuffer: FromWorld + Send + 'static {
/// ///
/// // Sound the alarm if there are any criminals who pose a threat. /// // Sound the alarm if there are any criminals who pose a threat.
/// fn alert_criminal( /// fn alert_criminal(
/// settlements: Query<&Settlement>, /// settlement: Single<&Settlement>,
/// criminals: Query<&Criminal>, /// criminals: Query<&Criminal>,
/// mut alarm: Deferred<AlarmFlag> /// mut alarm: Deferred<AlarmFlag>
/// ) { /// ) {
/// let settlement = settlements.single();
/// for criminal in &criminals { /// for criminal in &criminals {
/// // Only sound the alarm if the criminal is a threat. /// // Only sound the alarm if the criminal is a threat.
/// // For this example, assume that this check is expensive to run. /// // For this example, assume that this check is expensive to run.
/// // Since the majority of this system's run-time is dominated /// // Since the majority of this system's run-time is dominated
/// // by calling `is_threat()`, we defer sounding the alarm to /// // by calling `is_threat()`, we defer sounding the alarm to
/// // allow this system to run in parallel with other alarm systems. /// // allow this system to run in parallel with other alarm systems.
/// if criminal.is_threat(settlement) { /// if criminal.is_threat(*settlement) {
/// alarm.flag(); /// alarm.flag();
/// } /// }
/// } /// }

View file

@ -60,9 +60,8 @@ pub trait HierarchyQueryExt<'w, 's, D: QueryData, F: QueryFilter> {
/// # use bevy_hierarchy::prelude::*; /// # use bevy_hierarchy::prelude::*;
/// # #[derive(Component)] /// # #[derive(Component)]
/// # struct Marker; /// # struct Marker;
/// fn system(query: Query<Entity, With<Marker>>, children_query: Query<&Children>) { /// fn system(entity: Single<Entity, With<Marker>>, children_query: Query<&Children>) {
/// let entity = query.single(); /// for descendant in children_query.iter_descendants(*entity) {
/// for descendant in children_query.iter_descendants(entity) {
/// // Do something! /// // Do something!
/// } /// }
/// } /// }
@ -95,9 +94,8 @@ pub trait HierarchyQueryExt<'w, 's, D: QueryData, F: QueryFilter> {
/// # use bevy_hierarchy::prelude::*; /// # use bevy_hierarchy::prelude::*;
/// # #[derive(Component)] /// # #[derive(Component)]
/// # struct Marker; /// # struct Marker;
/// fn system(query: Query<Entity, With<Marker>>, parent_query: Query<&Parent>) { /// fn system(entity: Single<Entity, With<Marker>>, parent_query: Query<&Parent>) {
/// let entity = query.single(); /// for ancestor in parent_query.iter_ancestors(*entity) {
/// for ancestor in parent_query.iter_ancestors(entity) {
/// // Do something! /// // Do something!
/// } /// }
/// } /// }

View file

@ -11,11 +11,11 @@ fn main() {
} }
fn draw_cursor( fn draw_cursor(
camera_query: Query<(&Camera, &GlobalTransform)>, camera_query: Single<(&Camera, &GlobalTransform)>,
windows: Query<&Window>, windows: Query<&Window>,
mut gizmos: Gizmos, mut gizmos: Gizmos,
) { ) {
let (camera, camera_transform) = camera_query.single(); let (camera, camera_transform) = *camera_query;
let Ok(window) = windows.get_single() else { let Ok(window) = windows.get_single() else {
return; return;

View file

@ -71,18 +71,17 @@ fn setup(
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
fn update_bloom_settings( fn update_bloom_settings(
mut camera: Query<(Entity, Option<&mut Bloom>), With<Camera>>, camera: Single<(Entity, Option<&mut Bloom>), With<Camera>>,
mut text: Query<&mut Text>, mut text: Single<&mut Text>,
mut commands: Commands, mut commands: Commands,
keycode: Res<ButtonInput<KeyCode>>, keycode: Res<ButtonInput<KeyCode>>,
time: Res<Time>, time: Res<Time>,
) { ) {
let bloom = camera.single_mut(); let bloom = camera.into_inner();
let mut text = text.single_mut();
match bloom { match bloom {
(entity, Some(mut bloom)) => { (entity, Some(mut bloom)) => {
**text = "Bloom (Toggle: Space)\n".to_string(); text.0 = "Bloom (Toggle: Space)\n".to_string();
text.push_str(&format!("(Q/A) Intensity: {}\n", bloom.intensity)); text.push_str(&format!("(Q/A) Intensity: {}\n", bloom.intensity));
text.push_str(&format!( text.push_str(&format!(
"(W/S) Low-frequency boost: {}\n", "(W/S) Low-frequency boost: {}\n",
@ -173,7 +172,7 @@ fn update_bloom_settings(
} }
(entity, None) => { (entity, None) => {
**text = "Bloom: Off (Toggle: Space)".to_string(); text.0 = "Bloom: Off (Toggle: Space)".to_string();
if keycode.just_pressed(KeyCode::Space) { if keycode.just_pressed(KeyCode::Space) {
commands.entity(entity).insert(Bloom::default()); commands.entity(entity).insert(Bloom::default());

View file

@ -72,12 +72,11 @@ fn update_test_state(
state.set(next); state.set(next);
} }
fn update_text(mut text: Query<&mut Text>, cur_state: Res<State<Test>>) { fn update_text(mut text: Single<&mut Text>, cur_state: Res<State<Test>>) {
if !cur_state.is_changed() { if !cur_state.is_changed() {
return; return;
} }
let mut text = text.single_mut();
text.clear(); text.clear();
text.push_str("Intersection test:\n"); text.push_str("Intersection test:\n");

View file

@ -144,12 +144,11 @@ fn rotate(time: Res<Time>, mut transforms: Query<&mut Transform, With<Rotate>>)
/// Scales camera projection to fit the window (integer multiples only). /// Scales camera projection to fit the window (integer multiples only).
fn fit_canvas( fn fit_canvas(
mut resize_events: EventReader<WindowResized>, mut resize_events: EventReader<WindowResized>,
mut projections: Query<&mut OrthographicProjection, With<OuterCamera>>, mut projection: Single<&mut OrthographicProjection, With<OuterCamera>>,
) { ) {
for event in resize_events.read() { for event in resize_events.read() {
let h_scale = event.width / RES_WIDTH as f32; let h_scale = event.width / RES_WIDTH as f32;
let v_scale = event.height / RES_HEIGHT as f32; let v_scale = event.height / RES_HEIGHT as f32;
let mut projection = projections.single_mut();
projection.scaling_mode = ScalingMode::WindowSize(h_scale.min(v_scale).round()); projection.scaling_mode = ScalingMode::WindowSize(h_scale.min(v_scale).round());
} }
} }

View file

@ -102,9 +102,9 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
fn player_movement_system( fn player_movement_system(
time: Res<Time>, time: Res<Time>,
keyboard_input: Res<ButtonInput<KeyCode>>, keyboard_input: Res<ButtonInput<KeyCode>>,
mut query: Query<(&Player, &mut Transform)>, query: Single<(&Player, &mut Transform)>,
) { ) {
let (ship, mut transform) = query.single_mut(); let (ship, mut transform) = query.into_inner();
let mut rotation_factor = 0.0; let mut rotation_factor = 0.0;
let mut movement_factor = 0.0; let mut movement_factor = 0.0;
@ -143,9 +143,8 @@ fn player_movement_system(
/// Demonstrates snapping the enemy ship to face the player ship immediately. /// Demonstrates snapping the enemy ship to face the player ship immediately.
fn snap_to_player_system( fn snap_to_player_system(
mut query: Query<&mut Transform, (With<SnapToPlayer>, Without<Player>)>, mut query: Query<&mut Transform, (With<SnapToPlayer>, Without<Player>)>,
player_query: Query<&Transform, With<Player>>, player_transform: Single<&Transform, With<Player>>,
) { ) {
let player_transform = player_query.single();
// get the player translation in 2D // get the player translation in 2D
let player_translation = player_transform.translation.xy(); let player_translation = player_transform.translation.xy();
@ -186,9 +185,8 @@ fn snap_to_player_system(
fn rotate_to_player_system( fn rotate_to_player_system(
time: Res<Time>, time: Res<Time>,
mut query: Query<(&RotateToPlayer, &mut Transform), Without<Player>>, mut query: Query<(&RotateToPlayer, &mut Transform), Without<Player>>,
player_query: Query<&Transform, With<Player>>, player_transform: Single<&Transform, With<Player>>,
) { ) {
let player_transform = player_query.single();
// get the player translation in 2D // get the player translation in 2D
let player_translation = player_transform.translation.xy(); let player_translation = player_transform.translation.xy();

View file

@ -24,9 +24,7 @@ fn main() {
} }
// This system runs when the user clicks the left arrow key or right arrow key // This system runs when the user clicks the left arrow key or right arrow key
fn trigger_animation<S: Component>(mut query: Query<&mut AnimationConfig, With<S>>) { fn trigger_animation<S: Component>(mut animation: Single<&mut AnimationConfig, With<S>>) {
// we expect the Component of type S to be used as a marker Component by only a single entity
let mut animation = query.single_mut();
// we create a new timer when the animation is triggered // we create a new timer when the animation is triggered
animation.frame_timer = AnimationConfig::timer_from_fps(animation.fps); animation.frame_timer = AnimationConfig::timer_from_fps(animation.fps);
} }

View file

@ -104,9 +104,9 @@ fn update_colors(
keyboard_input: Res<ButtonInput<KeyCode>>, keyboard_input: Res<ButtonInput<KeyCode>>,
mut config: ResMut<Wireframe2dConfig>, mut config: ResMut<Wireframe2dConfig>,
mut wireframe_colors: Query<&mut Wireframe2dColor>, mut wireframe_colors: Query<&mut Wireframe2dColor>,
mut text: Query<&mut Text>, mut text: Single<&mut Text>,
) { ) {
**text.single_mut() = format!( text.0 = format!(
"Controls "Controls
--------------- ---------------
Z - Toggle global Z - Toggle global

View file

@ -11,15 +11,14 @@ fn main() {
} }
fn draw_cursor( fn draw_cursor(
camera_query: Query<(&Camera, &GlobalTransform)>, camera_query: Single<(&Camera, &GlobalTransform)>,
ground_query: Query<&GlobalTransform, With<Ground>>, ground: Single<&GlobalTransform, With<Ground>>,
windows: Query<&Window>, windows: Single<&Window>,
mut gizmos: Gizmos, mut gizmos: Gizmos,
) { ) {
let (camera, camera_transform) = camera_query.single(); let (camera, camera_transform) = *camera_query;
let ground = ground_query.single();
let Some(cursor_position) = windows.single().cursor_position() else { let Some(cursor_position) = windows.cursor_position() else {
return; return;
}; };

View file

@ -37,7 +37,7 @@ type TaaComponents = (
fn modify_aa( fn modify_aa(
keys: Res<ButtonInput<KeyCode>>, keys: Res<ButtonInput<KeyCode>>,
mut camera: Query< camera: Single<
( (
Entity, Entity,
Option<&mut Fxaa>, Option<&mut Fxaa>,
@ -49,7 +49,7 @@ fn modify_aa(
>, >,
mut commands: Commands, mut commands: Commands,
) { ) {
let (camera_entity, fxaa, smaa, taa, mut msaa) = camera.single_mut(); let (camera_entity, fxaa, smaa, taa, mut msaa) = camera.into_inner();
let mut camera = commands.entity(camera_entity); let mut camera = commands.entity(camera_entity);
// No AA // No AA
@ -177,7 +177,7 @@ fn modify_sharpening(
} }
fn update_ui( fn update_ui(
camera: Query< camera: Single<
( (
Option<&Fxaa>, Option<&Fxaa>,
Option<&Smaa>, Option<&Smaa>,
@ -187,12 +187,11 @@ fn update_ui(
), ),
With<Camera>, With<Camera>,
>, >,
mut ui: Query<&mut Text>, mut ui: Single<&mut Text>,
) { ) {
let (fxaa, smaa, taa, cas, msaa) = camera.single(); let (fxaa, smaa, taa, cas, msaa) = *camera;
let ui = &mut **ui.single_mut();
let ui = &mut ui.0;
*ui = "Antialias Method\n".to_string(); *ui = "Antialias Method\n".to_string();
draw_selectable_menu_item( draw_selectable_menu_item(

View file

@ -95,9 +95,7 @@ fn setup_instructions(mut commands: Commands) {
); );
} }
fn toggle_system(keycode: Res<ButtonInput<KeyCode>>, mut fog: Query<&mut DistanceFog>) { fn toggle_system(keycode: Res<ButtonInput<KeyCode>>, mut fog: Single<&mut DistanceFog>) {
let mut fog = fog.single_mut();
if keycode.just_pressed(KeyCode::Space) { if keycode.just_pressed(KeyCode::Space) {
let a = fog.color.alpha(); let a = fog.color.alpha();
fog.color.set_alpha(1.0 - a); fog.color.set_alpha(1.0 - a);

View file

@ -161,14 +161,14 @@ struct ExampleResources {
} }
fn example_control_system( fn example_control_system(
mut camera: Query<(&mut Transform, &mut AutoExposure), With<Camera3d>>, camera: Single<(&mut Transform, &mut AutoExposure), With<Camera3d>>,
mut display: Query<&mut Text, With<ExampleDisplay>>, mut display: Single<&mut Text, With<ExampleDisplay>>,
mut mask_image: Query<&mut Style, With<UiImage>>, mut mask_image: Single<&mut Style, With<UiImage>>,
time: Res<Time>, time: Res<Time>,
input: Res<ButtonInput<KeyCode>>, input: Res<ButtonInput<KeyCode>>,
resources: Res<ExampleResources>, resources: Res<ExampleResources>,
) { ) {
let (mut camera_transform, mut auto_exposure) = camera.single_mut(); let (mut camera_transform, mut auto_exposure) = camera.into_inner();
let rotation = if input.pressed(KeyCode::ArrowLeft) { let rotation = if input.pressed(KeyCode::ArrowLeft) {
time.delta_seconds() time.delta_seconds()
@ -198,14 +198,13 @@ fn example_control_system(
}; };
} }
mask_image.single_mut().display = if input.pressed(KeyCode::KeyV) { mask_image.display = if input.pressed(KeyCode::KeyV) {
Display::Flex Display::Flex
} else { } else {
Display::None Display::None
}; };
let mut display = display.single_mut(); display.0 = format!(
**display = format!(
"Compensation Curve: {}\nMetering Mask: {}", "Compensation Curve: {}\nMetering Mask: {}",
if auto_exposure.compensation_curve == resources.basic_compensation_curve { if auto_exposure.compensation_curve == resources.basic_compensation_curve {
"Enabled" "Enabled"

View file

@ -254,9 +254,9 @@ impl Default for ExampleState {
fn example_control_system( fn example_control_system(
mut materials: ResMut<Assets<StandardMaterial>>, mut materials: ResMut<Assets<StandardMaterial>>,
controllable: Query<(&MeshMaterial3d<StandardMaterial>, &ExampleControls)>, controllable: Query<(&MeshMaterial3d<StandardMaterial>, &ExampleControls)>,
mut camera: Query<(&mut Camera, &mut Transform, &GlobalTransform), With<Camera3d>>, camera: Single<(&mut Camera, &mut Transform, &GlobalTransform), With<Camera3d>>,
mut labels: Query<(&mut Style, &ExampleLabel)>, mut labels: Query<(&mut Style, &ExampleLabel)>,
mut display: Query<&mut Text, With<ExampleDisplay>>, mut display: Single<&mut Text, With<ExampleDisplay>>,
labelled: Query<&GlobalTransform>, labelled: Query<&GlobalTransform>,
mut state: Local<ExampleState>, mut state: Local<ExampleState>,
time: Res<Time>, time: Res<Time>,
@ -294,7 +294,7 @@ fn example_control_system(
} }
} }
let (mut camera, mut camera_transform, camera_global_transform) = camera.single_mut(); let (mut camera, mut camera_transform, camera_global_transform) = camera.into_inner();
if input.just_pressed(KeyCode::KeyH) { if input.just_pressed(KeyCode::KeyH) {
camera.hdr = !camera.hdr; camera.hdr = !camera.hdr;
@ -321,8 +321,7 @@ fn example_control_system(
style.left = Val::Px(viewport_position.x); style.left = Val::Px(viewport_position.x);
} }
let mut display = display.single_mut(); display.0 = format!(
**display = format!(
" HDR: {}\nAlpha: {:.2}", " HDR: {}\nAlpha: {:.2}",
if camera.hdr { "ON " } else { "OFF" }, if camera.hdr { "ON " } else { "OFF" },
state.alpha state.alpha

View file

@ -98,18 +98,17 @@ fn setup_scene(
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
fn update_bloom_settings( fn update_bloom_settings(
mut camera: Query<(Entity, Option<&mut Bloom>), With<Camera>>, camera: Single<(Entity, Option<&mut Bloom>), With<Camera>>,
mut text: Query<&mut Text>, mut text: Single<&mut Text>,
mut commands: Commands, mut commands: Commands,
keycode: Res<ButtonInput<KeyCode>>, keycode: Res<ButtonInput<KeyCode>>,
time: Res<Time>, time: Res<Time>,
) { ) {
let bloom = camera.single_mut(); let bloom = camera.into_inner();
let mut text = text.single_mut();
match bloom { match bloom {
(entity, Some(mut bloom)) => { (entity, Some(mut bloom)) => {
**text = "Bloom (Toggle: Space)\n".to_string(); text.0 = "Bloom (Toggle: Space)\n".to_string();
text.push_str(&format!("(Q/A) Intensity: {}\n", bloom.intensity)); text.push_str(&format!("(Q/A) Intensity: {}\n", bloom.intensity));
text.push_str(&format!( text.push_str(&format!(
"(W/S) Low-frequency boost: {}\n", "(W/S) Low-frequency boost: {}\n",
@ -200,7 +199,7 @@ fn update_bloom_settings(
} }
(entity, None) => { (entity, None) => {
**text = "Bloom: Off (Toggle: Space)".to_string(); text.0 = "Bloom: Off (Toggle: Space)".to_string();
if keycode.just_pressed(KeyCode::Space) { if keycode.just_pressed(KeyCode::Space) {
commands.entity(entity).insert(Bloom::NATURAL); commands.entity(entity).insert(Bloom::NATURAL);

View file

@ -560,13 +560,13 @@ fn update_ui_state(
&ColorGradingOptionWidget, &ColorGradingOptionWidget,
)>, )>,
button_text: Query<(Entity, &ColorGradingOptionWidget), (With<Text>, Without<HelpText>)>, button_text: Query<(Entity, &ColorGradingOptionWidget), (With<Text>, Without<HelpText>)>,
help_text: Query<Entity, With<HelpText>>, help_text: Single<Entity, With<HelpText>>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
cameras: Query<Ref<ColorGrading>>, cameras: Single<Ref<ColorGrading>>,
currently_selected_option: Res<SelectedColorGradingOption>, currently_selected_option: Res<SelectedColorGradingOption>,
) { ) {
// Exit early if the UI didn't change // Exit early if the UI didn't change
if !currently_selected_option.is_changed() && !cameras.single().is_changed() { if !currently_selected_option.is_changed() && !cameras.is_changed() {
return; return;
} }
@ -581,12 +581,7 @@ fn update_ui_state(
} }
} }
let value_label = cameras.iter().next().map(|color_grading| { let value_label = format!("{:.3}", currently_selected_option.get(cameras.as_ref()));
format!(
"{:.3}",
currently_selected_option.get(color_grading.as_ref())
)
});
// Update the buttons. // Update the buttons.
for (entity, widget) in button_text.iter() { for (entity, widget) in button_text.iter() {
@ -606,16 +601,14 @@ fn update_ui_state(
if widget.widget_type == ColorGradingOptionWidgetType::Value if widget.widget_type == ColorGradingOptionWidgetType::Value
&& *currently_selected_option == widget.option && *currently_selected_option == widget.option
{ {
if let Some(ref value_label) = value_label { writer.for_each_text(entity, |mut text| {
writer.for_each_text(entity, |mut text| { text.clone_from(&value_label);
text.clone_from(value_label); });
});
}
} }
} }
// Update the help text. // Update the help text.
*writer.text(help_text.single(), 0) = create_help_text(&currently_selected_option); *writer.text(*help_text, 0) = create_help_text(&currently_selected_option);
} }
/// Creates the help text at the top left of the window. /// Creates the help text at the top left of the window.
@ -626,7 +619,7 @@ fn create_help_text(currently_selected_option: &SelectedColorGradingOption) -> S
/// Processes keyboard input to change the value of the currently-selected color /// Processes keyboard input to change the value of the currently-selected color
/// grading option. /// grading option.
fn adjust_color_grading_option( fn adjust_color_grading_option(
mut cameras: Query<&mut ColorGrading>, mut color_grading: Single<&mut ColorGrading>,
input: Res<ButtonInput<KeyCode>>, input: Res<ButtonInput<KeyCode>>,
currently_selected_option: Res<SelectedColorGradingOption>, currently_selected_option: Res<SelectedColorGradingOption>,
) { ) {
@ -639,8 +632,7 @@ fn adjust_color_grading_option(
} }
if delta != 0.0 { if delta != 0.0 {
let mut color_grading = cameras.single_mut(); let new_value = currently_selected_option.get(color_grading.as_ref()) + delta;
let new_value = currently_selected_option.get(&color_grading) + delta;
currently_selected_option.set(&mut color_grading, new_value); currently_selected_option.set(&mut color_grading, new_value);
} }
} }

View file

@ -282,7 +282,7 @@ enum DefaultRenderMode {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn switch_mode( fn switch_mode(
mut text: Query<&mut Text>, mut text: Single<&mut Text>,
mut commands: Commands, mut commands: Commands,
keys: Res<ButtonInput<KeyCode>>, keys: Res<ButtonInput<KeyCode>>,
mut default_opaque_renderer_method: ResMut<DefaultOpaqueRendererMethod>, mut default_opaque_renderer_method: ResMut<DefaultOpaqueRendererMethod>,
@ -292,8 +292,6 @@ fn switch_mode(
mut hide_ui: Local<bool>, mut hide_ui: Local<bool>,
mut mode: Local<DefaultRenderMode>, mut mode: Local<DefaultRenderMode>,
) { ) {
let mut text = text.single_mut();
text.clear(); text.clear();
if keys.just_pressed(KeyCode::Space) { if keys.just_pressed(KeyCode::Space) {

View file

@ -128,16 +128,15 @@ fn setup_instructions(mut commands: Commands) {
} }
fn update_system( fn update_system(
mut camera: Query<(&mut DistanceFog, &mut Transform)>, camera: Single<(&mut DistanceFog, &mut Transform)>,
mut text: Query<&mut Text>, mut text: Single<&mut Text>,
time: Res<Time>, time: Res<Time>,
keycode: Res<ButtonInput<KeyCode>>, keycode: Res<ButtonInput<KeyCode>>,
) { ) {
let now = time.elapsed_seconds(); let now = time.elapsed_seconds();
let delta = time.delta_seconds(); let delta = time.delta_seconds();
let (mut fog, mut transform) = camera.single_mut(); let (mut fog, mut transform) = camera.into_inner();
let mut text = text.single_mut();
// Orbit camera around pyramid // Orbit camera around pyramid
let orbit_scale = 8.0 + ops::sin(now / 10.0) * 7.0; let orbit_scale = 8.0 + ops::sin(now / 10.0) * 7.0;
@ -149,7 +148,7 @@ fn update_system(
.looking_at(Vec3::ZERO, Vec3::Y); .looking_at(Vec3::ZERO, Vec3::Y);
// Fog Information // Fog Information
**text = format!("Fog Falloff: {:?}\nFog Color: {:?}", fog.falloff, fog.color); text.0 = format!("Fog Falloff: {:?}\nFog Color: {:?}", fog.falloff, fog.color);
// Fog Falloff Mode Switching // Fog Falloff Mode Switching
text.push_str("\n\n1 / 2 / 3 - Fog Falloff Mode"); text.push_str("\n\n1 / 2 / 3 - Fog Falloff Mode");

View file

@ -253,12 +253,12 @@ fn setup(
fn update_exposure( fn update_exposure(
key_input: Res<ButtonInput<KeyCode>>, key_input: Res<ButtonInput<KeyCode>>,
mut parameters: ResMut<Parameters>, mut parameters: ResMut<Parameters>,
mut exposure: Query<&mut Exposure>, mut exposure: Single<&mut Exposure>,
text: Query<Entity, With<Text>>, text: Single<Entity, With<Text>>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
) { ) {
// TODO: Clamp values to a reasonable range // TODO: Clamp values to a reasonable range
let entity = text.single(); let entity = *text;
if key_input.just_pressed(KeyCode::Digit2) { if key_input.just_pressed(KeyCode::Digit2) {
parameters.aperture_f_stops *= 2.0; parameters.aperture_f_stops *= 2.0;
} else if key_input.just_pressed(KeyCode::Digit1) { } else if key_input.just_pressed(KeyCode::Digit1) {
@ -285,7 +285,7 @@ fn update_exposure(
); );
*writer.text(entity, 3) = format!("Sensitivity: ISO {:.0}\n", parameters.sensitivity_iso); *writer.text(entity, 3) = format!("Sensitivity: ISO {:.0}\n", parameters.sensitivity_iso);
*exposure.single_mut() = Exposure::from_physical_camera(**parameters); **exposure = Exposure::from_physical_camera(**parameters);
} }
fn animate_light_direction( fn animate_light_direction(

View file

@ -58,7 +58,7 @@ fn check_for_gltf_extras(
Option<&GltfMeshExtras>, Option<&GltfMeshExtras>,
Option<&GltfMaterialExtras>, Option<&GltfMaterialExtras>,
)>, )>,
mut display: Query<&mut Text, With<ExampleDisplay>>, mut display: Single<&mut Text, With<ExampleDisplay>>,
) { ) {
let mut gltf_extra_infos_lines: Vec<String> = vec![]; let mut gltf_extra_infos_lines: Vec<String> = vec![];
@ -86,6 +86,6 @@ fn check_for_gltf_extras(
); );
gltf_extra_infos_lines.push(formatted_extras); gltf_extra_infos_lines.push(formatted_extras);
} }
**display.single_mut() = gltf_extra_infos_lines.join("\n"); display.0 = gltf_extra_infos_lines.join("\n");
} }
} }

View file

@ -251,13 +251,12 @@ fn setup_ui(mut commands: Commands) {
} }
fn keyboard_inputs( fn keyboard_inputs(
mut motion_blur: Query<&mut MotionBlur>, mut motion_blur: Single<&mut MotionBlur>,
presses: Res<ButtonInput<KeyCode>>, presses: Res<ButtonInput<KeyCode>>,
text: Query<Entity, With<Text>>, text: Single<Entity, With<Text>>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
mut camera: ResMut<CameraMode>, mut camera: ResMut<CameraMode>,
) { ) {
let mut motion_blur = motion_blur.single_mut();
if presses.just_pressed(KeyCode::Digit1) { if presses.just_pressed(KeyCode::Digit1) {
motion_blur.shutter_angle -= 0.25; motion_blur.shutter_angle -= 0.25;
} else if presses.just_pressed(KeyCode::Digit2) { } else if presses.just_pressed(KeyCode::Digit2) {
@ -274,7 +273,7 @@ fn keyboard_inputs(
} }
motion_blur.shutter_angle = motion_blur.shutter_angle.clamp(0.0, 1.0); motion_blur.shutter_angle = motion_blur.shutter_angle.clamp(0.0, 1.0);
motion_blur.samples = motion_blur.samples.clamp(0, 64); motion_blur.samples = motion_blur.samples.clamp(0, 64);
let entity = text.single(); let entity = *text;
*writer.text(entity, 1) = format!("Shutter angle: {:.2}\n", motion_blur.shutter_angle); *writer.text(entity, 1) = format!("Shutter angle: {:.2}\n", motion_blur.shutter_angle);
*writer.text(entity, 2) = format!("Samples: {:.5}\n", motion_blur.samples); *writer.text(entity, 2) = format!("Samples: {:.5}\n", motion_blur.samples);
} }
@ -326,12 +325,11 @@ fn move_cars(
} }
fn move_camera( fn move_camera(
mut camera: Query<(&mut Transform, &mut Projection), Without<CameraTracked>>, camera: Single<(&mut Transform, &mut Projection), Without<CameraTracked>>,
tracked: Query<&Transform, With<CameraTracked>>, tracked: Single<&Transform, With<CameraTracked>>,
mode: Res<CameraMode>, mode: Res<CameraMode>,
) { ) {
let tracked = tracked.single(); let (mut transform, mut projection) = camera.into_inner();
let (mut transform, mut projection) = camera.single_mut();
match *mode { match *mode {
CameraMode::Track => { CameraMode::Track => {
transform.look_at(tracked.translation, Vec3::Y); transform.look_at(tracked.translation, Vec3::Y);
@ -343,7 +341,7 @@ fn move_camera(
CameraMode::Chase => { CameraMode::Chase => {
transform.translation = transform.translation =
tracked.translation + Vec3::new(0.0, 0.15, 0.0) + tracked.back() * 0.6; tracked.translation + Vec3::new(0.0, 0.15, 0.0) + tracked.back() * 0.6;
transform.look_to(*tracked.forward(), Vec3::Y); transform.look_to(tracked.forward(), Vec3::Y);
if let Projection::Perspective(perspective) = &mut *projection { if let Projection::Perspective(perspective) = &mut *projection {
perspective.fov = 1.0; perspective.fov = 1.0;
} }

View file

@ -66,11 +66,11 @@ fn toggle_oit(
mut commands: Commands, mut commands: Commands,
text: Single<Entity, With<Text>>, text: Single<Entity, With<Text>>,
keyboard_input: Res<ButtonInput<KeyCode>>, keyboard_input: Res<ButtonInput<KeyCode>>,
q: Query<(Entity, Has<OrderIndependentTransparencySettings>), With<Camera3d>>, q: Single<(Entity, Has<OrderIndependentTransparencySettings>), With<Camera3d>>,
mut text_writer: UiTextWriter, mut text_writer: UiTextWriter,
) { ) {
if keyboard_input.just_pressed(KeyCode::KeyT) { if keyboard_input.just_pressed(KeyCode::KeyT) {
let (e, has_oit) = q.single(); let (e, has_oit) = *q;
*text_writer.text(*text, 2) = if has_oit { *text_writer.text(*text, 2) = if has_oit {
// Removing the component will completely disable OIT for this camera // Removing the component will completely disable OIT for this camera
commands commands

View file

@ -81,7 +81,7 @@ fn update_parallax_depth_scale(
mut target_depth: Local<TargetDepth>, mut target_depth: Local<TargetDepth>,
mut depth_update: Local<bool>, mut depth_update: Local<bool>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
text: Query<Entity, With<Text>>, text: Single<Entity, With<Text>>,
) { ) {
if input.just_pressed(KeyCode::Digit1) { if input.just_pressed(KeyCode::Digit1) {
target_depth.0 -= DEPTH_UPDATE_STEP; target_depth.0 -= DEPTH_UPDATE_STEP;
@ -98,7 +98,7 @@ fn update_parallax_depth_scale(
let current_depth = mat.parallax_depth_scale; let current_depth = mat.parallax_depth_scale;
let new_depth = current_depth.lerp(target_depth.0, DEPTH_CHANGE_RATE); let new_depth = current_depth.lerp(target_depth.0, DEPTH_CHANGE_RATE);
mat.parallax_depth_scale = new_depth; mat.parallax_depth_scale = new_depth;
*writer.text(text.single(), 1) = format!("Parallax depth scale: {new_depth:.5}\n"); *writer.text(*text, 1) = format!("Parallax depth scale: {new_depth:.5}\n");
if (new_depth - current_depth).abs() <= 0.000000001 { if (new_depth - current_depth).abs() <= 0.000000001 {
*depth_update = false; *depth_update = false;
} }
@ -109,7 +109,7 @@ fn update_parallax_depth_scale(
fn switch_method( fn switch_method(
input: Res<ButtonInput<KeyCode>>, input: Res<ButtonInput<KeyCode>>,
mut materials: ResMut<Assets<StandardMaterial>>, mut materials: ResMut<Assets<StandardMaterial>>,
text: Query<Entity, With<Text>>, text: Single<Entity, With<Text>>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
mut current: Local<CurrentMethod>, mut current: Local<CurrentMethod>,
) { ) {
@ -118,7 +118,7 @@ fn switch_method(
} else { } else {
return; return;
} }
let text_entity = text.single(); let text_entity = *text;
*writer.text(text_entity, 3) = format!("Method: {}\n", *current); *writer.text(text_entity, 3) = format!("Method: {}\n", *current);
for (_, mat) in materials.iter_mut() { for (_, mat) in materials.iter_mut() {
@ -130,7 +130,7 @@ fn update_parallax_layers(
input: Res<ButtonInput<KeyCode>>, input: Res<ButtonInput<KeyCode>>,
mut materials: ResMut<Assets<StandardMaterial>>, mut materials: ResMut<Assets<StandardMaterial>>,
mut target_layers: Local<TargetLayers>, mut target_layers: Local<TargetLayers>,
text: Query<Entity, With<Text>>, text: Single<Entity, With<Text>>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
) { ) {
if input.just_pressed(KeyCode::Digit3) { if input.just_pressed(KeyCode::Digit3) {
@ -142,7 +142,7 @@ fn update_parallax_layers(
return; return;
} }
let layer_count = ops::exp2(target_layers.0); let layer_count = ops::exp2(target_layers.0);
let text_entity = text.single(); let text_entity = *text;
*writer.text(text_entity, 2) = format!("Layers: {layer_count:.0}\n"); *writer.text(text_entity, 2) = format!("Layers: {layer_count:.0}\n");
for (_, mat) in materials.iter_mut() { for (_, mat) in materials.iter_mut() {
@ -183,11 +183,10 @@ const CAMERA_POSITIONS: &[Transform] = &[
]; ];
fn move_camera( fn move_camera(
mut camera: Query<&mut Transform, With<CameraController>>, mut camera: Single<&mut Transform, With<CameraController>>,
mut current_view: Local<usize>, mut current_view: Local<usize>,
button: Res<ButtonInput<MouseButton>>, button: Res<ButtonInput<MouseButton>>,
) { ) {
let mut camera = camera.single_mut();
if button.just_pressed(MouseButton::Left) { if button.just_pressed(MouseButton::Left) {
*current_view = (*current_view + 1) % CAMERA_POSITIONS.len(); *current_view = (*current_view + 1) % CAMERA_POSITIONS.len();
} }

View file

@ -152,13 +152,13 @@ fn toggle_light(
input: Res<ButtonInput<KeyCode>>, input: Res<ButtonInput<KeyCode>>,
mut point_lights: Query<&mut PointLight>, mut point_lights: Query<&mut PointLight>,
mut directional_lights: Query<&mut DirectionalLight>, mut directional_lights: Query<&mut DirectionalLight>,
example_text: Query<Entity, With<Text>>, example_text: Single<Entity, With<Text>>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
) { ) {
if input.just_pressed(KeyCode::KeyL) { if input.just_pressed(KeyCode::KeyL) {
for mut light in &mut point_lights { for mut light in &mut point_lights {
light.intensity = if light.intensity == 0.0 { light.intensity = if light.intensity == 0.0 {
*writer.text(example_text.single(), 4) = "PointLight".to_string(); *writer.text(*example_text, 4) = "PointLight".to_string();
100000000.0 100000000.0
} else { } else {
0.0 0.0
@ -166,7 +166,7 @@ fn toggle_light(
} }
for mut light in &mut directional_lights { for mut light in &mut directional_lights {
light.illuminance = if light.illuminance == 0.0 { light.illuminance = if light.illuminance == 0.0 {
*writer.text(example_text.single(), 4) = "DirectionalLight".to_string(); *writer.text(*example_text, 4) = "DirectionalLight".to_string();
100000.0 100000.0
} else { } else {
0.0 0.0
@ -178,7 +178,7 @@ fn toggle_light(
fn adjust_light_position( fn adjust_light_position(
input: Res<ButtonInput<KeyCode>>, input: Res<ButtonInput<KeyCode>>,
mut lights: Query<&mut Transform, With<Lights>>, mut lights: Query<&mut Transform, With<Lights>>,
example_text: Query<Entity, With<Text>>, example_text: Single<Entity, With<Text>>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
) { ) {
let mut offset = Vec3::ZERO; let mut offset = Vec3::ZERO;
@ -201,7 +201,7 @@ fn adjust_light_position(
offset.y += 1.0; offset.y += 1.0;
} }
if offset != Vec3::ZERO { if offset != Vec3::ZERO {
let example_text = example_text.single(); let example_text = *example_text;
for mut light in &mut lights { for mut light in &mut lights {
light.translation += offset; light.translation += offset;
light.look_at(Vec3::ZERO, Vec3::Y); light.look_at(Vec3::ZERO, Vec3::Y);
@ -215,7 +215,7 @@ fn adjust_light_position(
fn cycle_filter_methods( fn cycle_filter_methods(
input: Res<ButtonInput<KeyCode>>, input: Res<ButtonInput<KeyCode>>,
mut filter_methods: Query<&mut ShadowFilteringMethod>, mut filter_methods: Query<&mut ShadowFilteringMethod>,
example_text: Query<Entity, With<Text>>, example_text: Single<Entity, With<Text>>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
) { ) {
if input.just_pressed(KeyCode::KeyF) { if input.just_pressed(KeyCode::KeyF) {
@ -235,7 +235,7 @@ fn cycle_filter_methods(
ShadowFilteringMethod::Hardware2x2 ShadowFilteringMethod::Hardware2x2
} }
}; };
*writer.text(example_text.single(), 7) = filter_method_string; *writer.text(*example_text, 7) = filter_method_string;
} }
} }
} }
@ -243,7 +243,7 @@ fn cycle_filter_methods(
fn adjust_point_light_biases( fn adjust_point_light_biases(
input: Res<ButtonInput<KeyCode>>, input: Res<ButtonInput<KeyCode>>,
mut query: Query<&mut PointLight>, mut query: Query<&mut PointLight>,
example_text: Query<Entity, With<Text>>, example_text: Single<Entity, With<Text>>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
) { ) {
let depth_bias_step_size = 0.01; let depth_bias_step_size = 0.01;
@ -270,15 +270,15 @@ fn adjust_point_light_biases(
light.shadow_normal_bias = 0.0; light.shadow_normal_bias = 0.0;
} }
*writer.text(example_text.single(), 10) = format!("{:.2}", light.shadow_depth_bias); *writer.text(*example_text, 10) = format!("{:.2}", light.shadow_depth_bias);
*writer.text(example_text.single(), 13) = format!("{:.1}", light.shadow_normal_bias); *writer.text(*example_text, 13) = format!("{:.1}", light.shadow_normal_bias);
} }
} }
fn adjust_directional_light_biases( fn adjust_directional_light_biases(
input: Res<ButtonInput<KeyCode>>, input: Res<ButtonInput<KeyCode>>,
mut query: Query<&mut DirectionalLight>, mut query: Query<&mut DirectionalLight>,
example_text: Query<Entity, With<Text>>, example_text: Single<Entity, With<Text>>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
) { ) {
let depth_bias_step_size = 0.01; let depth_bias_step_size = 0.01;
@ -305,7 +305,7 @@ fn adjust_directional_light_biases(
light.shadow_normal_bias = 0.0; light.shadow_normal_bias = 0.0;
} }
*writer.text(example_text.single(), 16) = format!("{:.2}", light.shadow_depth_bias); *writer.text(*example_text, 16) = format!("{:.2}", light.shadow_depth_bias);
*writer.text(example_text.single(), 19) = format!("{:.1}", light.shadow_normal_bias); *writer.text(*example_text, 19) = format!("{:.1}", light.shadow_normal_bias);
} }
} }

View file

@ -189,11 +189,10 @@ fn movement(
} }
fn rotation( fn rotation(
mut query: Query<&mut Transform, With<Camera>>, mut transform: Single<&mut Transform, With<Camera>>,
input: Res<ButtonInput<KeyCode>>, input: Res<ButtonInput<KeyCode>>,
time: Res<Time>, time: Res<Time>,
) { ) {
let mut transform = query.single_mut();
let delta = time.delta_seconds(); let delta = time.delta_seconds();
if input.pressed(KeyCode::ArrowLeft) { if input.pressed(KeyCode::ArrowLeft) {

View file

@ -90,7 +90,7 @@ fn setup(
} }
fn update( fn update(
camera: Query< camera: Single<
( (
Entity, Entity,
Option<&ScreenSpaceAmbientOcclusion>, Option<&ScreenSpaceAmbientOcclusion>,
@ -98,16 +98,15 @@ fn update(
), ),
With<Camera>, With<Camera>,
>, >,
mut text: Query<&mut Text>, mut text: Single<&mut Text>,
mut sphere: Query<&mut Transform, With<SphereMarker>>, mut sphere: Single<&mut Transform, With<SphereMarker>>,
mut commands: Commands, mut commands: Commands,
keycode: Res<ButtonInput<KeyCode>>, keycode: Res<ButtonInput<KeyCode>>,
time: Res<Time>, time: Res<Time>,
) { ) {
let mut sphere = sphere.single_mut();
sphere.translation.y = ops::sin(time.elapsed_seconds() / 1.7) * 0.7; sphere.translation.y = ops::sin(time.elapsed_seconds() / 1.7) * 0.7;
let (camera_entity, ssao, temporal_jitter) = camera.single(); let (camera_entity, ssao, temporal_jitter) = *camera;
let current_ssao = ssao.cloned().unwrap_or_default(); let current_ssao = ssao.cloned().unwrap_or_default();
let mut commands = commands.entity(camera_entity); let mut commands = commands.entity(camera_entity);
@ -166,7 +165,6 @@ fn update(
} }
} }
let mut text = text.single_mut();
text.clear(); text.clear();
let (o, l, m, h, u) = match ssao.map(|s| s.quality_level) { let (o, l, m, h, u) = match ssao.map(|s| s.quality_level) {

View file

@ -285,34 +285,31 @@ fn toggle_scene(
fn toggle_tonemapping_method( fn toggle_tonemapping_method(
keys: Res<ButtonInput<KeyCode>>, keys: Res<ButtonInput<KeyCode>>,
mut tonemapping: Query<&mut Tonemapping>, mut tonemapping: Single<&mut Tonemapping>,
mut color_grading: Query<&mut ColorGrading>, mut color_grading: Single<&mut ColorGrading>,
per_method_settings: Res<PerMethodSettings>, per_method_settings: Res<PerMethodSettings>,
) { ) {
let mut method = tonemapping.single_mut();
let mut color_grading = color_grading.single_mut();
if keys.just_pressed(KeyCode::Digit1) { if keys.just_pressed(KeyCode::Digit1) {
*method = Tonemapping::None; **tonemapping = Tonemapping::None;
} else if keys.just_pressed(KeyCode::Digit2) { } else if keys.just_pressed(KeyCode::Digit2) {
*method = Tonemapping::Reinhard; **tonemapping = Tonemapping::Reinhard;
} else if keys.just_pressed(KeyCode::Digit3) { } else if keys.just_pressed(KeyCode::Digit3) {
*method = Tonemapping::ReinhardLuminance; **tonemapping = Tonemapping::ReinhardLuminance;
} else if keys.just_pressed(KeyCode::Digit4) { } else if keys.just_pressed(KeyCode::Digit4) {
*method = Tonemapping::AcesFitted; **tonemapping = Tonemapping::AcesFitted;
} else if keys.just_pressed(KeyCode::Digit5) { } else if keys.just_pressed(KeyCode::Digit5) {
*method = Tonemapping::AgX; **tonemapping = Tonemapping::AgX;
} else if keys.just_pressed(KeyCode::Digit6) { } else if keys.just_pressed(KeyCode::Digit6) {
*method = Tonemapping::SomewhatBoringDisplayTransform; **tonemapping = Tonemapping::SomewhatBoringDisplayTransform;
} else if keys.just_pressed(KeyCode::Digit7) { } else if keys.just_pressed(KeyCode::Digit7) {
*method = Tonemapping::TonyMcMapface; **tonemapping = Tonemapping::TonyMcMapface;
} else if keys.just_pressed(KeyCode::Digit8) { } else if keys.just_pressed(KeyCode::Digit8) {
*method = Tonemapping::BlenderFilmic; **tonemapping = Tonemapping::BlenderFilmic;
} }
*color_grading = (*per_method_settings **color_grading = (*per_method_settings
.settings .settings
.get::<Tonemapping>(&method) .get::<Tonemapping>(&tonemapping)
.as_ref() .as_ref()
.unwrap()) .unwrap())
.clone(); .clone();
@ -337,12 +334,11 @@ fn update_color_grading_settings(
keys: Res<ButtonInput<KeyCode>>, keys: Res<ButtonInput<KeyCode>>,
time: Res<Time>, time: Res<Time>,
mut per_method_settings: ResMut<PerMethodSettings>, mut per_method_settings: ResMut<PerMethodSettings>,
tonemapping: Query<&Tonemapping>, tonemapping: Single<&Tonemapping>,
current_scene: Res<CurrentScene>, current_scene: Res<CurrentScene>,
mut selected_parameter: ResMut<SelectedParameter>, mut selected_parameter: ResMut<SelectedParameter>,
) { ) {
let method = tonemapping.single(); let color_grading = per_method_settings.settings.get_mut(*tonemapping).unwrap();
let color_grading = per_method_settings.settings.get_mut(method).unwrap();
let mut dt = time.delta_seconds() * 0.25; let mut dt = time.delta_seconds() * 0.25;
if keys.pressed(KeyCode::ArrowLeft) { if keys.pressed(KeyCode::ArrowLeft) {
dt = -dt; dt = -dt;
@ -390,8 +386,8 @@ fn update_color_grading_settings(
} }
fn update_ui( fn update_ui(
mut text_query: Query<&mut Text, Without<SceneNumber>>, mut text_query: Single<&mut Text, Without<SceneNumber>>,
settings: Query<(&Tonemapping, &ColorGrading)>, settings: Single<(&Tonemapping, &ColorGrading)>,
current_scene: Res<CurrentScene>, current_scene: Res<CurrentScene>,
selected_parameter: Res<SelectedParameter>, selected_parameter: Res<SelectedParameter>,
mut hide_ui: Local<bool>, mut hide_ui: Local<bool>,
@ -401,21 +397,19 @@ fn update_ui(
*hide_ui = !*hide_ui; *hide_ui = !*hide_ui;
} }
let old_text = text_query.single();
if *hide_ui { if *hide_ui {
if !old_text.is_empty() { if !text_query.is_empty() {
// single_mut() always triggers change detection, // single_mut() always triggers change detection,
// so only access if text actually needs changing // so only access if text actually needs changing
text_query.single_mut().clear(); text_query.clear();
} }
return; return;
} }
let (tonemapping, color_grading) = settings.single(); let (tonemapping, color_grading) = *settings;
let tonemapping = *tonemapping; let tonemapping = *tonemapping;
let mut text = String::with_capacity(old_text.len()); let mut text = String::with_capacity(text_query.len());
let scn = current_scene.0; let scn = current_scene.0;
text.push_str("(H) Hide UI\n\n"); text.push_str("(H) Hide UI\n\n");
@ -529,10 +523,10 @@ fn update_ui(
text.push_str("(Enter) Reset all to scene recommendation\n"); text.push_str("(Enter) Reset all to scene recommendation\n");
} }
if text != old_text.as_str() { if text != text_query.as_str() {
// single_mut() always triggers change detection, // single_mut() always triggers change detection,
// so only access if text actually changed // so only access if text actually changed
**text_query.single_mut() = text; text_query.0 = text;
} }
} }

View file

@ -385,7 +385,7 @@ fn example_control_system(
mut commands: Commands, mut commands: Commands,
mut materials: ResMut<Assets<StandardMaterial>>, mut materials: ResMut<Assets<StandardMaterial>>,
controllable: Query<(&MeshMaterial3d<StandardMaterial>, &ExampleControls)>, controllable: Query<(&MeshMaterial3d<StandardMaterial>, &ExampleControls)>,
mut camera: Query< camera: Single<
( (
Entity, Entity,
&mut Camera, &mut Camera,
@ -396,7 +396,7 @@ fn example_control_system(
), ),
With<Camera3d>, With<Camera3d>,
>, >,
mut display: Query<&mut Text, With<ExampleDisplay>>, mut display: Single<&mut Text, With<ExampleDisplay>>,
mut state: Local<ExampleState>, mut state: Local<ExampleState>,
time: Res<Time>, time: Res<Time>,
input: Res<ButtonInput<KeyCode>>, input: Res<ButtonInput<KeyCode>>,
@ -466,7 +466,7 @@ fn example_control_system(
mut camera_transform, mut camera_transform,
depth_prepass, depth_prepass,
temporal_jitter, temporal_jitter,
) = camera.single_mut(); ) = camera.into_inner();
if input.just_pressed(KeyCode::KeyH) { if input.just_pressed(KeyCode::KeyH) {
camera.hdr = !camera.hdr; camera.hdr = !camera.hdr;
@ -548,7 +548,7 @@ fn example_control_system(
Quat::from_euler(EulerRot::XYZ, 0.0, rotation, 0.0), Quat::from_euler(EulerRot::XYZ, 0.0, rotation, 0.0),
); );
**display.single_mut() = format!( display.0 = format!(
concat!( concat!(
" J / K / L / ; Screen Space Specular Transmissive Quality: {:?}\n", " J / K / L / ; Screen Space Specular Transmissive Quality: {:?}\n",
" O / P Screen Space Specular Transmissive Steps: {}\n", " O / P Screen Space Specular Transmissive Steps: {}\n",
@ -599,20 +599,19 @@ fn example_control_system(
} }
fn flicker_system( fn flicker_system(
mut flame: Query<&mut Transform, (With<Flicker>, With<Mesh3d>)>, mut flame: Single<&mut Transform, (With<Flicker>, With<Mesh3d>)>,
mut light: Query<(&mut PointLight, &mut Transform), (With<Flicker>, Without<Mesh3d>)>, light: Single<(&mut PointLight, &mut Transform), (With<Flicker>, Without<Mesh3d>)>,
time: Res<Time>, time: Res<Time>,
) { ) {
let s = time.elapsed_seconds(); let s = time.elapsed_seconds();
let a = ops::cos(s * 6.0) * 0.0125 + ops::cos(s * 4.0) * 0.025; let a = ops::cos(s * 6.0) * 0.0125 + ops::cos(s * 4.0) * 0.025;
let b = ops::cos(s * 5.0) * 0.0125 + ops::cos(s * 3.0) * 0.025; let b = ops::cos(s * 5.0) * 0.0125 + ops::cos(s * 3.0) * 0.025;
let c = ops::cos(s * 7.0) * 0.0125 + ops::cos(s * 2.0) * 0.025; let c = ops::cos(s * 7.0) * 0.0125 + ops::cos(s * 2.0) * 0.025;
let (mut light, mut light_transform) = light.single_mut(); let (mut light, mut light_transform) = light.into_inner();
let mut flame_transform = flame.single_mut();
light.intensity = 4_000.0 + 3000.0 * (a + b + c); light.intensity = 4_000.0 + 3000.0 * (a + b + c);
flame_transform.translation = Vec3::new(-1.0, 1.23, 0.0); flame.translation = Vec3::new(-1.0, 1.23, 0.0);
flame_transform.look_at(Vec3::new(-1.0 - c, 1.7 - b, 0.0 - a), Vec3::X); flame.look_at(Vec3::new(-1.0 - c, 1.7 - b, 0.0 - a), Vec3::X);
flame_transform.rotate(Quat::from_euler(EulerRot::XYZ, 0.0, 0.0, PI / 2.0)); flame.rotate(Quat::from_euler(EulerRot::XYZ, 0.0, 0.0, PI / 2.0));
light_transform.translation = Vec3::new(-1.0 - c, 1.7, 0.0 - a); light_transform.translation = Vec3::new(-1.0 - c, 1.7, 0.0 - a);
flame_transform.translation = Vec3::new(-1.0 - c, 1.23, 0.0 - a); flame.translation = Vec3::new(-1.0 - c, 1.23, 0.0 - a);
} }

View file

@ -115,9 +115,9 @@ fn update_colors(
keyboard_input: Res<ButtonInput<KeyCode>>, keyboard_input: Res<ButtonInput<KeyCode>>,
mut config: ResMut<WireframeConfig>, mut config: ResMut<WireframeConfig>,
mut wireframe_colors: Query<&mut WireframeColor, With<Wireframe>>, mut wireframe_colors: Query<&mut WireframeColor, With<Wireframe>>,
mut text: Query<&mut Text>, mut text: Single<&mut Text>,
) { ) {
**text.single_mut() = format!( text.0 = format!(
"Controls "Controls
--------------- ---------------
Z - Toggle global Z - Toggle global

View file

@ -137,9 +137,9 @@ fn setup(mut commands: Commands) {
fn print_logs( fn print_logs(
mut events: EventReader<LogEvent>, mut events: EventReader<LogEvent>,
mut commands: Commands, mut commands: Commands,
log_viewer_root: Query<Entity, With<LogViewerRoot>>, log_viewer_root: Single<Entity, With<LogViewerRoot>>,
) { ) {
let root_entity = log_viewer_root.single(); let root_entity = *log_viewer_root;
commands.entity(root_entity).with_children(|child| { commands.entity(root_entity).with_children(|child| {
for event in events.read() { for event in events.read() {

View file

@ -108,22 +108,20 @@ fn update_emitters(
fn update_listener( fn update_listener(
keyboard: Res<ButtonInput<KeyCode>>, keyboard: Res<ButtonInput<KeyCode>>,
time: Res<Time>, time: Res<Time>,
mut listeners: Query<&mut Transform, With<SpatialListener>>, mut listener: Single<&mut Transform, With<SpatialListener>>,
) { ) {
let mut transform = listeners.single_mut();
let speed = 200.; let speed = 200.;
if keyboard.pressed(KeyCode::ArrowRight) { if keyboard.pressed(KeyCode::ArrowRight) {
transform.translation.x += speed * time.delta_seconds(); listener.translation.x += speed * time.delta_seconds();
} }
if keyboard.pressed(KeyCode::ArrowLeft) { if keyboard.pressed(KeyCode::ArrowLeft) {
transform.translation.x -= speed * time.delta_seconds(); listener.translation.x -= speed * time.delta_seconds();
} }
if keyboard.pressed(KeyCode::ArrowUp) { if keyboard.pressed(KeyCode::ArrowUp) {
transform.translation.y += speed * time.delta_seconds(); listener.translation.y += speed * time.delta_seconds();
} }
if keyboard.pressed(KeyCode::ArrowDown) { if keyboard.pressed(KeyCode::ArrowDown) {
transform.translation.y -= speed * time.delta_seconds(); listener.translation.y -= speed * time.delta_seconds();
} }
} }

View file

@ -111,22 +111,20 @@ fn update_positions(
fn update_listener( fn update_listener(
keyboard: Res<ButtonInput<KeyCode>>, keyboard: Res<ButtonInput<KeyCode>>,
time: Res<Time>, time: Res<Time>,
mut listeners: Query<&mut Transform, With<SpatialListener>>, mut listeners: Single<&mut Transform, With<SpatialListener>>,
) { ) {
let mut transform = listeners.single_mut();
let speed = 2.; let speed = 2.;
if keyboard.pressed(KeyCode::ArrowRight) { if keyboard.pressed(KeyCode::ArrowRight) {
transform.translation.x += speed * time.delta_seconds(); listeners.translation.x += speed * time.delta_seconds();
} }
if keyboard.pressed(KeyCode::ArrowLeft) { if keyboard.pressed(KeyCode::ArrowLeft) {
transform.translation.x -= speed * time.delta_seconds(); listeners.translation.x -= speed * time.delta_seconds();
} }
if keyboard.pressed(KeyCode::ArrowDown) { if keyboard.pressed(KeyCode::ArrowDown) {
transform.translation.z += speed * time.delta_seconds(); listeners.translation.z += speed * time.delta_seconds();
} }
if keyboard.pressed(KeyCode::ArrowUp) { if keyboard.pressed(KeyCode::ArrowUp) {
transform.translation.z -= speed * time.delta_seconds(); listeners.translation.z -= speed * time.delta_seconds();
} }
} }

View file

@ -102,13 +102,12 @@ fn instructions(mut commands: Commands) {
} }
fn orbit( fn orbit(
mut camera: Query<&mut Transform, With<Camera>>, mut camera: Single<&mut Transform, With<Camera>>,
camera_settings: Res<CameraSettings>, camera_settings: Res<CameraSettings>,
mouse_buttons: Res<ButtonInput<MouseButton>>, mouse_buttons: Res<ButtonInput<MouseButton>>,
mouse_motion: Res<AccumulatedMouseMotion>, mouse_motion: Res<AccumulatedMouseMotion>,
time: Res<Time>, time: Res<Time>,
) { ) {
let mut transform = camera.single_mut();
let delta = mouse_motion.delta; let delta = mouse_motion.delta;
let mut delta_roll = 0.0; let mut delta_roll = 0.0;
@ -129,7 +128,7 @@ fn orbit(
delta_roll *= camera_settings.roll_speed * time.delta_seconds(); delta_roll *= camera_settings.roll_speed * time.delta_seconds();
// Obtain the existing pitch, yaw, and roll values from the transform. // Obtain the existing pitch, yaw, and roll values from the transform.
let (yaw, pitch, roll) = transform.rotation.to_euler(EulerRot::YXZ); let (yaw, pitch, roll) = camera.rotation.to_euler(EulerRot::YXZ);
// Establish the new yaw and pitch, preventing the pitch value from exceeding our limits. // Establish the new yaw and pitch, preventing the pitch value from exceeding our limits.
let pitch = (pitch + delta_pitch).clamp( let pitch = (pitch + delta_pitch).clamp(
@ -138,10 +137,10 @@ fn orbit(
); );
let roll = roll + delta_roll; let roll = roll + delta_roll;
let yaw = yaw + delta_yaw; let yaw = yaw + delta_yaw;
transform.rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, roll); camera.rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, roll);
// Adjust the translation to maintain the correct orientation toward the orbit target. // Adjust the translation to maintain the correct orientation toward the orbit target.
// In our example it's a static target, but this could easily be customised. // In our example it's a static target, but this could easily be customised.
let target = Vec3::ZERO; let target = Vec3::ZERO;
transform.translation = target - transform.forward() * camera_settings.orbit_distance; camera.translation = target - camera.forward() * camera_settings.orbit_distance;
} }

View file

@ -112,15 +112,13 @@ fn instructions(mut commands: Commands) {
} }
fn switch_projection( fn switch_projection(
mut camera: Query<&mut Projection, With<Camera>>, mut camera: Single<&mut Projection, With<Camera>>,
camera_settings: Res<CameraSettings>, camera_settings: Res<CameraSettings>,
keyboard_input: Res<ButtonInput<KeyCode>>, keyboard_input: Res<ButtonInput<KeyCode>>,
) { ) {
let mut projection = camera.single_mut();
if keyboard_input.just_pressed(KeyCode::Space) { if keyboard_input.just_pressed(KeyCode::Space) {
// Switch projection type // Switch projection type
*projection = match *projection { **camera = match **camera {
Projection::Orthographic(_) => Projection::Perspective(PerspectiveProjection { Projection::Orthographic(_) => Projection::Perspective(PerspectiveProjection {
fov: camera_settings.perspective_zoom_range.start, fov: camera_settings.perspective_zoom_range.start,
..default() ..default()
@ -136,14 +134,12 @@ fn switch_projection(
} }
fn zoom( fn zoom(
mut camera: Query<&mut Projection, With<Camera>>, camera: Single<&mut Projection, With<Camera>>,
camera_settings: Res<CameraSettings>, camera_settings: Res<CameraSettings>,
mouse_wheel_input: Res<AccumulatedMouseScroll>, mouse_wheel_input: Res<AccumulatedMouseScroll>,
) { ) {
let projection = camera.single_mut();
// Usually, you won't need to handle both types of projection. This is by way of demonstration. // Usually, you won't need to handle both types of projection. This is by way of demonstration.
match projection.into_inner() { match *camera.into_inner() {
Projection::Orthographic(ref mut orthographic) => { Projection::Orthographic(ref mut orthographic) => {
// Get the current scaling_mode value to allow clamping the new value to our zoom range. // Get the current scaling_mode value to allow clamping the new value to our zoom range.
let ScalingMode::FixedVertical(current) = orthographic.scaling_mode else { let ScalingMode::FixedVertical(current) = orthographic.scaling_mode else {

View file

@ -148,11 +148,9 @@ fn integrate(time: Res<Time>, mut query: Query<(&mut Acceleration, &mut Transfor
} }
fn look_at_star( fn look_at_star(
mut camera: Query<&mut Transform, (With<Camera>, Without<Star>)>, mut camera: Single<&mut Transform, (With<Camera>, Without<Star>)>,
star: Query<&Transform, With<Star>>, star: Single<&Transform, With<Star>>,
) { ) {
let mut camera = camera.single_mut();
let star = star.single();
let new_rotation = camera let new_rotation = camera
.looking_at(star.translation, Vec3::Y) .looking_at(star.translation, Vec3::Y)
.rotation .rotation

View file

@ -171,13 +171,12 @@ fn draw_shapes(mut gizmos: Gizmos, mines: Query<&Mine>) {
// Trigger `ExplodeMines` at the position of a given click // Trigger `ExplodeMines` at the position of a given click
fn handle_click( fn handle_click(
mouse_button_input: Res<ButtonInput<MouseButton>>, mouse_button_input: Res<ButtonInput<MouseButton>>,
camera: Query<(&Camera, &GlobalTransform)>, camera: Single<(&Camera, &GlobalTransform)>,
windows: Query<&Window>, windows: Single<&Window>,
mut commands: Commands, mut commands: Commands,
) { ) {
let (camera, camera_transform) = camera.single(); let (camera, camera_transform) = *camera;
if let Some(pos) = windows if let Some(pos) = windows
.single()
.cursor_position() .cursor_position()
.and_then(|cursor| camera.viewport_to_world(camera_transform, cursor).ok()) .and_then(|cursor| camera.viewport_to_world(camera_transform, cursor).ok())
.map(|ray| ray.origin.truncate()) .map(|ray| ray.origin.truncate())

View file

@ -55,16 +55,16 @@ fn setup_with_world(world: &mut World) {
/// Tag entities that have callbacks we want to run with the `Triggered` component. /// Tag entities that have callbacks we want to run with the `Triggered` component.
fn trigger_system( fn trigger_system(
mut commands: Commands, mut commands: Commands,
query_a: Query<Entity, With<A>>, query_a: Single<Entity, With<A>>,
query_b: Query<Entity, With<B>>, query_b: Single<Entity, With<B>>,
input: Res<ButtonInput<KeyCode>>, input: Res<ButtonInput<KeyCode>>,
) { ) {
if input.just_pressed(KeyCode::KeyA) { if input.just_pressed(KeyCode::KeyA) {
let entity = query_a.single(); let entity = *query_a;
commands.entity(entity).insert(Triggered); commands.entity(entity).insert(Triggered);
} }
if input.just_pressed(KeyCode::KeyB) { if input.just_pressed(KeyCode::KeyB) {
let entity = query_b.single(); let entity = *query_b;
commands.entity(entity).insert(Triggered); commands.entity(entity).insert(Triggered);
} }
} }
@ -79,13 +79,13 @@ fn evaluate_callbacks(query: Query<(Entity, &Callback), With<Triggered>>, mut co
} }
} }
fn system_a(query: Query<Entity, With<Text>>, mut writer: UiTextWriter) { fn system_a(entity_a: Single<Entity, With<Text>>, mut writer: UiTextWriter) {
*writer.text(query.single(), 3) = String::from("A"); *writer.text(*entity_a, 3) = String::from("A");
info!("A: One shot system registered with Commands was triggered"); info!("A: One shot system registered with Commands was triggered");
} }
fn system_b(query: Query<Entity, With<Text>>, mut writer: UiTextWriter) { fn system_b(entity_b: Single<Entity, With<Text>>, mut writer: UiTextWriter) {
*writer.text(query.single(), 3) = String::from("B"); *writer.text(*entity_b, 3) = String::from("B");
info!("B: One shot system registered with World was triggered"); info!("B: One shot system registered with World was triggered");
} }

View file

@ -41,8 +41,7 @@ fn move_system(mut sprites: Query<(&mut Transform, &Velocity)>) {
} }
// Bounce sprites outside the window // Bounce sprites outside the window
fn bounce_system(windows: Query<&Window>, mut sprites: Query<(&Transform, &mut Velocity)>) { fn bounce_system(window: Single<&Window>, mut sprites: Query<(&Transform, &mut Velocity)>) {
let window = windows.single();
let width = window.width(); let width = window.width();
let height = window.height(); let height = window.height();
let left = width / -2.0; let left = width / -2.0;

View file

@ -377,8 +377,8 @@ fn rotate_bonus(game: Res<Game>, time: Res<Time>, mut transforms: Query<&mut Tra
} }
// update the score displayed during the game // update the score displayed during the game
fn scoreboard_system(game: Res<Game>, mut query: Query<&mut Text>) { fn scoreboard_system(game: Res<Game>, mut display: Single<&mut Text>) {
**query.single_mut() = format!("Sugar Rush: {}", game.score); display.0 = format!("Sugar Rush: {}", game.score);
} }
// restart the game when pressing spacebar // restart the game when pressing spacebar

View file

@ -301,10 +301,9 @@ fn setup(
fn move_paddle( fn move_paddle(
keyboard_input: Res<ButtonInput<KeyCode>>, keyboard_input: Res<ButtonInput<KeyCode>>,
mut query: Query<&mut Transform, With<Paddle>>, mut paddle_transform: Single<&mut Transform, With<Paddle>>,
time: Res<Time>, time: Res<Time>,
) { ) {
let mut paddle_transform = query.single_mut();
let mut direction = 0.0; let mut direction = 0.0;
if keyboard_input.pressed(KeyCode::ArrowLeft) { if keyboard_input.pressed(KeyCode::ArrowLeft) {
@ -336,20 +335,20 @@ fn apply_velocity(mut query: Query<(&mut Transform, &Velocity)>, time: Res<Time>
fn update_scoreboard( fn update_scoreboard(
score: Res<Score>, score: Res<Score>,
query: Query<Entity, (With<ScoreboardUi>, With<Text>)>, score_root: Single<Entity, (With<ScoreboardUi>, With<Text>)>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
) { ) {
*writer.text(query.single(), 1) = score.to_string(); *writer.text(*score_root, 1) = score.to_string();
} }
fn check_for_collisions( fn check_for_collisions(
mut commands: Commands, mut commands: Commands,
mut score: ResMut<Score>, mut score: ResMut<Score>,
mut ball_query: Query<(&mut Velocity, &Transform), With<Ball>>, ball_query: Single<(&mut Velocity, &Transform), With<Ball>>,
collider_query: Query<(Entity, &Transform, Option<&Brick>), With<Collider>>, collider_query: Query<(Entity, &Transform, Option<&Brick>), With<Collider>>,
mut collision_events: EventWriter<CollisionEvent>, mut collision_events: EventWriter<CollisionEvent>,
) { ) {
let (mut ball_velocity, ball_transform) = ball_query.single_mut(); let (mut ball_velocity, ball_transform) = ball_query.into_inner();
for (collider_entity, collider_transform, maybe_brick) in &collider_query { for (collider_entity, collider_transform, maybe_brick) in &collider_query {
let collision = ball_collision( let collision = ball_collision(

View file

@ -159,7 +159,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
fn selection( fn selection(
mut timer: ResMut<SelectionTimer>, mut timer: ResMut<SelectionTimer>,
mut contributor_selection: ResMut<ContributorSelection>, mut contributor_selection: ResMut<ContributorSelection>,
text_query: Query<Entity, (With<ContributorDisplay>, With<Text>)>, contributor_root: Single<Entity, (With<ContributorDisplay>, With<Text>)>,
mut query: Query<(&Contributor, &mut Sprite, &mut Transform)>, mut query: Query<(&Contributor, &mut Sprite, &mut Transform)>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
time: Res<Time>, time: Res<Time>,
@ -186,7 +186,7 @@ fn selection(
let entity = contributor_selection.order[contributor_selection.idx]; let entity = contributor_selection.order[contributor_selection.idx];
if let Ok((contributor, mut sprite, mut transform)) = query.get_mut(entity) { if let Ok((contributor, mut sprite, mut transform)) = query.get_mut(entity) {
let entity = text_query.single(); let entity = *contributor_root;
select( select(
&mut sprite, &mut sprite,
contributor, contributor,
@ -242,10 +242,9 @@ fn gravity(time: Res<Time>, mut velocity_query: Query<&mut Velocity>) {
/// velocity. On collision with the ground it applies an upwards /// velocity. On collision with the ground it applies an upwards
/// force. /// force.
fn collisions( fn collisions(
windows: Query<&Window>, window: Single<&Window>,
mut query: Query<(&mut Velocity, &mut Transform), With<Contributor>>, mut query: Query<(&mut Velocity, &mut Transform), With<Contributor>>,
) { ) {
let window = windows.single();
let window_size = window.size(); let window_size = window.size();
let collision_area = Aabb2d::new(Vec2::ZERO, (window_size - SPRITE_SIZE) / 2.); let collision_area = Aabb2d::new(Vec2::ZERO, (window_size - SPRITE_SIZE) / 2.);

View file

@ -205,11 +205,10 @@ fn setup(
/// Project the cursor into the world coordinates and store it in a resource for easy use /// Project the cursor into the world coordinates and store it in a resource for easy use
fn get_cursor_world_pos( fn get_cursor_world_pos(
mut cursor_world_pos: ResMut<CursorWorldPos>, mut cursor_world_pos: ResMut<CursorWorldPos>,
q_primary_window: Query<&Window, With<PrimaryWindow>>, primary_window: Single<&Window, With<PrimaryWindow>>,
q_camera: Query<(&Camera, &GlobalTransform)>, q_camera: Single<(&Camera, &GlobalTransform)>,
) { ) {
let primary_window = q_primary_window.single(); let (main_camera, main_camera_transform) = *q_camera;
let (main_camera, main_camera_transform) = q_camera.single();
// Get the cursor position in the world // Get the cursor position in the world
cursor_world_pos.0 = primary_window.cursor_position().and_then(|cursor_pos| { cursor_world_pos.0 = primary_window.cursor_position().and_then(|cursor_pos| {
main_camera main_camera
@ -221,11 +220,9 @@ fn get_cursor_world_pos(
/// Update whether the window is clickable or not /// Update whether the window is clickable or not
fn update_cursor_hit_test( fn update_cursor_hit_test(
cursor_world_pos: Res<CursorWorldPos>, cursor_world_pos: Res<CursorWorldPos>,
mut q_primary_window: Query<&mut Window, With<PrimaryWindow>>, mut primary_window: Single<&mut Window, With<PrimaryWindow>>,
q_bevy_logo: Query<&Transform, With<BevyLogo>>, bevy_logo_transform: Single<&Transform, With<BevyLogo>>,
) { ) {
let mut primary_window = q_primary_window.single_mut();
// If the window has decorations (e.g. a border) then it should be clickable // If the window has decorations (e.g. a border) then it should be clickable
if primary_window.decorations { if primary_window.decorations {
primary_window.cursor_options.hit_test = true; primary_window.cursor_options.hit_test = true;
@ -238,7 +235,6 @@ fn update_cursor_hit_test(
}; };
// If the cursor is within the radius of the Bevy logo make the window clickable otherwise the window is not clickable // If the cursor is within the radius of the Bevy logo make the window clickable otherwise the window is not clickable
let bevy_logo_transform = q_bevy_logo.single();
primary_window.cursor_options.hit_test = bevy_logo_transform primary_window.cursor_options.hit_test = bevy_logo_transform
.translation .translation
.truncate() .truncate()
@ -250,7 +246,7 @@ fn update_cursor_hit_test(
fn start_drag( fn start_drag(
mut commands: Commands, mut commands: Commands,
cursor_world_pos: Res<CursorWorldPos>, cursor_world_pos: Res<CursorWorldPos>,
q_bevy_logo: Query<&Transform, With<BevyLogo>>, bevy_logo_transform: Single<&Transform, With<BevyLogo>>,
) { ) {
// If the cursor is not within the primary window skip this system // If the cursor is not within the primary window skip this system
let Some(cursor_world_pos) = cursor_world_pos.0 else { let Some(cursor_world_pos) = cursor_world_pos.0 else {
@ -258,7 +254,6 @@ fn start_drag(
}; };
// Get the offset from the cursor to the Bevy logo sprite // Get the offset from the cursor to the Bevy logo sprite
let bevy_logo_transform = q_bevy_logo.single();
let drag_offset = bevy_logo_transform.translation.truncate() - cursor_world_pos; let drag_offset = bevy_logo_transform.translation.truncate() - cursor_world_pos;
// If the cursor is within the Bevy logo radius start the drag operation and remember the offset of the cursor from the origin // If the cursor is within the Bevy logo radius start the drag operation and remember the offset of the cursor from the origin
@ -277,7 +272,7 @@ fn drag(
drag_offset: Res<DragOperation>, drag_offset: Res<DragOperation>,
cursor_world_pos: Res<CursorWorldPos>, cursor_world_pos: Res<CursorWorldPos>,
time: Res<Time>, time: Res<Time>,
mut q_bevy_logo: Query<&mut Transform, With<BevyLogo>>, mut bevy_transform: Single<&mut Transform, With<BevyLogo>>,
mut q_pupils: Query<&mut Pupil>, mut q_pupils: Query<&mut Pupil>,
) { ) {
// If the cursor is not within the primary window skip this system // If the cursor is not within the primary window skip this system
@ -285,9 +280,6 @@ fn drag(
return; return;
}; };
// Get the current Bevy logo transform
let mut bevy_transform = q_bevy_logo.single_mut();
// Calculate the new translation of the Bevy logo based on cursor and drag offset // Calculate the new translation of the Bevy logo based on cursor and drag offset
let new_translation = cursor_world_pos + drag_offset.0; let new_translation = cursor_world_pos + drag_offset.0;
@ -310,7 +302,7 @@ fn drag(
fn quit( fn quit(
cursor_world_pos: Res<CursorWorldPos>, cursor_world_pos: Res<CursorWorldPos>,
mut app_exit: EventWriter<AppExit>, mut app_exit: EventWriter<AppExit>,
q_bevy_logo: Query<&Transform, With<BevyLogo>>, bevy_logo_transform: Single<&Transform, With<BevyLogo>>,
) { ) {
// If the cursor is not within the primary window skip this system // If the cursor is not within the primary window skip this system
let Some(cursor_world_pos) = cursor_world_pos.0 else { let Some(cursor_world_pos) = cursor_world_pos.0 else {
@ -318,7 +310,6 @@ fn quit(
}; };
// If the cursor is within the Bevy logo radius send the [`AppExit`] event to quit the app // If the cursor is within the Bevy logo radius send the [`AppExit`] event to quit the app
let bevy_logo_transform = q_bevy_logo.single();
if bevy_logo_transform if bevy_logo_transform
.translation .translation
.truncate() .truncate()
@ -334,7 +325,7 @@ fn toggle_transparency(
mut commands: Commands, mut commands: Commands,
mut window_transparency: ResMut<WindowTransparency>, mut window_transparency: ResMut<WindowTransparency>,
mut q_instructions_text: Query<&mut Visibility, With<InstructionsText>>, mut q_instructions_text: Query<&mut Visibility, With<InstructionsText>>,
mut q_primary_window: Query<&mut Window, With<PrimaryWindow>>, mut primary_window: Single<&mut Window, With<PrimaryWindow>>,
) { ) {
// Toggle the window transparency resource // Toggle the window transparency resource
window_transparency.0 = !window_transparency.0; window_transparency.0 = !window_transparency.0;
@ -350,9 +341,12 @@ fn toggle_transparency(
// Remove the primary window's decorations (e.g. borders), make it always on top of other desktop windows, and set the clear color to transparent // Remove the primary window's decorations (e.g. borders), make it always on top of other desktop windows, and set the clear color to transparent
// only if window transparency is enabled // only if window transparency is enabled
let mut window = q_primary_window.single_mut();
let clear_color; let clear_color;
(window.decorations, window.window_level, clear_color) = if window_transparency.0 { (
primary_window.decorations,
primary_window.window_level,
clear_color,
) = if window_transparency.0 {
(false, WindowLevel::AlwaysOnTop, Color::NONE) (false, WindowLevel::AlwaysOnTop, Color::NONE)
} else { } else {
(true, WindowLevel::Normal, WINDOW_CLEAR_COLOR) (true, WindowLevel::Normal, WINDOW_CLEAR_COLOR)

View file

@ -361,13 +361,13 @@ mod menu {
// the button as the one currently selected // the button as the one currently selected
fn setting_button<T: Resource + Component + PartialEq + Copy>( fn setting_button<T: Resource + Component + PartialEq + Copy>(
interaction_query: Query<(&Interaction, &T, Entity), (Changed<Interaction>, With<Button>)>, interaction_query: Query<(&Interaction, &T, Entity), (Changed<Interaction>, With<Button>)>,
mut selected_query: Query<(Entity, &mut BackgroundColor), With<SelectedOption>>, selected_query: Single<(Entity, &mut BackgroundColor), With<SelectedOption>>,
mut commands: Commands, mut commands: Commands,
mut setting: ResMut<T>, mut setting: ResMut<T>,
) { ) {
let (previous_button, mut previous_button_color) = selected_query.into_inner();
for (interaction, button_setting, entity) in &interaction_query { for (interaction, button_setting, entity) in &interaction_query {
if *interaction == Interaction::Pressed && *setting != *button_setting { if *interaction == Interaction::Pressed && *setting != *button_setting {
let (previous_button, mut previous_button_color) = selected_query.single_mut();
*previous_button_color = NORMAL_BUTTON.into(); *previous_button_color = NORMAL_BUTTON.into();
commands.entity(previous_button).remove::<SelectedOption>(); commands.entity(previous_button).remove::<SelectedOption>();
commands.entity(entity).insert(SelectedOption); commands.entity(entity).insert(SelectedOption);

View file

@ -275,7 +275,7 @@ fn load_loading_screen(mut commands: Commands) {
// Determines when to show the loading screen // Determines when to show the loading screen
fn display_loading_screen( fn display_loading_screen(
mut loading_screen: Query<&mut Visibility, (With<LoadingScreen>, With<Node>)>, mut loading_screen: Single<&mut Visibility, (With<LoadingScreen>, With<Node>)>,
loading_state: Res<LoadingState>, loading_state: Res<LoadingState>,
) { ) {
let visibility = match loading_state.as_ref() { let visibility = match loading_state.as_ref() {
@ -283,7 +283,7 @@ fn display_loading_screen(
LoadingState::LevelReady => Visibility::Hidden, LoadingState::LevelReady => Visibility::Hidden,
}; };
*loading_screen.single_mut() = visibility; **loading_screen = visibility;
} }
mod pipelines_ready { mod pipelines_ready {

View file

@ -239,15 +239,11 @@ fn update_ui(
mut commands: Commands, mut commands: Commands,
state: Res<State>, state: Res<State>,
stepping: Res<Stepping>, stepping: Res<Stepping>,
ui: Query<(Entity, &Visibility), With<SteppingUi>>, ui: Single<(Entity, &Visibility), With<SteppingUi>>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
) { ) {
if ui.is_empty() {
return;
}
// ensure the UI is only visible when stepping is enabled // ensure the UI is only visible when stepping is enabled
let (ui, vis) = ui.single(); let (ui, vis) = *ui;
match (vis, stepping.is_enabled()) { match (vis, stepping.is_enabled()) {
(Visibility::Hidden, true) => { (Visibility::Hidden, true) => {
commands.entity(ui).insert(Visibility::Inherited); commands.entity(ui).insert(Visibility::Inherited);

View file

@ -136,9 +136,7 @@ fn setup(
} }
} }
fn rotate_camera(mut query: Query<&mut Transform, With<Camera>>, time: Res<Time>) { fn rotate_camera(mut transform: Single<&mut Transform, With<Camera>>, time: Res<Time>) {
let mut transform = query.single_mut();
transform.rotate_around(Vec3::ZERO, Quat::from_rotation_y(time.delta_seconds() / 2.)); transform.rotate_around(Vec3::ZERO, Quat::from_rotation_y(time.delta_seconds() / 2.));
} }
@ -146,7 +144,7 @@ fn update_config(
mut config_store: ResMut<GizmoConfigStore>, mut config_store: ResMut<GizmoConfigStore>,
keyboard: Res<ButtonInput<KeyCode>>, keyboard: Res<ButtonInput<KeyCode>>,
time: Res<Time>, time: Res<Time>,
color_text_query: Query<Entity, With<GizmoColorText>>, color_text_query: Single<Entity, With<GizmoColorText>>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
) { ) {
if keyboard.just_pressed(KeyCode::KeyD) { if keyboard.just_pressed(KeyCode::KeyD) {
@ -174,6 +172,6 @@ fn update_config(
LightGizmoColor::MatchLightColor => LightGizmoColor::ByLightType, LightGizmoColor::MatchLightColor => LightGizmoColor::ByLightType,
LightGizmoColor::ByLightType => LightGizmoColor::Manual(GRAY.into()), LightGizmoColor::ByLightType => LightGizmoColor::Manual(GRAY.into()),
}; };
*writer.text(color_text_query.single(), 1) = gizmo_color_text(light_config); *writer.text(*color_text_query, 1) = gizmo_color_text(light_config);
} }
} }

View file

@ -12,12 +12,10 @@ fn main() {
// This system grabs the mouse when the left mouse button is pressed // This system grabs the mouse when the left mouse button is pressed
// and releases it when the escape key is pressed // and releases it when the escape key is pressed
fn grab_mouse( fn grab_mouse(
mut windows: Query<&mut Window>, mut window: Single<&mut Window>,
mouse: Res<ButtonInput<MouseButton>>, mouse: Res<ButtonInput<MouseButton>>,
key: Res<ButtonInput<KeyCode>>, key: Res<ButtonInput<KeyCode>>,
) { ) {
let mut window = windows.single_mut();
if mouse.just_pressed(MouseButton::Left) { if mouse.just_pressed(MouseButton::Left) {
window.cursor_options.visible = false; window.cursor_options.visible = false;
window.cursor_options.grab_mode = CursorGrabMode::Locked; window.cursor_options.grab_mode = CursorGrabMode::Locked;

View file

@ -74,17 +74,15 @@ fn setup_scene(mut commands: Commands, asset_server: Res<AssetServer>) {
fn toggle_ime( fn toggle_ime(
input: Res<ButtonInput<MouseButton>>, input: Res<ButtonInput<MouseButton>>,
mut windows: Query<&mut Window>, mut window: Single<&mut Window>,
status_text: Query<Entity, (With<Node>, With<Text>)>, status_text: Single<Entity, (With<Node>, With<Text>)>,
mut ui_writer: UiTextWriter, mut ui_writer: UiTextWriter,
) { ) {
if input.just_pressed(MouseButton::Left) { if input.just_pressed(MouseButton::Left) {
let mut window = windows.single_mut();
window.ime_position = window.cursor_position().unwrap(); window.ime_position = window.cursor_position().unwrap();
window.ime_enabled = !window.ime_enabled; window.ime_enabled = !window.ime_enabled;
*ui_writer.text(status_text.single(), 3) = format!("{}\n", window.ime_enabled); *ui_writer.text(*status_text, 3) = format!("{}\n", window.ime_enabled);
} }
} }
@ -108,26 +106,26 @@ fn bubbling_text(
fn listen_ime_events( fn listen_ime_events(
mut events: EventReader<Ime>, mut events: EventReader<Ime>,
status_text: Query<Entity, (With<Node>, With<Text>)>, status_text: Single<Entity, (With<Node>, With<Text>)>,
mut edit_text: Query<&mut Text2d, (Without<Node>, Without<Bubble>)>, mut edit_text: Single<&mut Text2d, (Without<Node>, Without<Bubble>)>,
mut ui_writer: UiTextWriter, mut ui_writer: UiTextWriter,
) { ) {
for event in events.read() { for event in events.read() {
match event { match event {
Ime::Preedit { value, cursor, .. } if !cursor.is_none() => { Ime::Preedit { value, cursor, .. } if !cursor.is_none() => {
*ui_writer.text(status_text.single(), 7) = format!("{value}\n"); *ui_writer.text(*status_text, 7) = format!("{value}\n");
} }
Ime::Preedit { cursor, .. } if cursor.is_none() => { Ime::Preedit { cursor, .. } if cursor.is_none() => {
*ui_writer.text(status_text.single(), 7) = "\n".to_string(); *ui_writer.text(*status_text, 7) = "\n".to_string();
} }
Ime::Commit { value, .. } => { Ime::Commit { value, .. } => {
edit_text.single_mut().push_str(value); edit_text.push_str(value);
} }
Ime::Enabled { .. } => { Ime::Enabled { .. } => {
*ui_writer.text(status_text.single(), 5) = "true\n".to_string(); *ui_writer.text(*status_text, 5) = "true\n".to_string();
} }
Ime::Disabled { .. } => { Ime::Disabled { .. } => {
*ui_writer.text(status_text.single(), 5) = "false\n".to_string(); *ui_writer.text(*status_text, 5) = "false\n".to_string();
} }
_ => (), _ => (),
} }
@ -137,8 +135,9 @@ fn listen_ime_events(
fn listen_keyboard_input_events( fn listen_keyboard_input_events(
mut commands: Commands, mut commands: Commands,
mut events: EventReader<KeyboardInput>, mut events: EventReader<KeyboardInput>,
mut edit_text: Query<(&mut Text2d, &TextFont), (Without<Node>, Without<Bubble>)>, edit_text: Single<(&mut Text2d, &TextFont), (Without<Node>, Without<Bubble>)>,
) { ) {
let (mut text, style) = edit_text.into_inner();
for event in events.read() { for event in events.read() {
// Only trigger changes when the key is first pressed. // Only trigger changes when the key is first pressed.
if !event.state.is_pressed() { if !event.state.is_pressed() {
@ -147,7 +146,6 @@ fn listen_keyboard_input_events(
match &event.logical_key { match &event.logical_key {
Key::Enter => { Key::Enter => {
let (mut text, style) = edit_text.single_mut();
if text.is_empty() { if text.is_empty() {
continue; continue;
} }
@ -162,13 +160,13 @@ fn listen_keyboard_input_events(
)); ));
} }
Key::Space => { Key::Space => {
edit_text.single_mut().0.push(' '); text.push(' ');
} }
Key::Backspace => { Key::Backspace => {
edit_text.single_mut().0.pop(); text.pop();
} }
Key::Character(character) => { Key::Character(character) => {
edit_text.single_mut().0.push_str(character); text.push_str(character);
} }
_ => continue, _ => continue,
} }

View file

@ -259,7 +259,7 @@ fn update_bounding_shape(
fn switch_cameras( fn switch_cameras(
current: Res<State<CameraActive>>, current: Res<State<CameraActive>>,
mut next: ResMut<NextState<CameraActive>>, mut next: ResMut<NextState<CameraActive>>,
mut camera: Query<(&mut Transform, &mut Projection)>, camera: Single<(&mut Transform, &mut Projection)>,
) { ) {
let next_state = match current.get() { let next_state = match current.get() {
CameraActive::Dim2 => CameraActive::Dim3, CameraActive::Dim2 => CameraActive::Dim3,
@ -267,7 +267,7 @@ fn switch_cameras(
}; };
next.set(next_state); next.set(next_state);
let (mut transform, mut projection) = camera.single_mut(); let (mut transform, mut projection) = camera.into_inner();
match next_state { match next_state {
CameraActive::Dim2 => { CameraActive::Dim2 => {
*transform = TRANSFORM_2D; *transform = TRANSFORM_2D;

View file

@ -222,7 +222,7 @@ fn handle_keypress(
fn handle_mouse( fn handle_mouse(
accumulated_mouse_motion: Res<AccumulatedMouseMotion>, accumulated_mouse_motion: Res<AccumulatedMouseMotion>,
mut button_events: EventReader<MouseButtonInput>, mut button_events: EventReader<MouseButtonInput>,
mut camera: Query<&mut Transform, With<Camera>>, mut camera_transform: Single<&mut Transform, With<Camera>>,
mut mouse_pressed: ResMut<MousePressed>, mut mouse_pressed: ResMut<MousePressed>,
) { ) {
// Store left-pressed state in the MousePressed resource // Store left-pressed state in the MousePressed resource
@ -239,7 +239,6 @@ fn handle_mouse(
} }
if accumulated_mouse_motion.delta != Vec2::ZERO { if accumulated_mouse_motion.delta != Vec2::ZERO {
let displacement = accumulated_mouse_motion.delta.x; let displacement = accumulated_mouse_motion.delta.x;
let mut camera_transform = camera.single_mut();
camera_transform.rotate_around(Vec3::ZERO, Quat::from_rotation_y(-displacement / 150.)); camera_transform.rotate_around(Vec3::ZERO, Quat::from_rotation_y(-displacement / 150.));
} }
} }

View file

@ -332,12 +332,12 @@ pub struct HeaderNode;
fn update_active_cameras( fn update_active_cameras(
state: Res<State<CameraActive>>, state: Res<State<CameraActive>>,
mut camera_2d: Query<(Entity, &mut Camera), With<Camera2d>>, camera_2d: Single<(Entity, &mut Camera), With<Camera2d>>,
mut camera_3d: Query<(Entity, &mut Camera), (With<Camera3d>, Without<Camera2d>)>, camera_3d: Single<(Entity, &mut Camera), (With<Camera3d>, Without<Camera2d>)>,
mut text: Query<&mut TargetCamera, With<HeaderNode>>, mut text: Query<&mut TargetCamera, With<HeaderNode>>,
) { ) {
let (entity_2d, mut cam_2d) = camera_2d.single_mut(); let (entity_2d, mut cam_2d) = camera_2d.into_inner();
let (entity_3d, mut cam_3d) = camera_3d.single_mut(); let (entity_3d, mut cam_3d) = camera_3d.into_inner();
let is_camera_2d_active = matches!(*state.get(), CameraActive::Dim2); let is_camera_2d_active = matches!(*state.get(), CameraActive::Dim2);
cam_2d.is_active = is_camera_2d_active; cam_2d.is_active = is_camera_2d_active;

View file

@ -424,7 +424,7 @@ fn handle_keypress(
mut spawn_queue: ResMut<SpawnQueue>, mut spawn_queue: ResMut<SpawnQueue>,
mut counter: ResMut<PointCounter>, mut counter: ResMut<PointCounter>,
mut text_menus: Query<&mut Visibility, With<Text>>, mut text_menus: Query<&mut Visibility, With<Text>>,
mut camera: Query<&mut CameraRig>, mut camera_rig: Single<&mut CameraRig>,
) { ) {
// R => restart, deleting all samples // R => restart, deleting all samples
if keyboard.just_pressed(KeyCode::KeyR) { if keyboard.just_pressed(KeyCode::KeyR) {
@ -471,8 +471,6 @@ fn handle_keypress(
} }
} }
let mut camera_rig = camera.single_mut();
// +/- => zoom camera. // +/- => zoom camera.
if keyboard.just_pressed(KeyCode::NumpadSubtract) || keyboard.just_pressed(KeyCode::Minus) { if keyboard.just_pressed(KeyCode::NumpadSubtract) || keyboard.just_pressed(KeyCode::Minus) {
camera_rig.distance += MAX_CAMERA_DISTANCE / 15.0; camera_rig.distance += MAX_CAMERA_DISTANCE / 15.0;
@ -516,7 +514,7 @@ fn handle_mouse(
accumulated_mouse_motion: Res<AccumulatedMouseMotion>, accumulated_mouse_motion: Res<AccumulatedMouseMotion>,
accumulated_mouse_scroll: Res<AccumulatedMouseScroll>, accumulated_mouse_scroll: Res<AccumulatedMouseScroll>,
mut button_events: EventReader<MouseButtonInput>, mut button_events: EventReader<MouseButtonInput>,
mut camera: Query<&mut CameraRig>, mut camera_rig: Single<&mut CameraRig>,
mut mouse_pressed: ResMut<MousePressed>, mut mouse_pressed: ResMut<MousePressed>,
) { ) {
// Store left-pressed state in the MousePressed resource // Store left-pressed state in the MousePressed resource
@ -527,8 +525,6 @@ fn handle_mouse(
*mouse_pressed = MousePressed(button_event.state.is_pressed()); *mouse_pressed = MousePressed(button_event.state.is_pressed());
} }
let mut camera_rig = camera.single_mut();
if accumulated_mouse_scroll.delta != Vec2::ZERO { if accumulated_mouse_scroll.delta != Vec2::ZERO {
let mouse_scroll = accumulated_mouse_scroll.delta.y; let mouse_scroll = accumulated_mouse_scroll.delta.y;
camera_rig.distance -= mouse_scroll / 15.0 * MAX_CAMERA_DISTANCE; camera_rig.distance -= mouse_scroll / 15.0 * MAX_CAMERA_DISTANCE;

View file

@ -38,25 +38,22 @@ fn main() {
} }
fn touch_camera( fn touch_camera(
windows: Query<&Window>, window: Single<&Window>,
mut touches: EventReader<TouchInput>, mut touches: EventReader<TouchInput>,
mut camera: Query<&mut Transform, With<Camera3d>>, mut camera_transform: Single<&mut Transform, With<Camera3d>>,
mut last_position: Local<Option<Vec2>>, mut last_position: Local<Option<Vec2>>,
mut rotations: EventReader<RotationGesture>, mut rotations: EventReader<RotationGesture>,
) { ) {
let window = windows.single();
for touch in touches.read() { for touch in touches.read() {
if touch.phase == TouchPhase::Started { if touch.phase == TouchPhase::Started {
*last_position = None; *last_position = None;
} }
if let Some(last_position) = *last_position { if let Some(last_position) = *last_position {
let mut transform = camera.single_mut(); **camera_transform = Transform::from_xyz(
*transform = Transform::from_xyz( camera_transform.translation.x
transform.translation.x
+ (touch.position.x - last_position.x) / window.width() * 5.0, + (touch.position.x - last_position.x) / window.width() * 5.0,
transform.translation.y, camera_transform.translation.y,
transform.translation.z camera_transform.translation.z
+ (touch.position.y - last_position.y) / window.height() * 5.0, + (touch.position.y - last_position.y) / window.height() * 5.0,
) )
.looking_at(Vec3::ZERO, Vec3::Y); .looking_at(Vec3::ZERO, Vec3::Y);
@ -65,9 +62,8 @@ fn touch_camera(
} }
// Rotation gestures only work on iOS // Rotation gestures only work on iOS
for rotation in rotations.read() { for rotation in rotations.read() {
let mut transform = camera.single_mut(); let forward = camera_transform.forward();
let forward = transform.forward(); camera_transform.rotate_axis(forward, rotation.0 / 10.0);
transform.rotate_axis(forward, rotation.0 / 10.0);
} }
} }

View file

@ -90,14 +90,12 @@ fn setup(
} }
fn move_target( fn move_target(
mut target: Query<&mut Transform, With<TargetSphere>>, mut target: Single<&mut Transform, With<TargetSphere>>,
target_speed: Res<TargetSphereSpeed>, target_speed: Res<TargetSphereSpeed>,
mut target_pos: ResMut<TargetPosition>, mut target_pos: ResMut<TargetPosition>,
time: Res<Time>, time: Res<Time>,
mut rng: ResMut<RandomSource>, mut rng: ResMut<RandomSource>,
) { ) {
let mut target = target.single_mut();
match Dir3::new(target_pos.0 - target.translation) { match Dir3::new(target_pos.0 - target.translation) {
// The target and the present position of the target sphere are far enough to have a well- // The target and the present position of the target sphere are far enough to have a well-
// defined direction between them, so let's move closer: // defined direction between them, so let's move closer:
@ -119,13 +117,11 @@ fn move_target(
} }
fn move_follower( fn move_follower(
mut following: Query<&mut Transform, With<FollowingSphere>>, mut following: Single<&mut Transform, With<FollowingSphere>>,
target: Query<&Transform, (With<TargetSphere>, Without<FollowingSphere>)>, target: Single<&Transform, (With<TargetSphere>, Without<FollowingSphere>)>,
decay_rate: Res<DecayRate>, decay_rate: Res<DecayRate>,
time: Res<Time>, time: Res<Time>,
) { ) {
let target = target.single();
let mut following = following.single_mut();
let decay_rate = decay_rate.0; let decay_rate = decay_rate.0;
let delta_time = time.delta_seconds(); let delta_time = time.delta_seconds();

View file

@ -62,8 +62,8 @@ fn move_cube(mut query: Query<&mut Transform, With<Cube>>, time: Res<Time>) {
} }
} }
fn remove(mut commands: Commands, query: Query<Entity, With<Cube>>) { fn remove(mut commands: Commands, cube_entity: Single<Entity, With<Cube>>) {
commands.entity(query.single()).remove::<Cube>(); commands.entity(*cube_entity).remove::<Cube>();
} }
#[derive(Component, Reflect, Serialize, Deserialize)] #[derive(Component, Reflect, Serialize, Deserialize)]

View file

@ -84,8 +84,7 @@ fn setup(mut commands: Commands, mut images: ResMut<Assets<Image>>) {
} }
// Switch texture to display every frame to show the one that was written to most recently. // Switch texture to display every frame to show the one that was written to most recently.
fn switch_textures(images: Res<GameOfLifeImages>, mut displayed: Query<&mut Sprite>) { fn switch_textures(images: Res<GameOfLifeImages>, mut sprite: Single<&mut Sprite>) {
let mut sprite = displayed.single_mut();
if sprite.image == images.texture_a { if sprite.image == images.texture_a {
sprite.image = images.texture_b.clone_weak(); sprite.image = images.texture_b.clone_weak();
} else { } else {

View file

@ -51,9 +51,7 @@ fn setup(
)); ));
} }
fn rotate_camera(mut camera: Query<&mut Transform, With<MainCamera>>, time: Res<Time>) { fn rotate_camera(mut cam_transform: Single<&mut Transform, With<MainCamera>>, time: Res<Time>) {
let cam_transform = camera.single_mut().into_inner();
cam_transform.rotate_around( cam_transform.rotate_around(
Vec3::ZERO, Vec3::ZERO,
Quat::from_axis_angle(Vec3::Y, 45f32.to_radians() * time.delta_seconds()), Quat::from_axis_angle(Vec3::Y, 45f32.to_radians() * time.delta_seconds()),

View file

@ -212,9 +212,9 @@ impl Material for PrepassOutputMaterial {
fn toggle_prepass_view( fn toggle_prepass_view(
mut prepass_view: Local<u32>, mut prepass_view: Local<u32>,
keycode: Res<ButtonInput<KeyCode>>, keycode: Res<ButtonInput<KeyCode>>,
material_handle: Query<&MeshMaterial3d<PrepassOutputMaterial>>, material_handle: Single<&MeshMaterial3d<PrepassOutputMaterial>>,
mut materials: ResMut<Assets<PrepassOutputMaterial>>, mut materials: ResMut<Assets<PrepassOutputMaterial>>,
text: Query<Entity, With<Text>>, text: Single<Entity, With<Text>>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
) { ) {
if keycode.just_pressed(KeyCode::Space) { if keycode.just_pressed(KeyCode::Space) {
@ -227,14 +227,13 @@ fn toggle_prepass_view(
3 => "motion vectors", 3 => "motion vectors",
_ => unreachable!(), _ => unreachable!(),
}; };
let text = text.single(); let text = *text;
*writer.text(text, 1) = format!("Prepass Output: {label}\n"); *writer.text(text, 1) = format!("Prepass Output: {label}\n");
writer.for_each_color(text, |mut color| { writer.for_each_color(text, |mut color| {
color.0 = Color::WHITE; color.0 = Color::WHITE;
}); });
let handle = material_handle.single(); let mat = materials.get_mut(*material_handle).unwrap();
let mat = materials.get_mut(handle).unwrap();
mat.settings.show_depth = (*prepass_view == 1) as u32; mat.settings.show_depth = (*prepass_view == 1) as u32;
mat.settings.show_normals = (*prepass_view == 2) as u32; mat.settings.show_normals = (*prepass_view == 2) as u32;
mat.settings.show_motion_vectors = (*prepass_view == 3) as u32; mat.settings.show_motion_vectors = (*prepass_view == 3) as u32;

View file

@ -227,8 +227,8 @@ fn setup_game(mut commands: Commands, asset_server: Res<AssetServer>) {
info!("Setup game"); info!("Setup game");
} }
fn teardown_game(mut commands: Commands, player: Query<Entity, With<Sprite>>) { fn teardown_game(mut commands: Commands, player: Single<Entity, With<Sprite>>) {
commands.entity(player.single()).despawn(); commands.entity(*player).despawn();
info!("Teardown game"); info!("Teardown game");
} }

View file

@ -180,13 +180,11 @@ struct BirdScheduled {
fn scheduled_spawner( fn scheduled_spawner(
mut commands: Commands, mut commands: Commands,
args: Res<Args>, args: Res<Args>,
windows: Query<&Window>, window: Single<&Window>,
mut scheduled: ResMut<BirdScheduled>, mut scheduled: ResMut<BirdScheduled>,
mut counter: ResMut<BevyCounter>, mut counter: ResMut<BevyCounter>,
bird_resources: ResMut<BirdResources>, bird_resources: ResMut<BirdResources>,
) { ) {
let window = windows.single();
if scheduled.waves > 0 { if scheduled.waves > 0 {
let bird_resources = bird_resources.into_inner(); let bird_resources = bird_resources.into_inner();
spawn_birds( spawn_birds(
@ -226,7 +224,7 @@ fn setup(
mut meshes: ResMut<Assets<Mesh>>, mut meshes: ResMut<Assets<Mesh>>,
material_assets: ResMut<Assets<ColorMaterial>>, material_assets: ResMut<Assets<ColorMaterial>>,
images: ResMut<Assets<Image>>, images: ResMut<Assets<Image>>,
windows: Query<&Window>, window: Single<&Window>,
counter: ResMut<BevyCounter>, counter: ResMut<BevyCounter>,
) { ) {
warn!(include_str!("warning_string.txt")); warn!(include_str!("warning_string.txt"));
@ -314,7 +312,7 @@ fn setup(
spawn_birds( spawn_birds(
&mut commands, &mut commands,
args, args,
&windows.single().resolution, &window.resolution,
counter, counter,
scheduled.per_wave, scheduled.per_wave,
&mut bird_resources, &mut bird_resources,
@ -334,7 +332,7 @@ fn mouse_handler(
args: Res<Args>, args: Res<Args>,
time: Res<Time>, time: Res<Time>,
mouse_button_input: Res<ButtonInput<MouseButton>>, mouse_button_input: Res<ButtonInput<MouseButton>>,
windows: Query<&Window>, window: Single<&Window>,
bird_resources: ResMut<BirdResources>, bird_resources: ResMut<BirdResources>,
mut counter: ResMut<BevyCounter>, mut counter: ResMut<BevyCounter>,
mut rng: Local<Option<ChaCha8Rng>>, mut rng: Local<Option<ChaCha8Rng>>,
@ -346,7 +344,6 @@ fn mouse_handler(
*rng = Some(ChaCha8Rng::seed_from_u64(42)); *rng = Some(ChaCha8Rng::seed_from_u64(42));
} }
let rng = rng.as_mut().unwrap(); let rng = rng.as_mut().unwrap();
let window = windows.single();
if mouse_button_input.just_released(MouseButton::Left) { if mouse_button_input.just_released(MouseButton::Left) {
counter.color = Color::linear_rgb(rng.gen(), rng.gen(), rng.gen()); counter.color = Color::linear_rgb(rng.gen(), rng.gen(), rng.gen());
@ -538,9 +535,7 @@ fn handle_collision(half_extents: Vec2, translation: &Vec3, velocity: &mut Vec3)
velocity.y = 0.0; velocity.y = 0.0;
} }
} }
fn collision_system(windows: Query<&Window>, mut bird_query: Query<(&mut Bird, &Transform)>) { fn collision_system(window: Single<&Window>, mut bird_query: Query<(&mut Bird, &Transform)>) {
let window = windows.single();
let half_extents = 0.5 * window.size(); let half_extents = 0.5 * window.size();
for (mut bird, transform) in &mut bird_query { for (mut bird, transform) in &mut bird_query {
@ -551,10 +546,10 @@ fn collision_system(windows: Query<&Window>, mut bird_query: Query<(&mut Bird, &
fn counter_system( fn counter_system(
diagnostics: Res<DiagnosticsStore>, diagnostics: Res<DiagnosticsStore>,
counter: Res<BevyCounter>, counter: Res<BevyCounter>,
query: Query<Entity, With<StatsText>>, query: Single<Entity, With<StatsText>>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
) { ) {
let text = query.single(); let text = *query;
if counter.is_changed() { if counter.is_changed() {
*writer.text(text, 2) = counter.count.to_string(); *writer.text(text, 2) = counter.count.to_string();

View file

@ -100,10 +100,9 @@ fn setup(
} }
// System for rotating and translating the camera // System for rotating and translating the camera
fn move_camera(time: Res<Time>, mut camera_query: Query<&mut Transform, With<Camera>>) { fn move_camera(time: Res<Time>, mut camera_transform: Single<&mut Transform, With<Camera>>) {
let mut camera_transform = camera_query.single_mut();
camera_transform.rotate(Quat::from_rotation_z(time.delta_seconds() * 0.5)); camera_transform.rotate(Quat::from_rotation_z(time.delta_seconds() * 0.5));
*camera_transform = *camera_transform **camera_transform = **camera_transform
* Transform::from_translation(Vec3::X * CAMERA_SPEED * time.delta_seconds()); * Transform::from_translation(Vec3::X * CAMERA_SPEED * time.delta_seconds());
} }

View file

@ -438,9 +438,8 @@ fn spherical_polar_to_cartesian(p: DVec2) -> DVec3 {
fn move_camera( fn move_camera(
time: Res<Time>, time: Res<Time>,
args: Res<Args>, args: Res<Args>,
mut camera_query: Query<&mut Transform, With<Camera>>, mut camera_transform: Single<&mut Transform, With<Camera>>,
) { ) {
let mut camera_transform = camera_query.single_mut();
let delta = 0.15 let delta = 0.15
* if args.benchmark { * if args.benchmark {
1.0 / 60.0 1.0 / 60.0

View file

@ -98,9 +98,7 @@ fn setup(mut commands: Commands) {
)); ));
} }
fn ui_system(mut query: Query<&mut Text>, config: Res<Config>, diag: Res<DiagnosticsStore>) { fn ui_system(mut text: Single<&mut Text>, config: Res<Config>, diag: Res<DiagnosticsStore>) {
let mut text = query.single_mut();
let Some(fps) = diag let Some(fps) = diag
.get(&FrameTimeDiagnosticsPlugin::FPS) .get(&FrameTimeDiagnosticsPlugin::FPS)
.and_then(Diagnostic::smoothed) .and_then(Diagnostic::smoothed)
@ -108,7 +106,7 @@ fn ui_system(mut query: Query<&mut Text>, config: Res<Config>, diag: Res<Diagnos
return; return;
}; };
**text = format!( text.0 = format!(
"Line count: {}\n\ "Line count: {}\n\
FPS: {:.0}\n\n\ FPS: {:.0}\n\n\
Controls:\n\ Controls:\n\

View file

@ -133,8 +133,7 @@ fn spherical_polar_to_cartesian(p: DVec2) -> DVec3 {
} }
// System for rotating the camera // System for rotating the camera
fn move_camera(time: Res<Time>, mut camera_query: Query<&mut Transform, With<Camera>>) { fn move_camera(time: Res<Time>, mut camera_transform: Single<&mut Transform, With<Camera>>) {
let mut camera_transform = camera_query.single_mut();
let delta = time.delta_seconds() * 0.15; let delta = time.delta_seconds() * 0.15;
camera_transform.rotate_z(delta); camera_transform.rotate_z(delta);
camera_transform.rotate_x(delta); camera_transform.rotate_x(delta);

View file

@ -104,10 +104,9 @@ fn setup(mut commands: Commands, assets: Res<AssetServer>, color_tint: Res<Color
} }
// System for rotating and translating the camera // System for rotating and translating the camera
fn move_camera(time: Res<Time>, mut camera_query: Query<&mut Transform, With<Camera>>) { fn move_camera(time: Res<Time>, mut camera_transform: Single<&mut Transform, With<Camera>>) {
let mut camera_transform = camera_query.single_mut();
camera_transform.rotate_z(time.delta_seconds() * 0.5); camera_transform.rotate_z(time.delta_seconds() * 0.5);
*camera_transform = *camera_transform **camera_transform = **camera_transform
* Transform::from_translation(Vec3::X * CAMERA_SPEED * time.delta_seconds()); * Transform::from_translation(Vec3::X * CAMERA_SPEED * time.delta_seconds());
} }

View file

@ -448,7 +448,7 @@ fn update_axes(
fn update_connected( fn update_connected(
mut connected: EventReader<GamepadConnectionEvent>, mut connected: EventReader<GamepadConnectionEvent>,
gamepads: Query<(Entity, &Gamepad)>, gamepads: Query<(Entity, &Gamepad)>,
query: Query<Entity, With<ConnectedGamepadsText>>, text: Single<Entity, With<ConnectedGamepadsText>>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
) { ) {
if connected.is_empty() { if connected.is_empty() {
@ -462,7 +462,7 @@ fn update_connected(
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n"); .join("\n");
*writer.text(query.single(), 1) = if !formatted.is_empty() { *writer.text(*text, 1) = if !formatted.is_empty() {
formatted formatted
} else { } else {
"None".to_string() "None".to_string()

View file

@ -178,7 +178,7 @@ impl MorphKey {
} }
fn update_text( fn update_text(
controls: Option<ResMut<WeightsControl>>, controls: Option<ResMut<WeightsControl>>,
text: Query<Entity, With<Text>>, text: Single<Entity, With<Text>>,
morphs: Query<&MorphWeights>, morphs: Query<&MorphWeights>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
) { ) {
@ -196,7 +196,7 @@ fn update_text(
target.weight = actual_weight; target.weight = actual_weight;
} }
let key_name = &AVAILABLE_KEYS[i].name; let key_name = &AVAILABLE_KEYS[i].name;
*writer.text(text.single(), i + 3) = format!("[{key_name}] {target}\n"); *writer.text(*text, i + 3) = format!("[{key_name}] {target}\n");
} }
} }
fn update_morphs( fn update_morphs(

View file

@ -119,28 +119,26 @@ fn setup(
// Update systems // Update systems
// Draw the main and secondary axes on the rotating ship // Draw the main and secondary axes on the rotating ship
fn draw_ship_axes(mut gizmos: Gizmos, query: Query<&Transform, With<Ship>>) { fn draw_ship_axes(mut gizmos: Gizmos, ship_transform: Single<&Transform, With<Ship>>) {
let ship_transform = query.single();
// Local Z-axis arrow, negative direction // Local Z-axis arrow, negative direction
let z_ends = arrow_ends(ship_transform, Vec3::NEG_Z, 1.5); let z_ends = arrow_ends(*ship_transform, Vec3::NEG_Z, 1.5);
gizmos.arrow(z_ends.0, z_ends.1, RED); gizmos.arrow(z_ends.0, z_ends.1, RED);
// local X-axis arrow // local X-axis arrow
let x_ends = arrow_ends(ship_transform, Vec3::X, 1.5); let x_ends = arrow_ends(*ship_transform, Vec3::X, 1.5);
gizmos.arrow(x_ends.0, x_ends.1, Color::srgb(0.65, 0., 0.)); gizmos.arrow(x_ends.0, x_ends.1, Color::srgb(0.65, 0., 0.));
} }
// Draw the randomly generated axes // Draw the randomly generated axes
fn draw_random_axes(mut gizmos: Gizmos, query: Query<&RandomAxes>) { fn draw_random_axes(mut gizmos: Gizmos, random_axes: Single<&RandomAxes>) {
let RandomAxes(v1, v2) = query.single(); let RandomAxes(v1, v2) = *random_axes;
gizmos.arrow(Vec3::ZERO, 1.5 * *v1, WHITE); gizmos.arrow(Vec3::ZERO, 1.5 * *v1, WHITE);
gizmos.arrow(Vec3::ZERO, 1.5 * *v2, GRAY); gizmos.arrow(Vec3::ZERO, 1.5 * *v2, GRAY);
} }
// Actually update the ship's transform according to its initial source and target // Actually update the ship's transform according to its initial source and target
fn rotate_ship(mut ship: Query<(&mut Ship, &mut Transform)>, time: Res<Time>) { fn rotate_ship(ship: Single<(&mut Ship, &mut Transform)>, time: Res<Time>) {
let (mut ship, mut ship_transform) = ship.single_mut(); let (mut ship, mut ship_transform) = ship.into_inner();
if !ship.in_motion { if !ship.in_motion {
return; return;
@ -159,20 +157,17 @@ fn rotate_ship(mut ship: Query<(&mut Ship, &mut Transform)>, time: Res<Time>) {
// Handle user inputs from the keyboard for dynamically altering the scenario // Handle user inputs from the keyboard for dynamically altering the scenario
fn handle_keypress( fn handle_keypress(
mut ship: Query<&mut Ship>, mut ship: Single<&mut Ship>,
mut random_axes: Query<&mut RandomAxes>, mut random_axes: Single<&mut RandomAxes>,
mut instructions: Query<&mut Visibility, With<Instructions>>, mut instructions_viz: Single<&mut Visibility, With<Instructions>>,
keyboard: Res<ButtonInput<KeyCode>>, keyboard: Res<ButtonInput<KeyCode>>,
mut seeded_rng: ResMut<SeededRng>, mut seeded_rng: ResMut<SeededRng>,
) { ) {
let mut ship = ship.single_mut();
let mut random_axes = random_axes.single_mut();
if keyboard.just_pressed(KeyCode::KeyR) { if keyboard.just_pressed(KeyCode::KeyR) {
// Randomize the target axes // Randomize the target axes
let first = seeded_rng.0.gen(); let first = seeded_rng.0.gen();
let second = seeded_rng.0.gen(); let second = seeded_rng.0.gen();
*random_axes = RandomAxes(first, second); **random_axes = RandomAxes(first, second);
// Stop the ship and set it up to transform from its present orientation to the new one // Stop the ship and set it up to transform from its present orientation to the new one
ship.in_motion = false; ship.in_motion = false;
@ -184,11 +179,10 @@ fn handle_keypress(
} }
if keyboard.just_pressed(KeyCode::KeyH) { if keyboard.just_pressed(KeyCode::KeyH) {
let mut instructions_viz = instructions.single_mut(); if *instructions_viz.as_ref() == Visibility::Hidden {
if *instructions_viz == Visibility::Hidden { **instructions_viz = Visibility::Visible;
*instructions_viz = Visibility::Visible;
} else { } else {
*instructions_viz = Visibility::Hidden; **instructions_viz = Visibility::Hidden;
} }
} }
} }
@ -197,7 +191,7 @@ fn handle_keypress(
fn handle_mouse( fn handle_mouse(
accumulated_mouse_motion: Res<AccumulatedMouseMotion>, accumulated_mouse_motion: Res<AccumulatedMouseMotion>,
mut button_events: EventReader<MouseButtonInput>, mut button_events: EventReader<MouseButtonInput>,
mut camera: Query<&mut Transform, With<Camera>>, mut camera_transform: Single<&mut Transform, With<Camera>>,
mut mouse_pressed: ResMut<MousePressed>, mut mouse_pressed: ResMut<MousePressed>,
) { ) {
// Store left-pressed state in the MousePressed resource // Store left-pressed state in the MousePressed resource
@ -214,7 +208,6 @@ fn handle_mouse(
} }
if accumulated_mouse_motion.delta != Vec2::ZERO { if accumulated_mouse_motion.delta != Vec2::ZERO {
let displacement = accumulated_mouse_motion.delta.x; let displacement = accumulated_mouse_motion.delta.x;
let mut camera_transform = camera.single_mut();
camera_transform.rotate_around(Vec3::ZERO, Quat::from_rotation_y(-displacement / 75.)); camera_transform.rotate_around(Vec3::ZERO, Quat::from_rotation_y(-displacement / 75.));
} }
} }

View file

@ -258,7 +258,7 @@ fn update_transform<T: UpdateTransform + Component>(
fn toggle_overflow( fn toggle_overflow(
mut containers: Query<&mut Style, With<Container>>, mut containers: Query<&mut Style, With<Container>>,
mut instructions: Query<Entity, With<Instructions>>, instructions: Single<Entity, With<Instructions>>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
) { ) {
for mut style in &mut containers { for mut style in &mut containers {
@ -278,7 +278,7 @@ fn toggle_overflow(
_ => Overflow::visible(), _ => Overflow::visible(),
}; };
let entity = instructions.single_mut(); let entity = *instructions;
*writer.text(entity, 1) = format!("{:?}", style.overflow); *writer.text(entity, 1) = format!("{:?}", style.overflow);
} }
} }

View file

@ -68,12 +68,10 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
/// This systems polls the relative cursor position and displays its value in a text component. /// This systems polls the relative cursor position and displays its value in a text component.
fn relative_cursor_position_system( fn relative_cursor_position_system(
relative_cursor_position_query: Query<&RelativeCursorPosition>, relative_cursor_position: Single<&RelativeCursorPosition>,
mut output_query: Query<(&mut Text, &mut TextColor)>, output_query: Single<(&mut Text, &mut TextColor)>,
) { ) {
let relative_cursor_position = relative_cursor_position_query.single(); let (mut output, mut text_color) = output_query.into_inner();
let (mut output, mut text_color) = output_query.single_mut();
**output = if let Some(relative_cursor_position) = relative_cursor_position.normalized { **output = if let Some(relative_cursor_position) = relative_cursor_position.normalized {
format!( format!(

View file

@ -293,28 +293,27 @@ fn update_buttons(
(Entity, &Interaction, &Constraint, &ButtonValue), (Entity, &Interaction, &Constraint, &ButtonValue),
Changed<Interaction>, Changed<Interaction>,
>, >,
mut bar_query: Query<&mut Style, With<Bar>>, mut bar_style: Single<&mut Style, With<Bar>>,
mut text_query: Query<&mut TextColor>, mut text_query: Query<&mut TextColor>,
children_query: Query<&Children>, children_query: Query<&Children>,
mut button_activated_event: EventWriter<ButtonActivatedEvent>, mut button_activated_event: EventWriter<ButtonActivatedEvent>,
) { ) {
let mut style = bar_query.single_mut();
for (button_id, interaction, constraint, value) in button_query.iter_mut() { for (button_id, interaction, constraint, value) in button_query.iter_mut() {
match interaction { match interaction {
Interaction::Pressed => { Interaction::Pressed => {
button_activated_event.send(ButtonActivatedEvent(button_id)); button_activated_event.send(ButtonActivatedEvent(button_id));
match constraint { match constraint {
Constraint::FlexBasis => { Constraint::FlexBasis => {
style.flex_basis = value.0; bar_style.flex_basis = value.0;
} }
Constraint::Width => { Constraint::Width => {
style.width = value.0; bar_style.width = value.0;
} }
Constraint::MinWidth => { Constraint::MinWidth => {
style.min_width = value.0; bar_style.min_width = value.0;
} }
Constraint::MaxWidth => { Constraint::MaxWidth => {
style.max_width = value.0; bar_style.max_width = value.0;
} }
} }
} }

View file

@ -46,10 +46,9 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// A simple system to handle some keyboard input and toggle on/off the hittest. // A simple system to handle some keyboard input and toggle on/off the hittest.
fn toggle_mouse_passthrough( fn toggle_mouse_passthrough(
keyboard_input: Res<ButtonInput<KeyCode>>, keyboard_input: Res<ButtonInput<KeyCode>>,
mut windows: Query<&mut Window>, mut window: Single<&mut Window>,
) { ) {
if keyboard_input.just_pressed(KeyCode::KeyP) { if keyboard_input.just_pressed(KeyCode::KeyP) {
let mut window = windows.single_mut();
window.cursor_options.hit_test = !window.cursor_options.hit_test; window.cursor_options.hit_test = !window.cursor_options.hit_test;
} }
} }

View file

@ -147,7 +147,7 @@ pub(crate) mod test_setup {
pub(crate) fn update_text( pub(crate) fn update_text(
mut frame: Local<usize>, mut frame: Local<usize>,
mode: Res<ExampleMode>, mode: Res<ExampleMode>,
query: Query<Entity, With<ModeText>>, text: Single<Entity, With<ModeText>>,
mut writer: UiTextWriter, mut writer: UiTextWriter,
) { ) {
*frame += 1; *frame += 1;
@ -159,9 +159,8 @@ pub(crate) mod test_setup {
} }
ExampleMode::ApplicationWithWakeUp => "desktop_app(), reactive, WakeUp sent", ExampleMode::ApplicationWithWakeUp => "desktop_app(), reactive, WakeUp sent",
}; };
let text = query.single(); *writer.text(*text, 2) = mode.to_string();
*writer.text(text, 2) = mode.to_string(); *writer.text(*text, 4) = frame.to_string();
*writer.text(text, 4) = frame.to_string();
} }
/// Set up a scene with a cube and some text /// Set up a scene with a cube and some text

View file

@ -67,11 +67,9 @@ fn setup(mut commands: Commands) {
/// Set the title of the window to the current override /// Set the title of the window to the current override
fn display_override( fn display_override(
mut windows: Query<&mut Window>, mut window: Single<&mut Window>,
mut custom_text: Query<&mut Text, With<CustomText>>, mut custom_text: Single<&mut Text, With<CustomText>>,
) { ) {
let mut window = windows.single_mut();
let text = format!( let text = format!(
"Scale factor: {:.1} {}", "Scale factor: {:.1} {}",
window.scale_factor(), window.scale_factor(),
@ -83,13 +81,11 @@ fn display_override(
); );
window.title.clone_from(&text); window.title.clone_from(&text);
**custom_text.single_mut() = text; custom_text.0 = text;
} }
/// This system toggles scale factor overrides when enter is pressed /// This system toggles scale factor overrides when enter is pressed
fn toggle_override(input: Res<ButtonInput<KeyCode>>, mut windows: Query<&mut Window>) { fn toggle_override(input: Res<ButtonInput<KeyCode>>, mut window: Single<&mut Window>) {
let mut window = windows.single_mut();
if input.just_pressed(KeyCode::Enter) { if input.just_pressed(KeyCode::Enter) {
let scale_factor_override = window.resolution.scale_factor_override(); let scale_factor_override = window.resolution.scale_factor_override();
window window
@ -99,8 +95,7 @@ fn toggle_override(input: Res<ButtonInput<KeyCode>>, mut windows: Query<&mut Win
} }
/// This system changes the scale factor override when up or down is pressed /// This system changes the scale factor override when up or down is pressed
fn change_scale_factor(input: Res<ButtonInput<KeyCode>>, mut windows: Query<&mut Window>) { fn change_scale_factor(input: Res<ButtonInput<KeyCode>>, mut window: Single<&mut Window>) {
let mut window = windows.single_mut();
let scale_factor_override = window.resolution.scale_factor_override(); let scale_factor_override = window.resolution.scale_factor_override();
if input.just_pressed(KeyCode::ArrowUp) { if input.just_pressed(KeyCode::ArrowUp) {
window window

View file

@ -56,11 +56,9 @@ fn setup_ui(mut commands: Commands) {
/// This system shows how to request the window to a new resolution /// This system shows how to request the window to a new resolution
fn toggle_resolution( fn toggle_resolution(
keys: Res<ButtonInput<KeyCode>>, keys: Res<ButtonInput<KeyCode>>,
mut windows: Query<&mut Window>, mut window: Single<&mut Window>,
resolution: Res<ResolutionSettings>, resolution: Res<ResolutionSettings>,
) { ) {
let mut window = windows.single_mut();
if keys.just_pressed(KeyCode::Digit1) { if keys.just_pressed(KeyCode::Digit1) {
let res = resolution.small; let res = resolution.small;
window.resolution.set(res.x, res.y); window.resolution.set(res.x, res.y);
@ -78,12 +76,11 @@ fn toggle_resolution(
/// This system shows how to respond to a window being resized. /// This system shows how to respond to a window being resized.
/// Whenever the window is resized, the text will update with the new resolution. /// Whenever the window is resized, the text will update with the new resolution.
fn on_resize_system( fn on_resize_system(
mut q: Query<&mut Text, With<ResolutionText>>, mut text: Single<&mut Text, With<ResolutionText>>,
mut resize_reader: EventReader<WindowResized>, mut resize_reader: EventReader<WindowResized>,
) { ) {
let mut text = q.single_mut();
for e in resize_reader.read() { for e in resize_reader.read() {
// When resolution is being changed // When resolution is being changed
**text = format!("{:.1} x {:.1}", e.width, e.height); text.0 = format!("{:.1} x {:.1}", e.width, e.height);
} }
} }

View file

@ -55,22 +55,20 @@ fn main() {
.run(); .run();
} }
fn make_visible(mut window: Query<&mut Window>, frames: Res<FrameCount>) { fn make_visible(mut window: Single<&mut Window>, frames: Res<FrameCount>) {
// The delay may be different for your app or system. // The delay may be different for your app or system.
if frames.0 == 3 { if frames.0 == 3 {
// At this point the gpu is ready to show the app so we can make the window visible. // At this point the gpu is ready to show the app so we can make the window visible.
// Alternatively, you could toggle the visibility in Startup. // Alternatively, you could toggle the visibility in Startup.
// It will work, but it will have one white frame before it starts rendering // It will work, but it will have one white frame before it starts rendering
window.single_mut().visible = true; window.visible = true;
} }
} }
/// This system toggles the vsync mode when pressing the button V. /// This system toggles the vsync mode when pressing the button V.
/// You'll see fps increase displayed in the console. /// You'll see fps increase displayed in the console.
fn toggle_vsync(input: Res<ButtonInput<KeyCode>>, mut windows: Query<&mut Window>) { fn toggle_vsync(input: Res<ButtonInput<KeyCode>>, mut window: Single<&mut Window>) {
if input.just_pressed(KeyCode::KeyV) { if input.just_pressed(KeyCode::KeyV) {
let mut window = windows.single_mut();
window.present_mode = if matches!(window.present_mode, PresentMode::AutoVsync) { window.present_mode = if matches!(window.present_mode, PresentMode::AutoVsync) {
PresentMode::AutoNoVsync PresentMode::AutoNoVsync
} else { } else {
@ -88,10 +86,8 @@ fn toggle_vsync(input: Res<ButtonInput<KeyCode>>, mut windows: Query<&mut Window
/// [documentation](https://docs.rs/bevy/latest/bevy/prelude/struct.Window.html#structfield.window_level) /// [documentation](https://docs.rs/bevy/latest/bevy/prelude/struct.Window.html#structfield.window_level)
/// for more details. /// for more details.
fn switch_level(input: Res<ButtonInput<KeyCode>>, mut windows: Query<&mut Window>) { fn switch_level(input: Res<ButtonInput<KeyCode>>, mut window: Single<&mut Window>) {
if input.just_pressed(KeyCode::KeyT) { if input.just_pressed(KeyCode::KeyT) {
let mut window = windows.single_mut();
window.window_level = match window.window_level { window.window_level = match window.window_level {
WindowLevel::AlwaysOnBottom => WindowLevel::Normal, WindowLevel::AlwaysOnBottom => WindowLevel::Normal,
WindowLevel::Normal => WindowLevel::AlwaysOnTop, WindowLevel::Normal => WindowLevel::AlwaysOnTop,
@ -106,14 +102,12 @@ fn switch_level(input: Res<ButtonInput<KeyCode>>, mut windows: Query<&mut Window
/// This feature only works on some platforms. Please check the /// This feature only works on some platforms. Please check the
/// [documentation](https://docs.rs/bevy/latest/bevy/prelude/struct.Window.html#structfield.enabled_buttons) /// [documentation](https://docs.rs/bevy/latest/bevy/prelude/struct.Window.html#structfield.enabled_buttons)
/// for more details. /// for more details.
fn toggle_window_controls(input: Res<ButtonInput<KeyCode>>, mut windows: Query<&mut Window>) { fn toggle_window_controls(input: Res<ButtonInput<KeyCode>>, mut window: Single<&mut Window>) {
let toggle_minimize = input.just_pressed(KeyCode::Digit1); let toggle_minimize = input.just_pressed(KeyCode::Digit1);
let toggle_maximize = input.just_pressed(KeyCode::Digit2); let toggle_maximize = input.just_pressed(KeyCode::Digit2);
let toggle_close = input.just_pressed(KeyCode::Digit3); let toggle_close = input.just_pressed(KeyCode::Digit3);
if toggle_minimize || toggle_maximize || toggle_close { if toggle_minimize || toggle_maximize || toggle_close {
let mut window = windows.single_mut();
if toggle_minimize { if toggle_minimize {
window.enabled_buttons.minimize = !window.enabled_buttons.minimize; window.enabled_buttons.minimize = !window.enabled_buttons.minimize;
} }
@ -127,18 +121,15 @@ fn toggle_window_controls(input: Res<ButtonInput<KeyCode>>, mut windows: Query<&
} }
/// This system will then change the title during execution /// This system will then change the title during execution
fn change_title(mut windows: Query<&mut Window>, time: Res<Time>) { fn change_title(mut window: Single<&mut Window>, time: Res<Time>) {
let mut window = windows.single_mut();
window.title = format!( window.title = format!(
"Seconds since startup: {}", "Seconds since startup: {}",
time.elapsed().as_secs_f32().round() time.elapsed().as_secs_f32().round()
); );
} }
fn toggle_cursor(mut windows: Query<&mut Window>, input: Res<ButtonInput<KeyCode>>) { fn toggle_cursor(mut window: Single<&mut Window>, input: Res<ButtonInput<KeyCode>>) {
if input.just_pressed(KeyCode::Space) { if input.just_pressed(KeyCode::Space) {
let mut window = windows.single_mut();
window.cursor_options.visible = !window.cursor_options.visible; window.cursor_options.visible = !window.cursor_options.visible;
window.cursor_options.grab_mode = match window.cursor_options.grab_mode { window.cursor_options.grab_mode = match window.cursor_options.grab_mode {
CursorGrabMode::None => CursorGrabMode::Locked, CursorGrabMode::None => CursorGrabMode::Locked,
@ -148,10 +139,8 @@ fn toggle_cursor(mut windows: Query<&mut Window>, input: Res<ButtonInput<KeyCode
} }
// This system will toggle the color theme used by the window // This system will toggle the color theme used by the window
fn toggle_theme(mut windows: Query<&mut Window>, input: Res<ButtonInput<KeyCode>>) { fn toggle_theme(mut window: Single<&mut Window>, input: Res<ButtonInput<KeyCode>>) {
if input.just_pressed(KeyCode::KeyF) { if input.just_pressed(KeyCode::KeyF) {
let mut window = windows.single_mut();
if let Some(current_theme) = window.window_theme { if let Some(current_theme) = window.window_theme {
window.window_theme = match current_theme { window.window_theme = match current_theme {
WindowTheme::Light => Some(WindowTheme::Dark), WindowTheme::Light => Some(WindowTheme::Dark),
@ -181,17 +170,15 @@ fn init_cursor_icons(mut commands: Commands, asset_server: Res<AssetServer>) {
/// This system cycles the cursor's icon through a small set of icons when clicking /// This system cycles the cursor's icon through a small set of icons when clicking
fn cycle_cursor_icon( fn cycle_cursor_icon(
mut commands: Commands, mut commands: Commands,
windows: Query<Entity, With<Window>>, window: Single<Entity, With<Window>>,
input: Res<ButtonInput<MouseButton>>, input: Res<ButtonInput<MouseButton>>,
mut index: Local<usize>, mut index: Local<usize>,
cursor_icons: Res<CursorIcons>, cursor_icons: Res<CursorIcons>,
) { ) {
let window_entity = windows.single();
if input.just_pressed(MouseButton::Left) { if input.just_pressed(MouseButton::Left) {
*index = (*index + 1) % cursor_icons.0.len(); *index = (*index + 1) % cursor_icons.0.len();
commands commands
.entity(window_entity) .entity(*window)
.insert(cursor_icons.0[*index].clone()); .insert(cursor_icons.0[*index].clone());
} else if input.just_pressed(MouseButton::Right) { } else if input.just_pressed(MouseButton::Right) {
*index = if *index == 0 { *index = if *index == 0 {
@ -200,7 +187,7 @@ fn cycle_cursor_icon(
*index - 1 *index - 1
}; };
commands commands
.entity(window_entity) .entity(*window)
.insert(cursor_icons.0[*index].clone()); .insert(cursor_icons.0[*index].clone());
} }
} }

View file

@ -18,12 +18,11 @@ fn main() {
.run(); .run();
} }
fn minimise_automatically(mut windows: Query<&mut Window>, frames: Res<FrameCount>) { fn minimise_automatically(mut window: Single<&mut Window>, frames: Res<FrameCount>) {
if frames.0 != 60 { if frames.0 != 60 {
return; return;
} }
let mut window = windows.single_mut();
window.set_minimized(true); window.set_minimized(true);
} }

View file

@ -96,9 +96,8 @@ fn change_window_size(
} }
} }
fn sync_dimensions(dim: Res<Dimensions>, mut windows: Query<&mut Window>) { fn sync_dimensions(dim: Res<Dimensions>, mut window: Single<&mut Window>) {
if dim.is_changed() { if dim.is_changed() {
let mut window = windows.single_mut();
window.resolution.set(dim.width as f32, dim.height as f32); window.resolution.set(dim.width as f32, dim.height as f32);
} }
} }