-
-
Notifications
You must be signed in to change notification settings - Fork 4k
Add Disabled marker #12928
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Disabled marker #12928
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -21,6 +21,52 @@ pub use par_iter::*; | |||||
pub use state::*; | ||||||
pub use world_query::*; | ||||||
|
||||||
use crate as bevy_ecs; | ||||||
|
||||||
/// A special marker component to disable an entity. | ||||||
/// | ||||||
/// Disabled entities do not show up in most queries, unless the query mentions Disabled. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
/// | ||||||
/// ## Example | ||||||
/// | ||||||
/// ```rust | ||||||
/// # use bevy_ecs::prelude::*; | ||||||
/// # let mut world = World::new(); | ||||||
/// # | ||||||
/// // This entity is enabled, since all entities are enabled by default | ||||||
/// let entity_a = world.spawn_empty().id(); | ||||||
/// | ||||||
/// // We disable this entity using a helper method | ||||||
/// let entity_b = world.spawn_empty().id(); | ||||||
/// world.disable(entity_b); | ||||||
/// | ||||||
/// // It can also be inserted like other component | ||||||
/// let entity_c = world.spawn(Disabled).id(); | ||||||
/// | ||||||
/// // This query does not mention Disabled, so disabled entities are hidden | ||||||
/// let mut query = world.query::<Entity>(); | ||||||
/// assert_eq!(1, query.iter(&world).count()); | ||||||
/// assert_eq!(Ok(entity_a), query.get_single(&world)); | ||||||
/// | ||||||
/// // If our query mentions Disabled, we can find disabled entities like normal | ||||||
/// // Here we query for only the disabled entities | ||||||
/// let mut query = world.query_filtered::<(), With<Disabled>>(); | ||||||
/// assert!(query.get(&world, entity_a).is_err()); | ||||||
/// assert!(query.get_many(&world, [entity_b, entity_c]).is_ok()); | ||||||
/// | ||||||
/// // It also works as part of the query data | ||||||
/// let mut query = world.query::<Has<Disabled>>(); | ||||||
/// assert_eq!(Ok([false, true, true]), query.get_many(&world, [entity_a, entity_b, entity_c])); | ||||||
/// | ||||||
/// // If we exclude Disabled, it functions the same as the default behavior | ||||||
/// let mut query = world.query_filtered::<Entity, Without<Disabled>>(); | ||||||
/// assert_eq!(1, query.iter(&world).count()); | ||||||
/// assert_eq!(Ok(entity_a), query.get_single(&world)); | ||||||
/// ``` | ||||||
#[derive(bevy_ecs_macros::Component, Clone, Copy)] | ||||||
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))] | ||||||
pub struct Disabled; | ||||||
Comment on lines
+67
to
+68
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should reflect There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes to both. |
||||||
|
||||||
/// A debug checked version of [`Option::unwrap_unchecked`]. Will panic in | ||||||
/// debug modes if unwrapping a `None` or `Err` value in debug mode, but is | ||||||
/// equivalent to `Option::unwrap_unchecked` or `Result::unwrap_unchecked` | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ use crate::{ | |
change_detection::MutUntyped, | ||
component::{Component, ComponentId, ComponentTicks, Components, StorageType}, | ||
entity::{Entities, Entity, EntityLocation}, | ||
query::{Access, DebugCheckedUnwrap}, | ||
query::{Access, DebugCheckedUnwrap, Disabled}, | ||
removal_detection::RemovedComponentEvents, | ||
storage::Storages, | ||
world::{Mut, World}, | ||
|
@@ -1136,6 +1136,8 @@ impl<'w> EntityWorldMut<'w> { | |
/// | ||
/// See [`EntityCommands::retain`](crate::system::EntityCommands::retain) for more details. | ||
pub fn retain<T: Bundle>(&mut self) -> &mut Self { | ||
let disabled_id = self.world.init_component::<Disabled>(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This behavior needs to be documented. It's a nice bit of design though! |
||
|
||
let archetypes = &mut self.world.archetypes; | ||
let storages = &mut self.world.storages; | ||
let components = &mut self.world.components; | ||
|
@@ -1148,7 +1150,7 @@ impl<'w> EntityWorldMut<'w> { | |
|
||
let to_remove = &old_archetype | ||
.components() | ||
.filter(|c| !retained_bundle_info.components().contains(c)) | ||
.filter(|c| !retained_bundle_info.components().contains(c) && *c != disabled_id) | ||
.collect::<Vec<_>>(); | ||
let remove_bundle = self.world.bundles.init_dynamic_info(components, to_remove); | ||
|
||
|
@@ -1269,6 +1271,16 @@ impl<'w> EntityWorldMut<'w> { | |
self.entity | ||
} | ||
|
||
/// Enables the current entity, see [`Disabled`] for more information. | ||
pub fn enable(&mut self) { | ||
self.remove::<Disabled>(); | ||
} | ||
|
||
/// Disables the current entity, see [`Disabled`] for more information. | ||
pub fn disable(&mut self) { | ||
self.insert(Disabled); | ||
} | ||
|
||
/// Gets read-only access to the world that the current entity belongs to. | ||
#[inline] | ||
pub fn world(&self) -> &World { | ||
|
@@ -2583,6 +2595,25 @@ mod tests { | |
assert_eq!(world.entity(ent).archetype().components().next(), None); | ||
} | ||
|
||
// Test that calling retain retains `Disabled`. | ||
#[test] | ||
fn retain_disabled() { | ||
#[derive(Component)] | ||
struct Marker<const N: usize>; | ||
|
||
let mut world = World::new(); | ||
let ent = world | ||
.spawn((Marker::<1>, Marker::<2>, Marker::<3>, Disabled)) | ||
.id(); | ||
|
||
let disabled_id = world.init_component::<Disabled>(); | ||
world.entity_mut(ent).retain::<Marker<1>>(); | ||
assert!(world.entity(ent).contains_id(disabled_id)); | ||
|
||
world.entity_mut(ent).retain::<()>(); | ||
assert!(world.entity(ent).contains_id(disabled_id)); | ||
} | ||
|
||
// Test removing some components with `retain`, including components not on the entity. | ||
#[test] | ||
fn retain_some_components() { | ||
|
Uh oh!
There was an error while loading. Please reload this page.