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.measurement_time(core::time::Duration::from_secs(3));
fn empty() {}
fn yes_with_query(query: Query<&TestBool>) -> bool {
query.single().0
fn yes_with_query(query: Single<&TestBool>) -> bool {
query.0
}
for amount in 0..21 {
let mut schedule = Schedule::default();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -72,12 +72,11 @@ fn update_test_state(
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() {
return;
}
let mut text = text.single_mut();
text.clear();
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).
fn fit_canvas(
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() {
let h_scale = event.width / RES_WIDTH 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());
}
}

View file

@ -102,9 +102,9 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
fn player_movement_system(
time: Res<Time>,
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 movement_factor = 0.0;
@ -143,9 +143,8 @@ fn player_movement_system(
/// Demonstrates snapping the enemy ship to face the player ship immediately.
fn snap_to_player_system(
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
let player_translation = player_transform.translation.xy();
@ -186,9 +185,8 @@ fn snap_to_player_system(
fn rotate_to_player_system(
time: Res<Time>,
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
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
fn trigger_animation<S: Component>(mut query: Query<&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();
fn trigger_animation<S: Component>(mut animation: Single<&mut AnimationConfig, With<S>>) {
// we create a new timer when the animation is triggered
animation.frame_timer = AnimationConfig::timer_from_fps(animation.fps);
}

View file

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

View file

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

View file

@ -37,7 +37,7 @@ type TaaComponents = (
fn modify_aa(
keys: Res<ButtonInput<KeyCode>>,
mut camera: Query<
camera: Single<
(
Entity,
Option<&mut Fxaa>,
@ -49,7 +49,7 @@ fn modify_aa(
>,
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);
// No AA
@ -177,7 +177,7 @@ fn modify_sharpening(
}
fn update_ui(
camera: Query<
camera: Single<
(
Option<&Fxaa>,
Option<&Smaa>,
@ -187,12 +187,11 @@ fn update_ui(
),
With<Camera>,
>,
mut ui: Query<&mut Text>,
mut ui: Single<&mut Text>,
) {
let (fxaa, smaa, taa, cas, msaa) = camera.single();
let ui = &mut **ui.single_mut();
let (fxaa, smaa, taa, cas, msaa) = *camera;
let ui = &mut ui.0;
*ui = "Antialias Method\n".to_string();
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>) {
let mut fog = fog.single_mut();
fn toggle_system(keycode: Res<ButtonInput<KeyCode>>, mut fog: Single<&mut DistanceFog>) {
if keycode.just_pressed(KeyCode::Space) {
let a = fog.color.alpha();
fog.color.set_alpha(1.0 - a);

View file

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

View file

@ -254,9 +254,9 @@ impl Default for ExampleState {
fn example_control_system(
mut materials: ResMut<Assets<StandardMaterial>>,
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 display: Query<&mut Text, With<ExampleDisplay>>,
mut display: Single<&mut Text, With<ExampleDisplay>>,
labelled: Query<&GlobalTransform>,
mut state: Local<ExampleState>,
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) {
camera.hdr = !camera.hdr;
@ -321,8 +321,7 @@ fn example_control_system(
style.left = Val::Px(viewport_position.x);
}
let mut display = display.single_mut();
**display = format!(
display.0 = format!(
" HDR: {}\nAlpha: {:.2}",
if camera.hdr { "ON " } else { "OFF" },
state.alpha

View file

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

View file

@ -560,13 +560,13 @@ fn update_ui_state(
&ColorGradingOptionWidget,
)>,
button_text: Query<(Entity, &ColorGradingOptionWidget), (With<Text>, Without<HelpText>)>,
help_text: Query<Entity, With<HelpText>>,
help_text: Single<Entity, With<HelpText>>,
mut writer: UiTextWriter,
cameras: Query<Ref<ColorGrading>>,
cameras: Single<Ref<ColorGrading>>,
currently_selected_option: Res<SelectedColorGradingOption>,
) {
// 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;
}
@ -581,12 +581,7 @@ fn update_ui_state(
}
}
let value_label = cameras.iter().next().map(|color_grading| {
format!(
"{:.3}",
currently_selected_option.get(color_grading.as_ref())
)
});
let value_label = format!("{:.3}", currently_selected_option.get(cameras.as_ref()));
// Update the buttons.
for (entity, widget) in button_text.iter() {
@ -606,16 +601,14 @@ fn update_ui_state(
if widget.widget_type == ColorGradingOptionWidgetType::Value
&& *currently_selected_option == widget.option
{
if let Some(ref value_label) = value_label {
writer.for_each_text(entity, |mut text| {
text.clone_from(value_label);
});
}
writer.for_each_text(entity, |mut text| {
text.clone_from(&value_label);
});
}
}
// 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.
@ -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
/// grading option.
fn adjust_color_grading_option(
mut cameras: Query<&mut ColorGrading>,
mut color_grading: Single<&mut ColorGrading>,
input: Res<ButtonInput<KeyCode>>,
currently_selected_option: Res<SelectedColorGradingOption>,
) {
@ -639,8 +632,7 @@ fn adjust_color_grading_option(
}
if delta != 0.0 {
let mut color_grading = cameras.single_mut();
let new_value = currently_selected_option.get(&color_grading) + delta;
let new_value = currently_selected_option.get(color_grading.as_ref()) + delta;
currently_selected_option.set(&mut color_grading, new_value);
}
}

View file

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

View file

@ -128,16 +128,15 @@ fn setup_instructions(mut commands: Commands) {
}
fn update_system(
mut camera: Query<(&mut DistanceFog, &mut Transform)>,
mut text: Query<&mut Text>,
camera: Single<(&mut DistanceFog, &mut Transform)>,
mut text: Single<&mut Text>,
time: Res<Time>,
keycode: Res<ButtonInput<KeyCode>>,
) {
let now = time.elapsed_seconds();
let delta = time.delta_seconds();
let (mut fog, mut transform) = camera.single_mut();
let mut text = text.single_mut();
let (mut fog, mut transform) = camera.into_inner();
// Orbit camera around pyramid
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);
// 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
text.push_str("\n\n1 / 2 / 3 - Fog Falloff Mode");

View file

@ -253,12 +253,12 @@ fn setup(
fn update_exposure(
key_input: Res<ButtonInput<KeyCode>>,
mut parameters: ResMut<Parameters>,
mut exposure: Query<&mut Exposure>,
text: Query<Entity, With<Text>>,
mut exposure: Single<&mut Exposure>,
text: Single<Entity, With<Text>>,
mut writer: UiTextWriter,
) {
// TODO: Clamp values to a reasonable range
let entity = text.single();
let entity = *text;
if key_input.just_pressed(KeyCode::Digit2) {
parameters.aperture_f_stops *= 2.0;
} 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);
*exposure.single_mut() = Exposure::from_physical_camera(**parameters);
**exposure = Exposure::from_physical_camera(**parameters);
}
fn animate_light_direction(

View file

@ -58,7 +58,7 @@ fn check_for_gltf_extras(
Option<&GltfMeshExtras>,
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![];
@ -86,6 +86,6 @@ fn check_for_gltf_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(
mut motion_blur: Query<&mut MotionBlur>,
mut motion_blur: Single<&mut MotionBlur>,
presses: Res<ButtonInput<KeyCode>>,
text: Query<Entity, With<Text>>,
text: Single<Entity, With<Text>>,
mut writer: UiTextWriter,
mut camera: ResMut<CameraMode>,
) {
let mut motion_blur = motion_blur.single_mut();
if presses.just_pressed(KeyCode::Digit1) {
motion_blur.shutter_angle -= 0.25;
} 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.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, 2) = format!("Samples: {:.5}\n", motion_blur.samples);
}
@ -326,12 +325,11 @@ fn move_cars(
}
fn move_camera(
mut camera: Query<(&mut Transform, &mut Projection), Without<CameraTracked>>,
tracked: Query<&Transform, With<CameraTracked>>,
camera: Single<(&mut Transform, &mut Projection), Without<CameraTracked>>,
tracked: Single<&Transform, With<CameraTracked>>,
mode: Res<CameraMode>,
) {
let tracked = tracked.single();
let (mut transform, mut projection) = camera.single_mut();
let (mut transform, mut projection) = camera.into_inner();
match *mode {
CameraMode::Track => {
transform.look_at(tracked.translation, Vec3::Y);
@ -343,7 +341,7 @@ fn move_camera(
CameraMode::Chase => {
transform.translation =
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 {
perspective.fov = 1.0;
}

View file

@ -66,11 +66,11 @@ fn toggle_oit(
mut commands: Commands,
text: Single<Entity, With<Text>>,
keyboard_input: Res<ButtonInput<KeyCode>>,
q: Query<(Entity, Has<OrderIndependentTransparencySettings>), With<Camera3d>>,
q: Single<(Entity, Has<OrderIndependentTransparencySettings>), With<Camera3d>>,
mut text_writer: UiTextWriter,
) {
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 {
// Removing the component will completely disable OIT for this camera
commands

View file

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

View file

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

View file

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

View file

@ -90,7 +90,7 @@ fn setup(
}
fn update(
camera: Query<
camera: Single<
(
Entity,
Option<&ScreenSpaceAmbientOcclusion>,
@ -98,16 +98,15 @@ fn update(
),
With<Camera>,
>,
mut text: Query<&mut Text>,
mut sphere: Query<&mut Transform, With<SphereMarker>>,
mut text: Single<&mut Text>,
mut sphere: Single<&mut Transform, With<SphereMarker>>,
mut commands: Commands,
keycode: Res<ButtonInput<KeyCode>>,
time: Res<Time>,
) {
let mut sphere = sphere.single_mut();
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 mut commands = commands.entity(camera_entity);
@ -166,7 +165,6 @@ fn update(
}
}
let mut text = text.single_mut();
text.clear();
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(
keys: Res<ButtonInput<KeyCode>>,
mut tonemapping: Query<&mut Tonemapping>,
mut color_grading: Query<&mut ColorGrading>,
mut tonemapping: Single<&mut Tonemapping>,
mut color_grading: Single<&mut ColorGrading>,
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) {
*method = Tonemapping::None;
**tonemapping = Tonemapping::None;
} else if keys.just_pressed(KeyCode::Digit2) {
*method = Tonemapping::Reinhard;
**tonemapping = Tonemapping::Reinhard;
} else if keys.just_pressed(KeyCode::Digit3) {
*method = Tonemapping::ReinhardLuminance;
**tonemapping = Tonemapping::ReinhardLuminance;
} else if keys.just_pressed(KeyCode::Digit4) {
*method = Tonemapping::AcesFitted;
**tonemapping = Tonemapping::AcesFitted;
} else if keys.just_pressed(KeyCode::Digit5) {
*method = Tonemapping::AgX;
**tonemapping = Tonemapping::AgX;
} else if keys.just_pressed(KeyCode::Digit6) {
*method = Tonemapping::SomewhatBoringDisplayTransform;
**tonemapping = Tonemapping::SomewhatBoringDisplayTransform;
} else if keys.just_pressed(KeyCode::Digit7) {
*method = Tonemapping::TonyMcMapface;
**tonemapping = Tonemapping::TonyMcMapface;
} else if keys.just_pressed(KeyCode::Digit8) {
*method = Tonemapping::BlenderFilmic;
**tonemapping = Tonemapping::BlenderFilmic;
}
*color_grading = (*per_method_settings
**color_grading = (*per_method_settings
.settings
.get::<Tonemapping>(&method)
.get::<Tonemapping>(&tonemapping)
.as_ref()
.unwrap())
.clone();
@ -337,12 +334,11 @@ fn update_color_grading_settings(
keys: Res<ButtonInput<KeyCode>>,
time: Res<Time>,
mut per_method_settings: ResMut<PerMethodSettings>,
tonemapping: Query<&Tonemapping>,
tonemapping: Single<&Tonemapping>,
current_scene: Res<CurrentScene>,
mut selected_parameter: ResMut<SelectedParameter>,
) {
let method = tonemapping.single();
let color_grading = per_method_settings.settings.get_mut(method).unwrap();
let color_grading = per_method_settings.settings.get_mut(*tonemapping).unwrap();
let mut dt = time.delta_seconds() * 0.25;
if keys.pressed(KeyCode::ArrowLeft) {
dt = -dt;
@ -390,8 +386,8 @@ fn update_color_grading_settings(
}
fn update_ui(
mut text_query: Query<&mut Text, Without<SceneNumber>>,
settings: Query<(&Tonemapping, &ColorGrading)>,
mut text_query: Single<&mut Text, Without<SceneNumber>>,
settings: Single<(&Tonemapping, &ColorGrading)>,
current_scene: Res<CurrentScene>,
selected_parameter: Res<SelectedParameter>,
mut hide_ui: Local<bool>,
@ -401,21 +397,19 @@ fn update_ui(
*hide_ui = !*hide_ui;
}
let old_text = text_query.single();
if *hide_ui {
if !old_text.is_empty() {
if !text_query.is_empty() {
// single_mut() always triggers change detection,
// so only access if text actually needs changing
text_query.single_mut().clear();
text_query.clear();
}
return;
}
let (tonemapping, color_grading) = settings.single();
let (tonemapping, color_grading) = *settings;
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;
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");
}
if text != old_text.as_str() {
if text != text_query.as_str() {
// single_mut() always triggers change detection,
// 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 materials: ResMut<Assets<StandardMaterial>>,
controllable: Query<(&MeshMaterial3d<StandardMaterial>, &ExampleControls)>,
mut camera: Query<
camera: Single<
(
Entity,
&mut Camera,
@ -396,7 +396,7 @@ fn example_control_system(
),
With<Camera3d>,
>,
mut display: Query<&mut Text, With<ExampleDisplay>>,
mut display: Single<&mut Text, With<ExampleDisplay>>,
mut state: Local<ExampleState>,
time: Res<Time>,
input: Res<ButtonInput<KeyCode>>,
@ -466,7 +466,7 @@ fn example_control_system(
mut camera_transform,
depth_prepass,
temporal_jitter,
) = camera.single_mut();
) = camera.into_inner();
if input.just_pressed(KeyCode::KeyH) {
camera.hdr = !camera.hdr;
@ -548,7 +548,7 @@ fn example_control_system(
Quat::from_euler(EulerRot::XYZ, 0.0, rotation, 0.0),
);
**display.single_mut() = format!(
display.0 = format!(
concat!(
" J / K / L / ; Screen Space Specular Transmissive Quality: {:?}\n",
" O / P Screen Space Specular Transmissive Steps: {}\n",
@ -599,20 +599,19 @@ fn example_control_system(
}
fn flicker_system(
mut flame: Query<&mut Transform, (With<Flicker>, With<Mesh3d>)>,
mut light: Query<(&mut PointLight, &mut Transform), (With<Flicker>, Without<Mesh3d>)>,
mut flame: Single<&mut Transform, (With<Flicker>, With<Mesh3d>)>,
light: Single<(&mut PointLight, &mut Transform), (With<Flicker>, Without<Mesh3d>)>,
time: Res<Time>,
) {
let s = time.elapsed_seconds();
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 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 flame_transform = flame.single_mut();
let (mut light, mut light_transform) = light.into_inner();
light.intensity = 4_000.0 + 3000.0 * (a + b + c);
flame_transform.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_transform.rotate(Quat::from_euler(EulerRot::XYZ, 0.0, 0.0, PI / 2.0));
flame.translation = Vec3::new(-1.0, 1.23, 0.0);
flame.look_at(Vec3::new(-1.0 - c, 1.7 - b, 0.0 - a), Vec3::X);
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);
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>>,
mut config: ResMut<WireframeConfig>,
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
---------------
Z - Toggle global

View file

@ -137,9 +137,9 @@ fn setup(mut commands: Commands) {
fn print_logs(
mut events: EventReader<LogEvent>,
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| {
for event in events.read() {

View file

@ -108,22 +108,20 @@ fn update_emitters(
fn update_listener(
keyboard: Res<ButtonInput<KeyCode>>,
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.;
if keyboard.pressed(KeyCode::ArrowRight) {
transform.translation.x += speed * time.delta_seconds();
listener.translation.x += speed * time.delta_seconds();
}
if keyboard.pressed(KeyCode::ArrowLeft) {
transform.translation.x -= speed * time.delta_seconds();
listener.translation.x -= speed * time.delta_seconds();
}
if keyboard.pressed(KeyCode::ArrowUp) {
transform.translation.y += speed * time.delta_seconds();
listener.translation.y += speed * time.delta_seconds();
}
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(
keyboard: Res<ButtonInput<KeyCode>>,
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.;
if keyboard.pressed(KeyCode::ArrowRight) {
transform.translation.x += speed * time.delta_seconds();
listeners.translation.x += speed * time.delta_seconds();
}
if keyboard.pressed(KeyCode::ArrowLeft) {
transform.translation.x -= speed * time.delta_seconds();
listeners.translation.x -= speed * time.delta_seconds();
}
if keyboard.pressed(KeyCode::ArrowDown) {
transform.translation.z += speed * time.delta_seconds();
listeners.translation.z += speed * time.delta_seconds();
}
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(
mut camera: Query<&mut Transform, With<Camera>>,
mut camera: Single<&mut Transform, With<Camera>>,
camera_settings: Res<CameraSettings>,
mouse_buttons: Res<ButtonInput<MouseButton>>,
mouse_motion: Res<AccumulatedMouseMotion>,
time: Res<Time>,
) {
let mut transform = camera.single_mut();
let delta = mouse_motion.delta;
let mut delta_roll = 0.0;
@ -129,7 +128,7 @@ fn orbit(
delta_roll *= camera_settings.roll_speed * time.delta_seconds();
// 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.
let pitch = (pitch + delta_pitch).clamp(
@ -138,10 +137,10 @@ fn orbit(
);
let roll = roll + delta_roll;
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.
// In our example it's a static target, but this could easily be customised.
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(
mut camera: Query<&mut Projection, With<Camera>>,
mut camera: Single<&mut Projection, With<Camera>>,
camera_settings: Res<CameraSettings>,
keyboard_input: Res<ButtonInput<KeyCode>>,
) {
let mut projection = camera.single_mut();
if keyboard_input.just_pressed(KeyCode::Space) {
// Switch projection type
*projection = match *projection {
**camera = match **camera {
Projection::Orthographic(_) => Projection::Perspective(PerspectiveProjection {
fov: camera_settings.perspective_zoom_range.start,
..default()
@ -136,14 +134,12 @@ fn switch_projection(
}
fn zoom(
mut camera: Query<&mut Projection, With<Camera>>,
camera: Single<&mut Projection, With<Camera>>,
camera_settings: Res<CameraSettings>,
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.
match projection.into_inner() {
match *camera.into_inner() {
Projection::Orthographic(ref mut orthographic) => {
// Get the current scaling_mode value to allow clamping the new value to our zoom range.
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(
mut camera: Query<&mut Transform, (With<Camera>, Without<Star>)>,
star: Query<&Transform, With<Star>>,
mut camera: Single<&mut Transform, (With<Camera>, Without<Star>)>,
star: Single<&Transform, With<Star>>,
) {
let mut camera = camera.single_mut();
let star = star.single();
let new_rotation = camera
.looking_at(star.translation, Vec3::Y)
.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
fn handle_click(
mouse_button_input: Res<ButtonInput<MouseButton>>,
camera: Query<(&Camera, &GlobalTransform)>,
windows: Query<&Window>,
camera: Single<(&Camera, &GlobalTransform)>,
windows: Single<&Window>,
mut commands: Commands,
) {
let (camera, camera_transform) = camera.single();
let (camera, camera_transform) = *camera;
if let Some(pos) = windows
.single()
.cursor_position()
.and_then(|cursor| camera.viewport_to_world(camera_transform, cursor).ok())
.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.
fn trigger_system(
mut commands: Commands,
query_a: Query<Entity, With<A>>,
query_b: Query<Entity, With<B>>,
query_a: Single<Entity, With<A>>,
query_b: Single<Entity, With<B>>,
input: Res<ButtonInput<KeyCode>>,
) {
if input.just_pressed(KeyCode::KeyA) {
let entity = query_a.single();
let entity = *query_a;
commands.entity(entity).insert(Triggered);
}
if input.just_pressed(KeyCode::KeyB) {
let entity = query_b.single();
let entity = *query_b;
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) {
*writer.text(query.single(), 3) = String::from("A");
fn system_a(entity_a: Single<Entity, With<Text>>, mut writer: UiTextWriter) {
*writer.text(*entity_a, 3) = String::from("A");
info!("A: One shot system registered with Commands was triggered");
}
fn system_b(query: Query<Entity, With<Text>>, mut writer: UiTextWriter) {
*writer.text(query.single(), 3) = String::from("B");
fn system_b(entity_b: Single<Entity, With<Text>>, mut writer: UiTextWriter) {
*writer.text(*entity_b, 3) = String::from("B");
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
fn bounce_system(windows: Query<&Window>, mut sprites: Query<(&Transform, &mut Velocity)>) {
let window = windows.single();
fn bounce_system(window: Single<&Window>, mut sprites: Query<(&Transform, &mut Velocity)>) {
let width = window.width();
let height = window.height();
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
fn scoreboard_system(game: Res<Game>, mut query: Query<&mut Text>) {
**query.single_mut() = format!("Sugar Rush: {}", game.score);
fn scoreboard_system(game: Res<Game>, mut display: Single<&mut Text>) {
display.0 = format!("Sugar Rush: {}", game.score);
}
// restart the game when pressing spacebar

View file

@ -301,10 +301,9 @@ fn setup(
fn move_paddle(
keyboard_input: Res<ButtonInput<KeyCode>>,
mut query: Query<&mut Transform, With<Paddle>>,
mut paddle_transform: Single<&mut Transform, With<Paddle>>,
time: Res<Time>,
) {
let mut paddle_transform = query.single_mut();
let mut direction = 0.0;
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(
score: Res<Score>,
query: Query<Entity, (With<ScoreboardUi>, With<Text>)>,
score_root: Single<Entity, (With<ScoreboardUi>, With<Text>)>,
mut writer: UiTextWriter,
) {
*writer.text(query.single(), 1) = score.to_string();
*writer.text(*score_root, 1) = score.to_string();
}
fn check_for_collisions(
mut commands: Commands,
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>>,
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 {
let collision = ball_collision(

View file

@ -159,7 +159,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
fn selection(
mut timer: ResMut<SelectionTimer>,
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 writer: UiTextWriter,
time: Res<Time>,
@ -186,7 +186,7 @@ fn selection(
let entity = contributor_selection.order[contributor_selection.idx];
if let Ok((contributor, mut sprite, mut transform)) = query.get_mut(entity) {
let entity = text_query.single();
let entity = *contributor_root;
select(
&mut sprite,
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
/// force.
fn collisions(
windows: Query<&Window>,
window: Single<&Window>,
mut query: Query<(&mut Velocity, &mut Transform), With<Contributor>>,
) {
let window = windows.single();
let window_size = window.size();
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
fn get_cursor_world_pos(
mut cursor_world_pos: ResMut<CursorWorldPos>,
q_primary_window: Query<&Window, With<PrimaryWindow>>,
q_camera: Query<(&Camera, &GlobalTransform)>,
primary_window: Single<&Window, With<PrimaryWindow>>,
q_camera: Single<(&Camera, &GlobalTransform)>,
) {
let primary_window = q_primary_window.single();
let (main_camera, main_camera_transform) = q_camera.single();
let (main_camera, main_camera_transform) = *q_camera;
// Get the cursor position in the world
cursor_world_pos.0 = primary_window.cursor_position().and_then(|cursor_pos| {
main_camera
@ -221,11 +220,9 @@ fn get_cursor_world_pos(
/// Update whether the window is clickable or not
fn update_cursor_hit_test(
cursor_world_pos: Res<CursorWorldPos>,
mut q_primary_window: Query<&mut Window, With<PrimaryWindow>>,
q_bevy_logo: Query<&Transform, With<BevyLogo>>,
mut primary_window: Single<&mut Window, With<PrimaryWindow>>,
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 primary_window.decorations {
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
let bevy_logo_transform = q_bevy_logo.single();
primary_window.cursor_options.hit_test = bevy_logo_transform
.translation
.truncate()
@ -250,7 +246,7 @@ fn update_cursor_hit_test(
fn start_drag(
mut commands: Commands,
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
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
let bevy_logo_transform = q_bevy_logo.single();
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
@ -277,7 +272,7 @@ fn drag(
drag_offset: Res<DragOperation>,
cursor_world_pos: Res<CursorWorldPos>,
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>,
) {
// If the cursor is not within the primary window skip this system
@ -285,9 +280,6 @@ fn drag(
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
let new_translation = cursor_world_pos + drag_offset.0;
@ -310,7 +302,7 @@ fn drag(
fn quit(
cursor_world_pos: Res<CursorWorldPos>,
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
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
let bevy_logo_transform = q_bevy_logo.single();
if bevy_logo_transform
.translation
.truncate()
@ -334,7 +325,7 @@ fn toggle_transparency(
mut commands: Commands,
mut window_transparency: ResMut<WindowTransparency>,
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
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
// only if window transparency is enabled
let mut window = q_primary_window.single_mut();
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)
} else {
(true, WindowLevel::Normal, WINDOW_CLEAR_COLOR)

View file

@ -361,13 +361,13 @@ mod menu {
// the button as the one currently selected
fn setting_button<T: Resource + Component + PartialEq + Copy>(
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 setting: ResMut<T>,
) {
let (previous_button, mut previous_button_color) = selected_query.into_inner();
for (interaction, button_setting, entity) in &interaction_query {
if *interaction == Interaction::Pressed && *setting != *button_setting {
let (previous_button, mut previous_button_color) = selected_query.single_mut();
*previous_button_color = NORMAL_BUTTON.into();
commands.entity(previous_button).remove::<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
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>,
) {
let visibility = match loading_state.as_ref() {
@ -283,7 +283,7 @@ fn display_loading_screen(
LoadingState::LevelReady => Visibility::Hidden,
};
*loading_screen.single_mut() = visibility;
**loading_screen = visibility;
}
mod pipelines_ready {

View file

@ -239,15 +239,11 @@ fn update_ui(
mut commands: Commands,
state: Res<State>,
stepping: Res<Stepping>,
ui: Query<(Entity, &Visibility), With<SteppingUi>>,
ui: Single<(Entity, &Visibility), With<SteppingUi>>,
mut writer: UiTextWriter,
) {
if ui.is_empty() {
return;
}
// ensure the UI is only visible when stepping is enabled
let (ui, vis) = ui.single();
let (ui, vis) = *ui;
match (vis, stepping.is_enabled()) {
(Visibility::Hidden, true) => {
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>) {
let mut transform = query.single_mut();
fn rotate_camera(mut transform: Single<&mut Transform, With<Camera>>, time: Res<Time>) {
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>,
keyboard: Res<ButtonInput<KeyCode>>,
time: Res<Time>,
color_text_query: Query<Entity, With<GizmoColorText>>,
color_text_query: Single<Entity, With<GizmoColorText>>,
mut writer: UiTextWriter,
) {
if keyboard.just_pressed(KeyCode::KeyD) {
@ -174,6 +172,6 @@ fn update_config(
LightGizmoColor::MatchLightColor => LightGizmoColor::ByLightType,
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
// and releases it when the escape key is pressed
fn grab_mouse(
mut windows: Query<&mut Window>,
mut window: Single<&mut Window>,
mouse: Res<ButtonInput<MouseButton>>,
key: Res<ButtonInput<KeyCode>>,
) {
let mut window = windows.single_mut();
if mouse.just_pressed(MouseButton::Left) {
window.cursor_options.visible = false;
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(
input: Res<ButtonInput<MouseButton>>,
mut windows: Query<&mut Window>,
status_text: Query<Entity, (With<Node>, With<Text>)>,
mut window: Single<&mut Window>,
status_text: Single<Entity, (With<Node>, With<Text>)>,
mut ui_writer: UiTextWriter,
) {
if input.just_pressed(MouseButton::Left) {
let mut window = windows.single_mut();
window.ime_position = window.cursor_position().unwrap();
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(
mut events: EventReader<Ime>,
status_text: Query<Entity, (With<Node>, With<Text>)>,
mut edit_text: Query<&mut Text2d, (Without<Node>, Without<Bubble>)>,
status_text: Single<Entity, (With<Node>, With<Text>)>,
mut edit_text: Single<&mut Text2d, (Without<Node>, Without<Bubble>)>,
mut ui_writer: UiTextWriter,
) {
for event in events.read() {
match event {
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() => {
*ui_writer.text(status_text.single(), 7) = "\n".to_string();
*ui_writer.text(*status_text, 7) = "\n".to_string();
}
Ime::Commit { value, .. } => {
edit_text.single_mut().push_str(value);
edit_text.push_str(value);
}
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 { .. } => {
*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(
mut commands: Commands,
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() {
// Only trigger changes when the key is first pressed.
if !event.state.is_pressed() {
@ -147,7 +146,6 @@ fn listen_keyboard_input_events(
match &event.logical_key {
Key::Enter => {
let (mut text, style) = edit_text.single_mut();
if text.is_empty() {
continue;
}
@ -162,13 +160,13 @@ fn listen_keyboard_input_events(
));
}
Key::Space => {
edit_text.single_mut().0.push(' ');
text.push(' ');
}
Key::Backspace => {
edit_text.single_mut().0.pop();
text.pop();
}
Key::Character(character) => {
edit_text.single_mut().0.push_str(character);
text.push_str(character);
}
_ => continue,
}

View file

@ -259,7 +259,7 @@ fn update_bounding_shape(
fn switch_cameras(
current: Res<State<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() {
CameraActive::Dim2 => CameraActive::Dim3,
@ -267,7 +267,7 @@ fn switch_cameras(
};
next.set(next_state);
let (mut transform, mut projection) = camera.single_mut();
let (mut transform, mut projection) = camera.into_inner();
match next_state {
CameraActive::Dim2 => {
*transform = TRANSFORM_2D;

View file

@ -222,7 +222,7 @@ fn handle_keypress(
fn handle_mouse(
accumulated_mouse_motion: Res<AccumulatedMouseMotion>,
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>,
) {
// Store left-pressed state in the MousePressed resource
@ -239,7 +239,6 @@ fn handle_mouse(
}
if accumulated_mouse_motion.delta != Vec2::ZERO {
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.));
}
}

View file

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

View file

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

View file

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

View file

@ -90,14 +90,12 @@ fn setup(
}
fn move_target(
mut target: Query<&mut Transform, With<TargetSphere>>,
mut target: Single<&mut Transform, With<TargetSphere>>,
target_speed: Res<TargetSphereSpeed>,
mut target_pos: ResMut<TargetPosition>,
time: Res<Time>,
mut rng: ResMut<RandomSource>,
) {
let mut target = target.single_mut();
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-
// defined direction between them, so let's move closer:
@ -119,13 +117,11 @@ fn move_target(
}
fn move_follower(
mut following: Query<&mut Transform, With<FollowingSphere>>,
target: Query<&Transform, (With<TargetSphere>, Without<FollowingSphere>)>,
mut following: Single<&mut Transform, With<FollowingSphere>>,
target: Single<&Transform, (With<TargetSphere>, Without<FollowingSphere>)>,
decay_rate: Res<DecayRate>,
time: Res<Time>,
) {
let target = target.single();
let mut following = following.single_mut();
let decay_rate = decay_rate.0;
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>>) {
commands.entity(query.single()).remove::<Cube>();
fn remove(mut commands: Commands, cube_entity: Single<Entity, With<Cube>>) {
commands.entity(*cube_entity).remove::<Cube>();
}
#[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.
fn switch_textures(images: Res<GameOfLifeImages>, mut displayed: Query<&mut Sprite>) {
let mut sprite = displayed.single_mut();
fn switch_textures(images: Res<GameOfLifeImages>, mut sprite: Single<&mut Sprite>) {
if sprite.image == images.texture_a {
sprite.image = images.texture_b.clone_weak();
} else {

View file

@ -51,9 +51,7 @@ fn setup(
));
}
fn rotate_camera(mut camera: Query<&mut Transform, With<MainCamera>>, time: Res<Time>) {
let cam_transform = camera.single_mut().into_inner();
fn rotate_camera(mut cam_transform: Single<&mut Transform, With<MainCamera>>, time: Res<Time>) {
cam_transform.rotate_around(
Vec3::ZERO,
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(
mut prepass_view: Local<u32>,
keycode: Res<ButtonInput<KeyCode>>,
material_handle: Query<&MeshMaterial3d<PrepassOutputMaterial>>,
material_handle: Single<&MeshMaterial3d<PrepassOutputMaterial>>,
mut materials: ResMut<Assets<PrepassOutputMaterial>>,
text: Query<Entity, With<Text>>,
text: Single<Entity, With<Text>>,
mut writer: UiTextWriter,
) {
if keycode.just_pressed(KeyCode::Space) {
@ -227,14 +227,13 @@ fn toggle_prepass_view(
3 => "motion vectors",
_ => unreachable!(),
};
let text = text.single();
let text = *text;
*writer.text(text, 1) = format!("Prepass Output: {label}\n");
writer.for_each_color(text, |mut color| {
color.0 = Color::WHITE;
});
let handle = material_handle.single();
let mat = materials.get_mut(handle).unwrap();
let mat = materials.get_mut(*material_handle).unwrap();
mat.settings.show_depth = (*prepass_view == 1) as u32;
mat.settings.show_normals = (*prepass_view == 2) 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");
}
fn teardown_game(mut commands: Commands, player: Query<Entity, With<Sprite>>) {
commands.entity(player.single()).despawn();
fn teardown_game(mut commands: Commands, player: Single<Entity, With<Sprite>>) {
commands.entity(*player).despawn();
info!("Teardown game");
}

View file

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

View file

@ -100,10 +100,9 @@ fn setup(
}
// System for rotating and translating the camera
fn move_camera(time: Res<Time>, mut camera_query: Query<&mut Transform, With<Camera>>) {
let mut camera_transform = camera_query.single_mut();
fn move_camera(time: Res<Time>, mut camera_transform: Single<&mut Transform, With<Camera>>) {
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());
}

View file

@ -438,9 +438,8 @@ fn spherical_polar_to_cartesian(p: DVec2) -> DVec3 {
fn move_camera(
time: Res<Time>,
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
* if args.benchmark {
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>) {
let mut text = query.single_mut();
fn ui_system(mut text: Single<&mut Text>, config: Res<Config>, diag: Res<DiagnosticsStore>) {
let Some(fps) = diag
.get(&FrameTimeDiagnosticsPlugin::FPS)
.and_then(Diagnostic::smoothed)
@ -108,7 +106,7 @@ fn ui_system(mut query: Query<&mut Text>, config: Res<Config>, diag: Res<Diagnos
return;
};
**text = format!(
text.0 = format!(
"Line count: {}\n\
FPS: {:.0}\n\n\
Controls:\n\

View file

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

View file

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

View file

@ -178,7 +178,7 @@ impl MorphKey {
}
fn update_text(
controls: Option<ResMut<WeightsControl>>,
text: Query<Entity, With<Text>>,
text: Single<Entity, With<Text>>,
morphs: Query<&MorphWeights>,
mut writer: UiTextWriter,
) {
@ -196,7 +196,7 @@ fn update_text(
target.weight = actual_weight;
}
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(

View file

@ -119,28 +119,26 @@ fn setup(
// Update systems
// Draw the main and secondary axes on the rotating ship
fn draw_ship_axes(mut gizmos: Gizmos, query: Query<&Transform, With<Ship>>) {
let ship_transform = query.single();
fn draw_ship_axes(mut gizmos: Gizmos, ship_transform: Single<&Transform, With<Ship>>) {
// 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);
// 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.));
}
// Draw the randomly generated axes
fn draw_random_axes(mut gizmos: Gizmos, query: Query<&RandomAxes>) {
let RandomAxes(v1, v2) = query.single();
fn draw_random_axes(mut gizmos: Gizmos, random_axes: Single<&RandomAxes>) {
let RandomAxes(v1, v2) = *random_axes;
gizmos.arrow(Vec3::ZERO, 1.5 * *v1, WHITE);
gizmos.arrow(Vec3::ZERO, 1.5 * *v2, GRAY);
}
// 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>) {
let (mut ship, mut ship_transform) = ship.single_mut();
fn rotate_ship(ship: Single<(&mut Ship, &mut Transform)>, time: Res<Time>) {
let (mut ship, mut ship_transform) = ship.into_inner();
if !ship.in_motion {
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
fn handle_keypress(
mut ship: Query<&mut Ship>,
mut random_axes: Query<&mut RandomAxes>,
mut instructions: Query<&mut Visibility, With<Instructions>>,
mut ship: Single<&mut Ship>,
mut random_axes: Single<&mut RandomAxes>,
mut instructions_viz: Single<&mut Visibility, With<Instructions>>,
keyboard: Res<ButtonInput<KeyCode>>,
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) {
// Randomize the target axes
let first = 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
ship.in_motion = false;
@ -184,11 +179,10 @@ fn handle_keypress(
}
if keyboard.just_pressed(KeyCode::KeyH) {
let mut instructions_viz = instructions.single_mut();
if *instructions_viz == Visibility::Hidden {
*instructions_viz = Visibility::Visible;
if *instructions_viz.as_ref() == Visibility::Hidden {
**instructions_viz = Visibility::Visible;
} else {
*instructions_viz = Visibility::Hidden;
**instructions_viz = Visibility::Hidden;
}
}
}
@ -197,7 +191,7 @@ fn handle_keypress(
fn handle_mouse(
accumulated_mouse_motion: Res<AccumulatedMouseMotion>,
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>,
) {
// Store left-pressed state in the MousePressed resource
@ -214,7 +208,6 @@ fn handle_mouse(
}
if accumulated_mouse_motion.delta != Vec2::ZERO {
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.));
}
}

View file

@ -258,7 +258,7 @@ fn update_transform<T: UpdateTransform + Component>(
fn toggle_overflow(
mut containers: Query<&mut Style, With<Container>>,
mut instructions: Query<Entity, With<Instructions>>,
instructions: Single<Entity, With<Instructions>>,
mut writer: UiTextWriter,
) {
for mut style in &mut containers {
@ -278,7 +278,7 @@ fn toggle_overflow(
_ => Overflow::visible(),
};
let entity = instructions.single_mut();
let entity = *instructions;
*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.
fn relative_cursor_position_system(
relative_cursor_position_query: Query<&RelativeCursorPosition>,
mut output_query: Query<(&mut Text, &mut TextColor)>,
relative_cursor_position: Single<&RelativeCursorPosition>,
output_query: Single<(&mut Text, &mut TextColor)>,
) {
let relative_cursor_position = relative_cursor_position_query.single();
let (mut output, mut text_color) = output_query.single_mut();
let (mut output, mut text_color) = output_query.into_inner();
**output = if let Some(relative_cursor_position) = relative_cursor_position.normalized {
format!(

View file

@ -293,28 +293,27 @@ fn update_buttons(
(Entity, &Interaction, &Constraint, &ButtonValue),
Changed<Interaction>,
>,
mut bar_query: Query<&mut Style, With<Bar>>,
mut bar_style: Single<&mut Style, With<Bar>>,
mut text_query: Query<&mut TextColor>,
children_query: Query<&Children>,
mut button_activated_event: EventWriter<ButtonActivatedEvent>,
) {
let mut style = bar_query.single_mut();
for (button_id, interaction, constraint, value) in button_query.iter_mut() {
match interaction {
Interaction::Pressed => {
button_activated_event.send(ButtonActivatedEvent(button_id));
match constraint {
Constraint::FlexBasis => {
style.flex_basis = value.0;
bar_style.flex_basis = value.0;
}
Constraint::Width => {
style.width = value.0;
bar_style.width = value.0;
}
Constraint::MinWidth => {
style.min_width = value.0;
bar_style.min_width = value.0;
}
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.
fn toggle_mouse_passthrough(
keyboard_input: Res<ButtonInput<KeyCode>>,
mut windows: Query<&mut Window>,
mut window: Single<&mut Window>,
) {
if keyboard_input.just_pressed(KeyCode::KeyP) {
let mut window = windows.single_mut();
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(
mut frame: Local<usize>,
mode: Res<ExampleMode>,
query: Query<Entity, With<ModeText>>,
text: Single<Entity, With<ModeText>>,
mut writer: UiTextWriter,
) {
*frame += 1;
@ -159,9 +159,8 @@ pub(crate) mod test_setup {
}
ExampleMode::ApplicationWithWakeUp => "desktop_app(), reactive, WakeUp sent",
};
let text = query.single();
*writer.text(text, 2) = mode.to_string();
*writer.text(text, 4) = frame.to_string();
*writer.text(*text, 2) = mode.to_string();
*writer.text(*text, 4) = frame.to_string();
}
/// 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
fn display_override(
mut windows: Query<&mut Window>,
mut custom_text: Query<&mut Text, With<CustomText>>,
mut window: Single<&mut Window>,
mut custom_text: Single<&mut Text, With<CustomText>>,
) {
let mut window = windows.single_mut();
let text = format!(
"Scale factor: {:.1} {}",
window.scale_factor(),
@ -83,13 +81,11 @@ fn display_override(
);
window.title.clone_from(&text);
**custom_text.single_mut() = text;
custom_text.0 = text;
}
/// This system toggles scale factor overrides when enter is pressed
fn toggle_override(input: Res<ButtonInput<KeyCode>>, mut windows: Query<&mut Window>) {
let mut window = windows.single_mut();
fn toggle_override(input: Res<ButtonInput<KeyCode>>, mut window: Single<&mut Window>) {
if input.just_pressed(KeyCode::Enter) {
let scale_factor_override = window.resolution.scale_factor_override();
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
fn change_scale_factor(input: Res<ButtonInput<KeyCode>>, mut windows: Query<&mut Window>) {
let mut window = windows.single_mut();
fn change_scale_factor(input: Res<ButtonInput<KeyCode>>, mut window: Single<&mut Window>) {
let scale_factor_override = window.resolution.scale_factor_override();
if input.just_pressed(KeyCode::ArrowUp) {
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
fn toggle_resolution(
keys: Res<ButtonInput<KeyCode>>,
mut windows: Query<&mut Window>,
mut window: Single<&mut Window>,
resolution: Res<ResolutionSettings>,
) {
let mut window = windows.single_mut();
if keys.just_pressed(KeyCode::Digit1) {
let res = resolution.small;
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.
/// Whenever the window is resized, the text will update with the new resolution.
fn on_resize_system(
mut q: Query<&mut Text, With<ResolutionText>>,
mut text: Single<&mut Text, With<ResolutionText>>,
mut resize_reader: EventReader<WindowResized>,
) {
let mut text = q.single_mut();
for e in resize_reader.read() {
// 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();
}
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.
if frames.0 == 3 {
// 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.
// 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.
/// 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) {
let mut window = windows.single_mut();
window.present_mode = if matches!(window.present_mode, PresentMode::AutoVsync) {
PresentMode::AutoNoVsync
} 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)
/// 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) {
let mut window = windows.single_mut();
window.window_level = match window.window_level {
WindowLevel::AlwaysOnBottom => WindowLevel::Normal,
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
/// [documentation](https://docs.rs/bevy/latest/bevy/prelude/struct.Window.html#structfield.enabled_buttons)
/// 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_maximize = input.just_pressed(KeyCode::Digit2);
let toggle_close = input.just_pressed(KeyCode::Digit3);
if toggle_minimize || toggle_maximize || toggle_close {
let mut window = windows.single_mut();
if toggle_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
fn change_title(mut windows: Query<&mut Window>, time: Res<Time>) {
let mut window = windows.single_mut();
fn change_title(mut window: Single<&mut Window>, time: Res<Time>) {
window.title = format!(
"Seconds since startup: {}",
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) {
let mut window = windows.single_mut();
window.cursor_options.visible = !window.cursor_options.visible;
window.cursor_options.grab_mode = match window.cursor_options.grab_mode {
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
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) {
let mut window = windows.single_mut();
if let Some(current_theme) = window.window_theme {
window.window_theme = match current_theme {
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
fn cycle_cursor_icon(
mut commands: Commands,
windows: Query<Entity, With<Window>>,
window: Single<Entity, With<Window>>,
input: Res<ButtonInput<MouseButton>>,
mut index: Local<usize>,
cursor_icons: Res<CursorIcons>,
) {
let window_entity = windows.single();
if input.just_pressed(MouseButton::Left) {
*index = (*index + 1) % cursor_icons.0.len();
commands
.entity(window_entity)
.entity(*window)
.insert(cursor_icons.0[*index].clone());
} else if input.just_pressed(MouseButton::Right) {
*index = if *index == 0 {
@ -200,7 +187,7 @@ fn cycle_cursor_icon(
*index - 1
};
commands
.entity(window_entity)
.entity(*window)
.insert(cursor_icons.0[*index].clone());
}
}

View file

@ -18,12 +18,11 @@ fn main() {
.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 {
return;
}
let mut window = windows.single_mut();
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() {
let mut window = windows.single_mut();
window.resolution.set(dim.width as f32, dim.height as f32);
}
}