From 311f04f858adc4ef02a123e6d148451f1e3a68a3 Mon Sep 17 00:00:00 2001 From: Moxinilian Date: Tue, 28 Jul 2020 00:10:32 +0200 Subject: [PATCH 1/2] transform: implement hierarchical entity despawn --- crates/bevy_ecs/src/system/commands.rs | 1 + .../bevy_transform/src/hierarchy/hierarchy.rs | 99 ++++++++++++++++--- 2 files changed, 89 insertions(+), 11 deletions(-) diff --git a/crates/bevy_ecs/src/system/commands.rs b/crates/bevy_ecs/src/system/commands.rs index 6febfa5163..66e099c9ac 100644 --- a/crates/bevy_ecs/src/system/commands.rs +++ b/crates/bevy_ecs/src/system/commands.rs @@ -224,6 +224,7 @@ impl Commands { self.write_world(SpawnBatch { components_iter }) } + /// Despawns only the specified entity, ignoring any other consideration. pub fn despawn(&mut self, entity: Entity) -> &mut Self { self.write_world(Despawn { entity }) } diff --git a/crates/bevy_transform/src/hierarchy/hierarchy.rs b/crates/bevy_transform/src/hierarchy/hierarchy.rs index 5670f6b9ed..42a675aab8 100644 --- a/crates/bevy_transform/src/hierarchy/hierarchy.rs +++ b/crates/bevy_transform/src/hierarchy/hierarchy.rs @@ -1,5 +1,5 @@ use crate::components::Children; -use bevy_ecs::{Entity, Query}; +use bevy_ecs::{Commands, Entity, Query, World, WorldWriter}; pub fn run_on_hierarchy( children_query: &Query<&Children>, @@ -14,16 +14,13 @@ where { // TODO: not a huge fan of this pattern. are there ways to do recursive updates in legion without allocations? // TODO: the problem above might be resolvable with world splitting - let children = match children_query.get::(entity) { - Ok(children) => Some( - children - .0 - .iter() - .map(|entity| *entity) - .collect::>(), - ), - Err(_) => None, - }; + let children = children_query.get::(entity).ok().map(|children| { + children + .0 + .iter() + .map(|entity| *entity) + .collect::>() + }); let parent_result = run(state, entity, parent_result, previous_result); previous_result = None; @@ -44,3 +41,83 @@ where previous_result } + +pub struct DespawnRecursive { + entity: Entity, +} + +fn despawn_with_children_recursive(world: &mut World, entity: Entity) { + if let Some(children) = world.get::(entity).ok().map(|children| { + children + .0 + .iter() + .map(|entity| *entity) + .collect::>() + }) { + for e in children { + despawn_with_children_recursive(world, e); + } + } + + world.despawn(entity).unwrap(); +} + +impl WorldWriter for DespawnRecursive { + fn write(self: Box, world: &mut World) { + despawn_with_children_recursive(world, self.entity); + } +} + +pub trait DespawnRecursiveExt { + /// Despawns the provided entity and its children. + fn despawn_recursive(&mut self, entity: Entity) -> &mut Self; +} + +impl DespawnRecursiveExt for Commands { + /// Despawns the provided entity and its children. + fn despawn_recursive(&mut self, entity: Entity) -> &mut Self { + self.write_world(DespawnRecursive { entity }) + } +} + +#[cfg(test)] +mod tests { + use super::DespawnRecursiveExt; + use crate::hierarchy::BuildChildren; + use bevy_ecs::{Commands, Entity, Resources, World}; + + #[test] + fn despawn_recursive() { + let mut world = World::default(); + let mut resources = Resources::default(); + let mut command_buffer = Commands::default(); + let parent_entity = Entity::new(); + + command_buffer.spawn((0u32, 0u64)).with_children(|parent| { + parent.spawn((0u32, 0u64)); + }); + + command_buffer + .spawn_as_entity(parent_entity, (1u32, 2u64)) + .with_children(|parent| { + parent.spawn((1u32, 2u64)); + parent.spawn((1u32, 2u64)); + }); + + command_buffer.spawn((0u32, 0u64)); + command_buffer.apply(&mut world, &mut resources); + + command_buffer.despawn_recursive(parent_entity); + command_buffer.apply(&mut world, &mut resources); + + let results = world + .query::<(&u32, &u64)>() + .iter() + .map(|(a, b)| (*a, *b)) + .collect::>(); + + // parent_entity and its children should be deleted, + // the (0, 0) tuples remaining. + assert_eq!(results, vec![(0u32, 0u64), (0u32, 0u64), (0u32, 0u64)]); + } +} From 3007201eac14eb1f22b1fc9f4f133a2fb73f8ce9 Mon Sep 17 00:00:00 2001 From: Moxinilian Date: Tue, 28 Jul 2020 00:23:59 +0200 Subject: [PATCH 2/2] transform: improve despawn_recursive tests --- crates/bevy_transform/src/hierarchy/hierarchy.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/bevy_transform/src/hierarchy/hierarchy.rs b/crates/bevy_transform/src/hierarchy/hierarchy.rs index 42a675aab8..34040e53ec 100644 --- a/crates/bevy_transform/src/hierarchy/hierarchy.rs +++ b/crates/bevy_transform/src/hierarchy/hierarchy.rs @@ -100,7 +100,9 @@ mod tests { command_buffer .spawn_as_entity(parent_entity, (1u32, 2u64)) .with_children(|parent| { - parent.spawn((1u32, 2u64)); + parent.spawn((1u32, 2u64)).with_children(|parent| { + parent.spawn((1u32, 2u64)); + }); parent.spawn((1u32, 2u64)); }); @@ -115,7 +117,7 @@ mod tests { .iter() .map(|(a, b)| (*a, *b)) .collect::>(); - + // parent_entity and its children should be deleted, // the (0, 0) tuples remaining. assert_eq!(results, vec![(0u32, 0u64), (0u32, 0u64), (0u32, 0u64)]);