mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
add Flags<T>
as a query to get flags of component (#1172)
add `Flags` as a query to get flags of component
This commit is contained in:
parent
bbae58a1f3
commit
d91117d6e7
6 changed files with 174 additions and 4 deletions
|
@ -198,6 +198,10 @@ path = "examples/diagnostics/custom_diagnostic.rs"
|
|||
name = "log_diagnostics"
|
||||
path = "examples/diagnostics/log_diagnostics.rs"
|
||||
|
||||
[[example]]
|
||||
name = "change_detection"
|
||||
path = "examples/ecs/change_detection.rs"
|
||||
|
||||
[[example]]
|
||||
name = "event"
|
||||
path = "examples/ecs/event.rs"
|
||||
|
|
|
@ -51,7 +51,7 @@ pub use entities::{Entity, EntityReserver, Location, NoSuchEntity};
|
|||
pub use entity_builder::{BuiltEntity, EntityBuilder};
|
||||
pub use entity_map::*;
|
||||
pub use filter::{Added, Changed, EntityFilter, Mutated, Or, QueryFilter, With, Without};
|
||||
pub use query::{Batch, BatchedIter, Mut, QueryIter, ReadOnlyFetch, WorldQuery};
|
||||
pub use query::{Batch, BatchedIter, Flags, Mut, QueryIter, ReadOnlyFetch, WorldQuery};
|
||||
pub use world::{ArchetypesGeneration, Component, ComponentError, SpawnBatchIter, World};
|
||||
pub use world_builder::*;
|
||||
|
||||
|
|
|
@ -130,6 +130,41 @@ impl<T: WorldQuery> WorldQuery for Option<T> {
|
|||
type Fetch = TryFetch<T::Fetch>;
|
||||
}
|
||||
|
||||
/// Flags on component `T` that happened since the start of the frame.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Flags<T: Component> {
|
||||
_marker: std::marker::PhantomData<T>,
|
||||
with: bool,
|
||||
added: bool,
|
||||
mutated: bool,
|
||||
}
|
||||
|
||||
impl<T: Component> Flags<T> {
|
||||
/// Does the entity have this component
|
||||
pub fn with(&self) -> bool {
|
||||
self.with
|
||||
}
|
||||
|
||||
/// Has this component been added since the start of the frame.
|
||||
pub fn added(&self) -> bool {
|
||||
self.added
|
||||
}
|
||||
|
||||
/// Has this component been mutated since the start of the frame.
|
||||
pub fn mutated(&self) -> bool {
|
||||
self.mutated
|
||||
}
|
||||
|
||||
/// Has this component been either mutated or added since the start of the frame.
|
||||
pub fn changed(&self) -> bool {
|
||||
self.added || self.mutated
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Component> WorldQuery for Flags<T> {
|
||||
type Fetch = FlagsFetch<T>;
|
||||
}
|
||||
|
||||
/// Unique borrow of an entity's component
|
||||
pub struct Mut<'a, T: Component> {
|
||||
pub(crate) value: &'a mut T,
|
||||
|
@ -237,6 +272,51 @@ impl<'a, T: Fetch<'a>> Fetch<'a> for TryFetch<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct FlagsFetch<T>(Option<NonNull<ComponentFlags>>, PhantomData<T>);
|
||||
unsafe impl<T> ReadOnlyFetch for FlagsFetch<T> {}
|
||||
|
||||
impl<'a, T: Component> Fetch<'a> for FlagsFetch<T> {
|
||||
type Item = Flags<T>;
|
||||
|
||||
const DANGLING: Self = Self(None, PhantomData::<T>);
|
||||
|
||||
#[inline]
|
||||
fn access() -> QueryAccess {
|
||||
QueryAccess::read::<T>()
|
||||
}
|
||||
|
||||
unsafe fn get(archetype: &'a Archetype, offset: usize) -> Option<Self> {
|
||||
Some(Self(
|
||||
archetype
|
||||
.get_type_state(std::any::TypeId::of::<T>())
|
||||
.map(|type_state| {
|
||||
NonNull::new_unchecked(type_state.component_flags().as_ptr().add(offset))
|
||||
}),
|
||||
PhantomData::<T>,
|
||||
))
|
||||
}
|
||||
|
||||
unsafe fn fetch(&self, n: usize) -> Self::Item {
|
||||
if let Some(flags) = self.0.as_ref() {
|
||||
let flags = *flags.as_ptr().add(n);
|
||||
Self::Item {
|
||||
_marker: PhantomData::<T>,
|
||||
with: true,
|
||||
added: flags.contains(ComponentFlags::ADDED),
|
||||
mutated: flags.contains(ComponentFlags::MUTATED),
|
||||
}
|
||||
} else {
|
||||
Self::Item {
|
||||
_marker: PhantomData::<T>,
|
||||
with: false,
|
||||
added: false,
|
||||
mutated: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ChunkInfo<Q: WorldQuery, F: QueryFilter> {
|
||||
fetch: Q::Fetch,
|
||||
filter: F::EntityFilter,
|
||||
|
@ -466,7 +546,7 @@ smaller_tuples_too!(tuple_impl, O, N, M, L, K, J, I, H, G, F, E, D, C, B, A);
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::core::{Added, Changed, Component, Entity, Mutated, Or, QueryFilter, World};
|
||||
use crate::core::{Added, Changed, Component, Entity, Flags, Mutated, Or, QueryFilter, World};
|
||||
use std::{vec, vec::Vec};
|
||||
|
||||
use super::Mut;
|
||||
|
@ -640,6 +720,38 @@ mod tests {
|
|||
assert_eq!(get_changed(&world), vec![e1]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flags_query() {
|
||||
let mut world = World::default();
|
||||
let e1 = world.spawn((A(0), B(0)));
|
||||
world.spawn((B(0),));
|
||||
|
||||
fn get_flags(world: &World) -> Vec<Flags<A>> {
|
||||
world.query::<Flags<A>>().collect::<Vec<Flags<A>>>()
|
||||
}
|
||||
let flags = get_flags(&world);
|
||||
assert!(flags[0].with());
|
||||
assert!(flags[0].added());
|
||||
assert!(!flags[0].mutated());
|
||||
assert!(flags[0].changed());
|
||||
assert!(!flags[1].with());
|
||||
assert!(!flags[1].added());
|
||||
assert!(!flags[1].mutated());
|
||||
assert!(!flags[1].changed());
|
||||
world.clear_trackers();
|
||||
let flags = get_flags(&world);
|
||||
assert!(flags[0].with());
|
||||
assert!(!flags[0].added());
|
||||
assert!(!flags[0].mutated());
|
||||
assert!(!flags[0].changed());
|
||||
*world.get_mut(e1).unwrap() = A(1);
|
||||
let flags = get_flags(&world);
|
||||
assert!(flags[0].with());
|
||||
assert!(!flags[0].added());
|
||||
assert!(flags[0].mutated());
|
||||
assert!(flags[0].changed());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exact_size_query() {
|
||||
let mut world = World::default();
|
||||
|
|
|
@ -16,7 +16,7 @@ pub mod prelude {
|
|||
resource::{ChangedRes, FromResources, Local, Res, ResMut, Resource, Resources},
|
||||
schedule::{Schedule, State, StateStage, SystemStage},
|
||||
system::{Commands, IntoSystem, Query, System},
|
||||
Added, Bundle, Changed, Component, Entity, In, IntoChainSystem, Mut, Mutated, Or, QuerySet,
|
||||
Ref, RefMut, With, Without, World,
|
||||
Added, Bundle, Changed, Component, Entity, Flags, In, IntoChainSystem, Mut, Mutated, Or,
|
||||
QuerySet, Ref, RefMut, With, Without, World,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -114,6 +114,7 @@ Example | File | Description
|
|||
|
||||
Example | File | Description
|
||||
--- | --- | ---
|
||||
`change_detection` | [`ecs/change_detection.rs`](./ecs/change_detection.rs) | Change detection on components
|
||||
`ecs_guide` | [`ecs/ecs_guide.rs`](./ecs/ecs_guide.rs) | Full guide to Bevy's ECS
|
||||
`event` | [`ecs/event.rs`](./ecs/event.rs) | Illustrates event creation, activation, and reception
|
||||
`hierarchy` | [`ecs/hierarchy.rs`](./ecs/hierarchy.rs) | Creates a hierarchy of parents and children entities
|
||||
|
|
53
examples/ecs/change_detection.rs
Normal file
53
examples/ecs/change_detection.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
use bevy::prelude::*;
|
||||
use rand::Rng;
|
||||
|
||||
// This example illustrates how to react to component change
|
||||
fn main() {
|
||||
App::build()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_startup_system(setup.system())
|
||||
.add_system(change_component.system())
|
||||
.add_system(change_detection.system())
|
||||
.add_system(flags_monitoring.system())
|
||||
.run();
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct MyComponent(f64);
|
||||
|
||||
fn setup(commands: &mut Commands) {
|
||||
commands.spawn((MyComponent(0.),));
|
||||
commands.spawn((Transform::default(),));
|
||||
}
|
||||
|
||||
fn change_component(time: Res<Time>, mut query: Query<(Entity, &mut MyComponent)>) {
|
||||
for (entity, mut component) in query.iter_mut() {
|
||||
if rand::thread_rng().gen_bool(0.1) {
|
||||
info!("changing component {:?}", entity);
|
||||
component.0 = time.seconds_since_startup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// There are query filters for `Changed<T>`, `Added<T>` and `Mutated<T>`
|
||||
// Only entities matching the filters will be in the query
|
||||
fn change_detection(query: Query<(Entity, &MyComponent), Changed<MyComponent>>) {
|
||||
for (entity, component) in query.iter() {
|
||||
info!("{:?} changed: {:?}", entity, component,);
|
||||
}
|
||||
}
|
||||
|
||||
// By looking at flags, the query is not filtered but the information is available
|
||||
fn flags_monitoring(query: Query<(Entity, Option<&MyComponent>, Flags<MyComponent>)>) {
|
||||
for (entity, component, flags) in query.iter() {
|
||||
info!(
|
||||
"{:?}: {:?} -> with: {:?} - added: {:?} - mutated: {:?} - changed: {:?}",
|
||||
entity,
|
||||
component,
|
||||
flags.with(),
|
||||
flags.added(),
|
||||
flags.mutated(),
|
||||
flags.changed()
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue