Query::get_unique (#1263)
Adds `get_unique` and `get_unique_mut` to extend the query api and cover a common use case. Also establishes a second impl block where non-core APIs that don't access the internal fields of queries can live.
This commit is contained in:
parent
2c203f7b8f
commit
9d60563adf
@ -7,7 +7,7 @@ use crate::{
|
|||||||
world::{Mut, World},
|
world::{Mut, World},
|
||||||
};
|
};
|
||||||
use bevy_tasks::TaskPool;
|
use bevy_tasks::TaskPool;
|
||||||
use std::any::TypeId;
|
use std::{any::TypeId, fmt::Debug};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
/// Provides scoped access to a World according to a given [WorldQuery] and query filter
|
/// Provides scoped access to a World according to a given [WorldQuery] and query filter
|
||||||
@ -212,6 +212,38 @@ where
|
|||||||
Err(QueryComponentError::MissingWriteAccess)
|
Err(QueryComponentError::MissingWriteAccess)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn single(&self) -> Result<<Q::Fetch as Fetch<'_>>::Item, QuerySingleError>
|
||||||
|
where
|
||||||
|
Q::Fetch: ReadOnlyFetch,
|
||||||
|
{
|
||||||
|
let mut query = self.iter();
|
||||||
|
let first = query.next();
|
||||||
|
let extra = query.next().is_some();
|
||||||
|
|
||||||
|
match (first, extra) {
|
||||||
|
(Some(r), false) => Ok(r),
|
||||||
|
(None, _) => Err(QuerySingleError::NoEntities(std::any::type_name::<Self>())),
|
||||||
|
(Some(_), _) => Err(QuerySingleError::MultipleEntities(std::any::type_name::<
|
||||||
|
Self,
|
||||||
|
>())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See [`Query::single`]
|
||||||
|
pub fn single_mut(&mut self) -> Result<<Q::Fetch as Fetch<'_>>::Item, QuerySingleError> {
|
||||||
|
let mut query = self.iter_mut();
|
||||||
|
let first = query.next();
|
||||||
|
let extra = query.next().is_some();
|
||||||
|
|
||||||
|
match (first, extra) {
|
||||||
|
(Some(r), false) => Ok(r),
|
||||||
|
(None, _) => Err(QuerySingleError::NoEntities(std::any::type_name::<Self>())),
|
||||||
|
(Some(_), _) => Err(QuerySingleError::MultipleEntities(std::any::type_name::<
|
||||||
|
Self,
|
||||||
|
>())),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An error that occurs when retrieving a specific [Entity]'s component from a [Query]
|
/// An error that occurs when retrieving a specific [Entity]'s component from a [Query]
|
||||||
@ -226,3 +258,11 @@ pub enum QueryComponentError {
|
|||||||
#[error("The requested entity does not exist.")]
|
#[error("The requested entity does not exist.")]
|
||||||
NoSuchEntity,
|
NoSuchEntity,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum QuerySingleError {
|
||||||
|
#[error("No entities fit the query {0}")]
|
||||||
|
NoEntities(&'static str),
|
||||||
|
#[error("Multiple entities fit the query {0}!")]
|
||||||
|
MultipleEntities(&'static str),
|
||||||
|
}
|
||||||
|
|||||||
@ -357,10 +357,9 @@ 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 query: Query<&mut Text>) {
|
||||||
for mut text in query.iter_mut() {
|
let mut text = query.single_mut().unwrap();
|
||||||
text.sections[0].value = format!("Sugar Rush: {}", game.score);
|
text.sections[0].value = format!("Sugar Rush: {}", game.score);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// restart the game when pressing spacebar
|
// restart the game when pressing spacebar
|
||||||
fn gameover_keyboard(mut state: ResMut<State<GameState>>, keyboard_input: Res<Input<KeyCode>>) {
|
fn gameover_keyboard(mut state: ResMut<State<GameState>>, keyboard_input: Res<Input<KeyCode>>) {
|
||||||
|
|||||||
@ -174,7 +174,7 @@ fn paddle_movement_system(
|
|||||||
keyboard_input: Res<Input<KeyCode>>,
|
keyboard_input: Res<Input<KeyCode>>,
|
||||||
mut query: Query<(&Paddle, &mut Transform)>,
|
mut query: Query<(&Paddle, &mut Transform)>,
|
||||||
) {
|
) {
|
||||||
for (paddle, mut transform) in query.iter_mut() {
|
if let Ok((paddle, mut transform)) = query.single_mut() {
|
||||||
let mut direction = 0.0;
|
let mut direction = 0.0;
|
||||||
if keyboard_input.pressed(KeyCode::Left) {
|
if keyboard_input.pressed(KeyCode::Left) {
|
||||||
direction -= 1.0;
|
direction -= 1.0;
|
||||||
@ -196,15 +196,14 @@ fn ball_movement_system(time: Res<Time>, mut ball_query: Query<(&Ball, &mut Tran
|
|||||||
// clamp the timestep to stop the ball from escaping when the game starts
|
// clamp the timestep to stop the ball from escaping when the game starts
|
||||||
let delta_seconds = f32::min(0.2, time.delta_seconds());
|
let delta_seconds = f32::min(0.2, time.delta_seconds());
|
||||||
|
|
||||||
for (ball, mut transform) in ball_query.iter_mut() {
|
if let Ok((ball, mut transform)) = ball_query.single_mut() {
|
||||||
transform.translation += ball.velocity * delta_seconds;
|
transform.translation += ball.velocity * delta_seconds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scoreboard_system(scoreboard: Res<Scoreboard>, mut query: Query<&mut Text>) {
|
fn scoreboard_system(scoreboard: Res<Scoreboard>, mut query: Query<&mut Text>) {
|
||||||
for mut text in query.iter_mut() {
|
let mut text = query.single_mut().unwrap();
|
||||||
text.sections[1].value = scoreboard.score.to_string();
|
text.sections[0].value = format!("Score: {}", scoreboard.score);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ball_collision_system(
|
fn ball_collision_system(
|
||||||
@ -213,7 +212,7 @@ fn ball_collision_system(
|
|||||||
mut ball_query: Query<(&mut Ball, &Transform, &Sprite)>,
|
mut ball_query: Query<(&mut Ball, &Transform, &Sprite)>,
|
||||||
collider_query: Query<(Entity, &Collider, &Transform, &Sprite)>,
|
collider_query: Query<(Entity, &Collider, &Transform, &Sprite)>,
|
||||||
) {
|
) {
|
||||||
for (mut ball, ball_transform, sprite) in ball_query.iter_mut() {
|
if let Ok((mut ball, ball_transform, sprite)) = ball_query.single_mut() {
|
||||||
let ball_size = sprite.size;
|
let ball_size = sprite.size;
|
||||||
let velocity = &mut ball.velocity;
|
let velocity = &mut ball.velocity;
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user