diff --git a/crates/bevy_ecs/src/system/commands.rs b/crates/bevy_ecs/src/system/commands.rs index c8f5a5731da03c..9e2d0c31ca0fa0 100644 --- a/crates/bevy_ecs/src/system/commands.rs +++ b/crates/bevy_ecs/src/system/commands.rs @@ -26,20 +26,16 @@ impl CommandQueue { } #[inline] - pub fn push_boxed(&mut self, command: Box) { + pub fn push(&mut self, command: Box) { self.commands.push(command); } - - #[inline] - pub fn push(&mut self, command: T) { - self.push_boxed(Box::new(command)); - } } /// A list of commands that will be run to modify a `World` pub struct Commands<'a> { queue: &'a mut CommandQueue, entities: &'a Entities, + current_entity: Option, } impl<'a> Commands<'a> { @@ -47,45 +43,18 @@ impl<'a> Commands<'a> { Self { queue, entities: world.entities(), - } - } - - /// Creates a new empty entity and returns an [EntityCommands] builder for it. - /// - /// # Example - /// - /// ``` - /// use bevy_ecs::prelude::*; - /// - /// fn example_system(mut commands: Commands) { - /// // Create a new empty entity and retrieve its id. - /// let empty_entity = commands.spawn().id(); - /// - /// // Create another empty entity, then add some component to it - /// commands.spawn() - /// // adds a new component bundle to the entity - /// .insert_bundle((1usize, 2u32)) - /// // adds a single component to the entity - /// .insert("hello world"); - /// } - /// # example_system.system(); - /// ``` - pub fn spawn(&mut self) -> EntityCommands<'a, '_> { - let entity = self.entities.reserve_entity(); - EntityCommands { - entity, - commands: self, + current_entity: None, } } /// Creates a new entity with the components contained in `bundle`. /// - /// This returns an [EntityCommands] builder, which enables inserting more components and bundles - /// using a "builder pattern". - /// /// Note that `bundle` is a [Bundle], which is a collection of components. [Bundle] is /// automatically implemented for tuples of components. You can also create your own bundle - /// types by deriving [`derive@Bundle`]. + /// types by deriving [`derive@Bundle`]. If you would like to spawn an entity with a single + /// component, consider wrapping the component in a tuple (which [Bundle] is implemented for). + /// + /// See [`Self::set_current_entity`], [`Self::insert`]. /// /// # Example /// @@ -103,118 +72,113 @@ impl<'a> Commands<'a> { /// /// fn example_system(mut commands: Commands) { /// // Create a new entity with a component bundle. - /// commands.spawn_bundle(ExampleBundle { + /// commands.spawn(ExampleBundle { /// a: Component1, /// b: Component2, /// }); /// - /// commands - /// // Create a new entity with two components using a "tuple bundle". - /// .spawn_bundle((Component1, Component2)) - /// // spawn_bundle returns a builder, so you can insert more bundles like this: - /// .insert_bundle((1usize, 2u32)) - /// // or insert single components like this: - /// .insert("hello world"); + /// // Create a new entity with a single component. + /// commands.spawn((Component1,)); + /// // Create a new entity with two components. + /// commands.spawn((Component1, Component2)); /// } /// # example_system.system(); /// ``` - pub fn spawn_bundle<'b, T: Bundle>(&'b mut self, bundle: T) -> EntityCommands<'a, 'b> { - let mut e = self.spawn(); - e.insert_bundle(bundle); - e - } - - /// Returns an [EntityCommands] builder for the requested `entity`. - /// - /// # Example - /// - /// ``` - /// use bevy_ecs::prelude::*; - /// - /// fn example_system(mut commands: Commands) { - /// // Create a new, empty entity - /// let entity = commands.spawn().id(); - /// - /// commands.entity(entity) - /// // adds a new component bundle to the entity - /// .insert_bundle((1usize, 2u32)) - /// // adds a single component to the entity - /// .insert("hello world"); - /// } - /// # example_system.system(); - /// ``` - pub fn entity(&mut self, entity: Entity) -> EntityCommands<'a, '_> { - EntityCommands { - entity, - commands: self, - } + pub fn spawn(&mut self, bundle: impl Bundle) -> &mut Self { + let entity = self.entities.reserve_entity(); + self.set_current_entity(entity); + self.insert_bundle(entity, bundle); + self } /// Equivalent to iterating `bundles_iter` and calling [`Self::spawn`] on each bundle, but /// slightly more performant. - pub fn spawn_batch(&mut self, bundles_iter: I) + pub fn spawn_batch(&mut self, bundles_iter: I) -> &mut Self where I: IntoIterator + Send + Sync + 'static, I::Item: Bundle, { - self.queue.push(SpawnBatch { bundles_iter }); + self.add_command(SpawnBatch { bundles_iter }) } - /// See [World::insert_resource]. - pub fn insert_resource(&mut self, resource: T) { - self.queue.push(InsertResource { resource }) + /// Despawns only the specified entity, not including its children. + pub fn despawn(&mut self, entity: Entity) -> &mut Self { + self.add_command(Despawn { entity }) + } + + /// Inserts a bundle of components into `entity`. + /// + /// See [crate::world::EntityMut::insert_bundle]. + pub fn insert_bundle(&mut self, entity: Entity, bundle: impl Bundle) -> &mut Self { + self.add_command(InsertBundle { entity, bundle }) } - pub fn remove_resource(&mut self) { - self.queue.push(RemoveResource:: { + /// Inserts a single component into `entity`. + /// + /// See [crate::world::EntityMut::insert]. + pub fn insert(&mut self, entity: Entity, component: impl Component) -> &mut Self { + self.add_command(Insert { entity, component }) + } + + /// See [crate::world::EntityMut::remove]. + pub fn remove(&mut self, entity: Entity) -> &mut Self + where + T: Component, + { + self.add_command(Remove:: { + entity, phantom: PhantomData, - }); + }) } - /// Adds a command directly to the command list. Prefer this to [`Self::add_command_boxed`] if - /// the type of `command` is statically known. - pub fn add(&mut self, command: C) { - self.queue.push(command); + /// See [World::insert_resource]. + pub fn insert_resource(&mut self, resource: T) -> &mut Self { + self.add_command(InsertResource { resource }) } -} -pub struct EntityCommands<'a, 'b> { - entity: Entity, - commands: &'b mut Commands<'a>, -} + /// See [crate::world::EntityMut::remove_bundle]. + pub fn remove_bundle(&mut self, entity: Entity) -> &mut Self + where + T: Bundle, + { + self.add_command(RemoveBundle:: { + entity, + phantom: PhantomData, + }) + } -impl<'a, 'b> EntityCommands<'a, 'b> { - /// Retrieves the current entity's unique [Entity] id. - #[inline] - pub fn id(&self) -> Entity { - self.entity + pub fn remove_resource(&mut self) -> &mut Self { + self.add_command(RemoveResource:: { + phantom: PhantomData, + }) } /// Adds a bundle of components to the current entity. /// /// See [`Self::with`], [`Self::current_entity`]. - pub fn insert_bundle(&mut self, bundle: impl Bundle) -> &mut Self { - self.commands.add(InsertBundle { - entity: self.entity, + pub fn with_bundle(&mut self, bundle: impl Bundle) -> &mut Self { + let current_entity = self.current_entity.expect("Cannot add bundle because the 'current entity' is not set. You should spawn an entity first."); + self.queue.push(Box::new(InsertBundle { + entity: current_entity, bundle, - }); + })); self } /// Adds a single component to the current entity. /// - /// See [`Self::insert_bundle`], [`Self::id`]. + /// See [`Self::with_bundle`], [`Self::current_entity`]. /// /// # Warning /// /// It's possible to call this with a bundle, but this is likely not intended and - /// [`Self::insert_bundle`] should be used instead. If `with` is called with a bundle, the bundle + /// [`Self::with_bundle`] should be used instead. If `with` is called with a bundle, the bundle /// itself will be added as a component instead of the bundles' inner components each being /// added. /// /// # Example /// - /// [`Self::insert`] can be chained with [`Self::spawn`]. + /// `with` can be chained with [`Self::spawn`]. /// /// ``` /// use bevy_ecs::prelude::*; @@ -223,58 +187,65 @@ impl<'a, 'b> EntityCommands<'a, 'b> { /// struct Component2; /// /// fn example_system(mut commands: Commands) { - /// // Create a new entity with `Component1` and `Component2` - /// commands.spawn() - /// .insert(Component1) - /// .insert(Component2); + /// // Create a new entity with a `Component1` and `Component2`. + /// commands.spawn((Component1,)).with(Component2); /// - /// // Psst! These are also equivalent to the expression above! - /// commands.spawn().insert_bundle((Component1, Component2)); - /// commands.spawn_bundle((Component1, Component2)); + /// // Psst! These are also equivalent to the line above! + /// commands.spawn((Component1, Component2)); + /// commands.spawn(()).with(Component1).with(Component2); + /// #[derive(Bundle)] + /// struct ExampleBundle { + /// a: Component1, + /// b: Component2, + /// } + /// commands.spawn(()).with_bundle(ExampleBundle { + /// a: Component1, + /// b: Component2, + /// }); /// } /// # example_system.system(); /// ``` - pub fn insert(&mut self, component: impl Component) -> &mut Self { - self.commands.add(Insert { - entity: self.entity, + pub fn with(&mut self, component: impl Component) -> &mut Self { + let current_entity = self.current_entity.expect("Cannot add component because the 'current entity' is not set. You should spawn an entity first."); + self.queue.push(Box::new(Insert { + entity: current_entity, component, - }); + })); self } - /// See [crate::world::EntityMut::remove_bundle]. - pub fn remove_bundle(&mut self) -> &mut Self - where - T: Bundle, - { - self.commands.add(RemoveBundle:: { - entity: self.entity, - phantom: PhantomData, - }); + /// Adds a command directly to the command list. Prefer this to [`Self::add_command_boxed`] if + /// the type of `command` is statically known. + pub fn add_command(&mut self, command: C) -> &mut Self { + self.queue.push(Box::new(command)); self } - /// See [crate::world::EntityMut::remove]. - pub fn remove(&mut self) -> &mut Self - where - T: Component, - { - self.commands.add(Remove:: { - entity: self.entity, - phantom: PhantomData, - }); + /// See [`Self::add_command`]. + pub fn add_command_boxed(&mut self, command: Box) -> &mut Self { + self.queue.push(command); self } - /// Despawns only the specified entity, not including its children. - pub fn despawn(&mut self) { - self.commands.add(Despawn { - entity: self.entity, - }) + /// Returns the current entity, set by [`Self::spawn`] or with [`Self::set_current_entity`]. + pub fn current_entity(&self) -> Option { + self.current_entity + } + + pub fn set_current_entity(&mut self, entity: Entity) { + self.current_entity = Some(entity); } - pub fn commands(&mut self) -> &mut Commands<'a> { - self.commands + pub fn clear_current_entity(&mut self) { + self.current_entity = None; + } + + pub fn for_current_entity(&mut self, f: impl FnOnce(Entity)) -> &mut Self { + let current_entity = self + .current_entity + .expect("The 'current entity' is not set. You should spawn an entity first."); + f(current_entity); + self } } @@ -421,8 +392,9 @@ mod tests { let mut world = World::default(); let mut command_queue = CommandQueue::default(); let entity = Commands::new(&mut command_queue, &world) - .spawn_bundle((1u32, 2u64)) - .id(); + .spawn((1u32, 2u64)) + .current_entity() + .unwrap(); command_queue.apply(&mut world); assert!(world.entities().len() == 1); let results = world @@ -432,11 +404,9 @@ mod tests { .collect::>(); assert_eq!(results, vec![(1u32, 2u64)]); // test entity despawn - { - let mut commands = Commands::new(&mut command_queue, &world); - commands.entity(entity).despawn(); - commands.entity(entity).despawn(); // double despawn shouldn't panic - } + Commands::new(&mut command_queue, &world) + .despawn(entity) + .despawn(entity); // double despawn shouldn't panic command_queue.apply(&mut world); let results2 = world .query::<(&u32, &u64)>() @@ -451,9 +421,9 @@ mod tests { let mut world = World::default(); let mut command_queue = CommandQueue::default(); let entity = Commands::new(&mut command_queue, &world) - .spawn() - .insert_bundle((1u32, 2u64)) - .id(); + .spawn((1u32, 2u64)) + .current_entity() + .unwrap(); command_queue.apply(&mut world); let results_before = world .query::<(&u32, &u64)>() @@ -464,9 +434,8 @@ mod tests { // test component removal Commands::new(&mut command_queue, &world) - .entity(entity) - .remove::() - .remove_bundle::<(u32, u64)>(); + .remove::(entity) + .remove_bundle::<(u32, u64)>(entity); command_queue.apply(&mut world); let results_after = world .query::<(&u32, &u64)>() diff --git a/crates/bevy_ecs/src/system/exclusive_system.rs b/crates/bevy_ecs/src/system/exclusive_system.rs index 607853294c5f7a..2196c2665ec084 100644 --- a/crates/bevy_ecs/src/system/exclusive_system.rs +++ b/crates/bevy_ecs/src/system/exclusive_system.rs @@ -131,7 +131,7 @@ mod tests { ) { for entity in query.iter() { *counter += 1; - commands.entity(entity).remove::(); + commands.remove::(entity); } } diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index 08b58c523b5e3c..7f7b6a71a08d76 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -296,18 +296,18 @@ fn load_node( ) -> Result<(), GltfError> { let transform = gltf_node.transform(); let mut gltf_error = None; - let mut node = world_builder.spawn_bundle(( + let node = world_builder.spawn(( Transform::from_matrix(Mat4::from_cols_array_2d(&transform.matrix())), GlobalTransform::identity(), )); if let Some(name) = gltf_node.name() { - node.insert(Name::new(name.to_string())); + node.with(Name::new(name.to_string())); } // create camera node if let Some(camera) = gltf_node.camera() { - node.insert(VisibleEntities { + node.with(VisibleEntities { ..Default::default() }); @@ -325,12 +325,12 @@ fn load_node( ..Default::default() }; - node.insert(Camera { + node.with(Camera { name: Some(base::camera::CAMERA_2D.to_owned()), projection_matrix: orthographic_projection.get_projection_matrix(), ..Default::default() }); - node.insert(orthographic_projection); + node.with(orthographic_projection); } gltf::camera::Projection::Perspective(perspective) => { let mut perspective_projection: PerspectiveProjection = PerspectiveProjection { @@ -344,12 +344,12 @@ fn load_node( if let Some(aspect_ratio) = perspective.aspect_ratio() { perspective_projection.aspect_ratio = aspect_ratio; } - node.insert(Camera { + node.with(Camera { name: Some(base::camera::CAMERA_3D.to_owned()), projection_matrix: perspective_projection.get_projection_matrix(), ..Default::default() }); - node.insert(perspective_projection); + node.with(perspective_projection); } } } @@ -374,7 +374,7 @@ fn load_node( let material_asset_path = AssetPath::new_ref(load_context.path(), Some(&material_label)); - parent.spawn_bundle(PbrBundle { + parent.spawn(PbrBundle { mesh: load_context.get_handle(mesh_asset_path), material: load_context.get_handle(material_asset_path), ..Default::default() diff --git a/crates/bevy_scene/src/command.rs b/crates/bevy_scene/src/command.rs index f7d04c60652c4e..e92dcfd5145bbf 100644 --- a/crates/bevy_scene/src/command.rs +++ b/crates/bevy_scene/src/command.rs @@ -20,12 +20,12 @@ impl Command for SpawnScene { } pub trait SpawnSceneCommands { - fn spawn_scene(&mut self, scene: Handle); + fn spawn_scene(&mut self, scene: Handle) -> &mut Self; } impl<'a> SpawnSceneCommands for Commands<'a> { - fn spawn_scene(&mut self, scene_handle: Handle) { - self.add(SpawnScene { scene_handle }); + fn spawn_scene(&mut self, scene_handle: Handle) -> &mut Self { + self.add_command(SpawnScene { scene_handle }) } } diff --git a/crates/bevy_transform/src/hierarchy/child_builder.rs b/crates/bevy_transform/src/hierarchy/child_builder.rs index 83f7bb61303236..eb9e7584428d07 100644 --- a/crates/bevy_transform/src/hierarchy/child_builder.rs +++ b/crates/bevy_transform/src/hierarchy/child_builder.rs @@ -1,8 +1,9 @@ use crate::prelude::{Children, Parent, PreviousParent}; use bevy_ecs::{ bundle::Bundle, + component::Component, entity::Entity, - system::{Command, Commands, EntityCommands}, + system::{Command, Commands}, world::{EntityMut, World}, }; use smallvec::SmallVec; @@ -46,7 +47,7 @@ pub struct PushChildren { } pub struct ChildBuilder<'a, 'b> { - commands: &'b mut Commands<'a>, + commands: &'a mut Commands<'b>, push_children: PushChildren, } @@ -80,65 +81,124 @@ impl Command for PushChildren { } impl<'a, 'b> ChildBuilder<'a, 'b> { - pub fn spawn_bundle(&mut self, bundle: impl Bundle) -> EntityCommands<'a, '_> { - let e = self.commands.spawn_bundle(bundle); - self.push_children.children.push(e.id()); - e + pub fn spawn(&mut self, bundle: impl Bundle) -> &mut Self { + self.commands.spawn(bundle); + self.push_children + .children + .push(self.commands.current_entity().unwrap()); + self } - pub fn spawn(&mut self) -> EntityCommands<'a, '_> { - let e = self.commands.spawn(); - self.push_children.children.push(e.id()); - e + pub fn current_entity(&self) -> Option { + self.commands.current_entity() } pub fn parent_entity(&self) -> Entity { self.push_children.parent } + pub fn with_bundle(&mut self, bundle: impl Bundle) -> &mut Self { + self.commands.with_bundle(bundle); + self + } + + pub fn with(&mut self, component: impl Component) -> &mut Self { + self.commands.with(component); + self + } + + pub fn for_current_entity(&mut self, func: impl FnOnce(Entity)) -> &mut Self { + let current_entity = self + .commands + .current_entity() + .expect("The 'current entity' is not set. You should spawn an entity first."); + func(current_entity); + self + } + pub fn add_command(&mut self, command: C) -> &mut Self { - self.commands.add(command); + self.commands.add_command(command); self } } pub trait BuildChildren { fn with_children(&mut self, f: impl FnOnce(&mut ChildBuilder)) -> &mut Self; - fn push_children(&mut self, children: &[Entity]) -> &mut Self; - fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self; + fn push_children(&mut self, parent: Entity, children: &[Entity]) -> &mut Self; + fn insert_children(&mut self, parent: Entity, index: usize, children: &[Entity]) -> &mut Self; +} + +impl<'a> BuildChildren for Commands<'a> { + fn with_children(&mut self, parent: impl FnOnce(&mut ChildBuilder)) -> &mut Self { + let current_entity = self.current_entity().expect("Cannot add children because the 'current entity' is not set. You should spawn an entity first."); + self.clear_current_entity(); + let push_children = { + let mut builder = ChildBuilder { + commands: self, + push_children: PushChildren { + children: SmallVec::default(), + parent: current_entity, + }, + }; + parent(&mut builder); + builder.push_children + }; + + self.set_current_entity(current_entity); + self.add_command(push_children); + self + } + + fn push_children(&mut self, parent: Entity, children: &[Entity]) -> &mut Self { + self.add_command(PushChildren { + children: SmallVec::from(children), + parent, + }); + self + } + + fn insert_children(&mut self, parent: Entity, index: usize, children: &[Entity]) -> &mut Self { + self.add_command(InsertChildren { + children: SmallVec::from(children), + index, + parent, + }); + self + } } -impl<'a, 'b> BuildChildren for EntityCommands<'a, 'b> { +impl<'a, 'b> BuildChildren for ChildBuilder<'a, 'b> { fn with_children(&mut self, spawn_children: impl FnOnce(&mut ChildBuilder)) -> &mut Self { - let parent = self.id(); + let current_entity = self.commands.current_entity().expect("Cannot add children because the 'current entity' is not set. You should spawn an entity first."); + self.commands.clear_current_entity(); let push_children = { let mut builder = ChildBuilder { - commands: self.commands(), + commands: self.commands, push_children: PushChildren { children: SmallVec::default(), - parent, + parent: current_entity, }, }; + spawn_children(&mut builder); builder.push_children }; - self.commands().add(push_children); + self.commands.set_current_entity(current_entity); + self.commands.add_command(push_children); self } - fn push_children(&mut self, children: &[Entity]) -> &mut Self { - let parent = self.id(); - self.commands().add(PushChildren { + fn push_children(&mut self, parent: Entity, children: &[Entity]) -> &mut Self { + self.commands.add_command(PushChildren { children: SmallVec::from(children), parent, }); self } - fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self { - let parent = self.id(); - self.commands().add(InsertChildren { + fn insert_children(&mut self, parent: Entity, index: usize, children: &[Entity]) -> &mut Self { + self.commands.add_command(InsertChildren { children: SmallVec::from(children), index, parent, @@ -155,8 +215,12 @@ pub struct WorldChildBuilder<'w> { } impl<'w> WorldChildBuilder<'w> { - pub fn spawn_bundle(&mut self, bundle: impl Bundle + Send + Sync + 'static) -> EntityMut<'_> { - let parent_entity = self.parent_entity(); + pub fn spawn(&mut self, bundle: impl Bundle + Send + Sync + 'static) -> &mut Self { + let parent_entity = self + .parent_entities + .last() + .cloned() + .expect("There should always be a parent at this point."); let entity = self .world .spawn() @@ -171,32 +235,33 @@ impl<'w> WorldChildBuilder<'w> { parent.insert(Children(smallvec::smallvec![entity])); } } - self.world.entity_mut(entity) + self } - pub fn spawn(&mut self) -> EntityMut<'_> { - let parent_entity = self.parent_entity(); - let entity = self - .world - .spawn() - .insert_bundle((Parent(parent_entity), PreviousParent(parent_entity))) - .id(); - self.current_entity = Some(entity); - if let Some(mut parent) = self.world.get_entity_mut(parent_entity) { - if let Some(mut children) = parent.get_mut::() { - children.0.push(entity); - } else { - parent.insert(Children(smallvec::smallvec![entity])); - } - } - self.world.entity_mut(entity) + pub fn with_bundle(&mut self, bundle: impl Bundle + Send + Sync + 'static) -> &mut Self { + self.world + .entity_mut(self.current_entity.unwrap()) + .insert_bundle(bundle); + self } - pub fn parent_entity(&self) -> Entity { - self.parent_entities - .last() - .cloned() - .expect("There should always be a parent at this point.") + pub fn with(&mut self, component: impl Component) -> &mut Self { + self.world + .entity_mut(self.current_entity.unwrap()) + .insert(component); + self + } + + pub fn current_entity(&self) -> Option { + self.current_entity + } + + pub fn for_current_entity(&mut self, func: impl FnOnce(Entity)) -> &mut Self { + let current_entity = self + .current_entity() + .expect("The 'current entity' is not set. You should spawn an entity first."); + func(current_entity); + self } } @@ -258,28 +323,45 @@ mod tests { let mut queue = CommandQueue::default(); let mut commands = Commands::new(&mut queue, &world); - let mut children = Vec::new(); - let parent = commands.spawn().insert(1).id(); - commands.entity(parent).with_children(|parent| { - children.push(parent.spawn().insert(2).id()); - children.push(parent.spawn().insert(3).id()); - children.push(parent.spawn().insert(4).id()); - }); + let mut parent = None; + let mut child1 = None; + let mut child2 = None; + let mut child3 = None; + + commands + .spawn((1,)) + .for_current_entity(|e| parent = Some(e)) + .with_children(|parent| { + parent + .spawn((2,)) + .for_current_entity(|e| child1 = Some(e)) + .spawn((3,)) + .for_current_entity(|e| child2 = Some(e)) + .spawn((4,)); + + child3 = parent.current_entity(); + }); queue.apply(&mut world); + let parent = parent.expect("parent should exist"); + let child1 = child1.expect("child1 should exist"); + let child2 = child2.expect("child2 should exist"); + let child3 = child3.expect("child3 should exist"); + let expected_children: SmallVec<[Entity; 8]> = smallvec![child1, child2, child3]; + assert_eq!( - world.get::(parent).unwrap().0.as_slice(), - children.as_slice(), + world.get::(parent).unwrap().0.clone(), + expected_children ); - assert_eq!(*world.get::(children[0]).unwrap(), Parent(parent)); - assert_eq!(*world.get::(children[1]).unwrap(), Parent(parent)); + assert_eq!(*world.get::(child1).unwrap(), Parent(parent)); + assert_eq!(*world.get::(child2).unwrap(), Parent(parent)); assert_eq!( - *world.get::(children[0]).unwrap(), + *world.get::(child1).unwrap(), PreviousParent(parent) ); assert_eq!( - *world.get::(children[1]).unwrap(), + *world.get::(child2).unwrap(), PreviousParent(parent) ); } @@ -295,7 +377,7 @@ mod tests { let mut queue = CommandQueue::default(); { let mut commands = Commands::new(&mut queue, &world); - commands.entity(entities[0]).push_children(&entities[1..3]); + commands.push_children(entities[0], &entities[1..3]); } queue.apply(&mut world); @@ -324,7 +406,7 @@ mod tests { { let mut commands = Commands::new(&mut queue, &world); - commands.entity(parent).insert_children(1, &entities[3..]); + commands.insert_children(parent, 1, &entities[3..]); } queue.apply(&mut world); diff --git a/crates/bevy_transform/src/hierarchy/hierarchy.rs b/crates/bevy_transform/src/hierarchy/hierarchy.rs index 23678c4ed592d3..455a88f202ac62 100644 --- a/crates/bevy_transform/src/hierarchy/hierarchy.rs +++ b/crates/bevy_transform/src/hierarchy/hierarchy.rs @@ -1,7 +1,7 @@ use crate::components::{Children, Parent}; use bevy_ecs::{ entity::Entity, - system::{Command, EntityCommands}, + system::{Command, Commands}, world::World, }; use bevy_utils::tracing::debug; @@ -44,14 +44,13 @@ impl Command for DespawnRecursive { pub trait DespawnRecursiveExt { /// Despawns the provided entity and its children. - fn despawn_recursive(&mut self); + fn despawn_recursive(&mut self, entity: Entity) -> &mut Self; } -impl<'a, 'b> DespawnRecursiveExt for EntityCommands<'a, 'b> { +impl<'a> DespawnRecursiveExt for Commands<'a> { /// Despawns the provided entity and its children. - fn despawn_recursive(&mut self) { - let entity = self.id(); - self.commands().add(DespawnRecursive { entity }); + fn despawn_recursive(&mut self, entity: Entity) -> &mut Self { + self.add_command(DespawnRecursive { entity }) } } @@ -74,33 +73,31 @@ mod tests { let mut commands = Commands::new(&mut queue, &world); commands - .spawn_bundle(("Another parent".to_owned(), 0u32)) + .spawn(("Another parent".to_owned(), 0u32)) .with_children(|parent| { - parent.spawn_bundle(("Another child".to_owned(), 1u32)); + parent.spawn(("Another child".to_owned(), 1u32)); }); // Create a grandparent entity which will _not_ be deleted - grandparent_entity = commands.spawn_bundle(("Grandparent".to_owned(), 2u32)).id(); - commands.entity(grandparent_entity).with_children(|parent| { + commands.spawn(("Grandparent".to_owned(), 2u32)); + grandparent_entity = commands.current_entity().unwrap(); + + commands.with_children(|parent| { // Add a child to the grandparent (the "parent"), which will get deleted - parent - .spawn_bundle(("Parent, to be deleted".to_owned(), 3u32)) - // All descendents of the "parent" should also be deleted. - .with_children(|parent| { - parent - .spawn_bundle(("First Child, to be deleted".to_owned(), 4u32)) - .with_children(|parent| { - // child - parent.spawn_bundle(( - "First grand child, to be deleted".to_owned(), - 5u32, - )); - }); - parent.spawn_bundle(("Second child, to be deleted".to_owned(), 6u32)); - }); + parent.spawn(("Parent, to be deleted".to_owned(), 3u32)); + // All descendents of the "parent" should also be deleted. + parent.with_children(|parent| { + parent + .spawn(("First Child, to be deleted".to_owned(), 4u32)) + .with_children(|parent| { + // child + parent.spawn(("First grand child, to be deleted".to_owned(), 5u32)); + }); + parent.spawn(("Second child, to be deleted".to_owned(), 6u32)); + }); }); - commands.spawn_bundle(("An innocent bystander".to_owned(), 7u32)); + commands.spawn(("An innocent bystander".to_owned(), 7u32)); } queue.apply(&mut world); @@ -108,9 +105,9 @@ mod tests { { let mut commands = Commands::new(&mut queue, &world); - commands.entity(parent_entity).despawn_recursive(); - // despawning the same entity twice should not panic - commands.entity(parent_entity).despawn_recursive(); + commands.despawn_recursive(parent_entity); + commands.despawn_recursive(parent_entity); // despawning the same entity twice should + // not panic } queue.apply(&mut world); diff --git a/crates/bevy_transform/src/hierarchy/hierarchy_maintenance_system.rs b/crates/bevy_transform/src/hierarchy/hierarchy_maintenance_system.rs index 0e8282179ffc4b..63bd6e384780f0 100644 --- a/crates/bevy_transform/src/hierarchy/hierarchy_maintenance_system.rs +++ b/crates/bevy_transform/src/hierarchy/hierarchy_maintenance_system.rs @@ -18,7 +18,7 @@ pub fn parent_update_system( for (entity, previous_parent) in removed_parent_query.iter() { if let Ok(mut previous_parent_children) = children_query.get_mut(previous_parent.0) { previous_parent_children.0.retain(|e| *e != entity); - commands.entity(entity).remove::(); + commands.remove::(entity); } } @@ -38,7 +38,7 @@ pub fn parent_update_system( // Set `PreviousParent = Parent`. *previous_parent = PreviousParent(parent.0); } else { - commands.entity(entity).insert(PreviousParent(parent.0)); + commands.insert(entity, PreviousParent(parent.0)); }; } } @@ -67,25 +67,19 @@ mod test { // Add parent entities let mut command_queue = CommandQueue::default(); let mut commands = Commands::new(&mut command_queue, &world); + let mut parent = None; let mut children = Vec::new(); - let parent = commands - .spawn() - .insert(Transform::from_xyz(1.0, 0.0, 0.0)) - .id(); - commands.entity(parent).with_children(|parent| { - children.push( + commands + .spawn((Transform::from_xyz(1.0, 0.0, 0.0),)) + .for_current_entity(|entity| parent = Some(entity)) + .with_children(|parent| { parent - .spawn() - .insert(Transform::from_xyz(0.0, 2.0, 0.0)) - .id(), - ); - children.push( - parent - .spawn() - .insert(Transform::from_xyz(0.0, 3.0, 0.0)) - .id(), - ); - }); + .spawn((Transform::from_xyz(0.0, 2.0, 0.0),)) + .for_current_entity(|entity| children.push(entity)) + .spawn((Transform::from_xyz(0.0, 0.0, 3.0),)) + .for_current_entity(|entity| children.push(entity)); + }); + let parent = parent.unwrap(); command_queue.apply(&mut world); schedule.run(&mut world); diff --git a/crates/bevy_transform/src/transform_propagate_system.rs b/crates/bevy_transform/src/transform_propagate_system.rs index 0c74d2579ce214..feb59d5012ef8e 100644 --- a/crates/bevy_transform/src/transform_propagate_system.rs +++ b/crates/bevy_transform/src/transform_propagate_system.rs @@ -109,22 +109,17 @@ mod test { GlobalTransform::identity(), )) .with_children(|parent| { - children.push( - parent - .spawn_bundle(( - Transform::from_xyz(0.0, 2.0, 0.), - GlobalTransform::identity(), - )) - .id(), - ); - children.push( - parent - .spawn_bundle(( - Transform::from_xyz(0.0, 0.0, 3.), - GlobalTransform::identity(), - )) - .id(), - ); + parent + .spawn(( + Transform::from_xyz(0.0, 2.0, 0.), + GlobalTransform::identity(), + )) + .for_current_entity(|entity| children.push(entity)) + .spawn(( + Transform::from_xyz(0.0, 0.0, 3.), + GlobalTransform::identity(), + )) + .for_current_entity(|entity| children.push(entity)); }); schedule.run(&mut world); @@ -155,27 +150,22 @@ mod test { let mut commands = Commands::new(&mut queue, &world); let mut children = Vec::new(); commands - .spawn_bundle(( + .spawn(( Transform::from_xyz(1.0, 0.0, 0.0), GlobalTransform::identity(), )) .with_children(|parent| { - children.push( - parent - .spawn_bundle(( - Transform::from_xyz(0.0, 2.0, 0.0), - GlobalTransform::identity(), - )) - .id(), - ); - children.push( - parent - .spawn_bundle(( - Transform::from_xyz(0.0, 0.0, 3.0), - GlobalTransform::identity(), - )) - .id(), - ); + parent + .spawn(( + Transform::from_xyz(0.0, 2.0, 0.0), + GlobalTransform::identity(), + )) + .for_current_entity(|entity| children.push(entity)) + .spawn(( + Transform::from_xyz(0.0, 0.0, 3.0), + GlobalTransform::identity(), + )) + .for_current_entity(|entity| children.push(entity)); }); queue.apply(&mut world); schedule.run(&mut world); diff --git a/crates/bevy_ui/src/update.rs b/crates/bevy_ui/src/update.rs index fd3fe3690e99c2..09c91a095f0ad2 100644 --- a/crates/bevy_ui/src/update.rs +++ b/crates/bevy_ui/src/update.rs @@ -80,42 +80,42 @@ mod tests { let mut world = World::default(); let mut queue = CommandQueue::default(); let mut commands = Commands::new(&mut queue, &world); - commands.spawn_bundle(node_with_transform("0")); + commands.spawn(node_with_transform("0")); commands - .spawn_bundle(node_with_transform("1")) + .spawn(node_with_transform("1")) .with_children(|parent| { parent - .spawn_bundle(node_with_transform("1-0")) + .spawn(node_with_transform("1-0")) .with_children(|parent| { - parent.spawn_bundle(node_with_transform("1-0-0")); - parent.spawn_bundle(node_without_transform("1-0-1")); - parent.spawn_bundle(node_with_transform("1-0-2")); + parent.spawn(node_with_transform("1-0-0")); + parent.spawn(node_without_transform("1-0-1")); + parent.spawn(node_with_transform("1-0-2")); }); - parent.spawn_bundle(node_with_transform("1-1")); + parent.spawn(node_with_transform("1-1")); parent - .spawn_bundle(node_without_transform("1-2")) + .spawn(node_without_transform("1-2")) .with_children(|parent| { - parent.spawn_bundle(node_with_transform("1-2-0")); - parent.spawn_bundle(node_with_transform("1-2-1")); + parent.spawn(node_with_transform("1-2-0")); + parent.spawn(node_with_transform("1-2-1")); parent - .spawn_bundle(node_with_transform("1-2-2")) + .spawn(node_with_transform("1-2-2")) .with_children(|_| ()); - parent.spawn_bundle(node_with_transform("1-2-3")); + parent.spawn(node_with_transform("1-2-3")); }); - parent.spawn_bundle(node_with_transform("1-3")); + parent.spawn(node_with_transform("1-3")); }); commands - .spawn_bundle(node_without_transform("2")) + .spawn(node_without_transform("2")) .with_children(|parent| { parent - .spawn_bundle(node_with_transform("2-0")) + .spawn(node_with_transform("2-0")) .with_children(|_parent| ()); parent - .spawn_bundle(node_with_transform("2-1")) + .spawn(node_with_transform("2-1")) .with_children(|parent| { - parent.spawn_bundle(node_with_transform("2-1-0")); + parent.spawn(node_with_transform("2-1-0")); }); }); queue.apply(&mut world); diff --git a/examples/2d/contributors.rs b/examples/2d/contributors.rs index 74db49dc9bda89..2ba11c06c452d1 100644 --- a/examples/2d/contributors.rs +++ b/examples/2d/contributors.rs @@ -57,8 +57,9 @@ fn setup( let texture_handle = asset_server.load("branding/icon.png"); - commands.spawn_bundle(OrthographicCameraBundle::new_2d()); - commands.spawn_bundle(UiCameraBundle::default()); + commands + .spawn(OrthographicCameraBundle::new_2d()) + .spawn(UiCameraBundle::default()); let mut sel = ContributorSelection { order: vec![], @@ -78,16 +79,13 @@ fn setup( let transform = Transform::from_xyz(pos.0, pos.1, 0.0); - let e = commands - .spawn() - .insert_bundle(( - Contributor { hue }, - Velocity { - translation: velocity, - rotation: -dir * 5.0, - }, - )) - .insert_bundle(SpriteBundle { + commands + .spawn((Contributor { hue },)) + .with(Velocity { + translation: velocity, + rotation: -dir * 5.0, + }) + .with_bundle(SpriteBundle { sprite: Sprite { size: Vec2::new(1.0, 1.0) * SPRITE_SIZE, resize_mode: SpriteResizeMode::Manual, @@ -100,20 +98,20 @@ fn setup( }), transform, ..Default::default() - }) - .id(); + }); + + let e = commands.current_entity().unwrap(); sel.order.push((name, e)); } sel.order.shuffle(&mut rnd); - commands.spawn_bundle((SelectTimer, Timer::from_seconds(SHOWCASE_TIMER_SECS, true))); + commands.spawn((SelectTimer, Timer::from_seconds(SHOWCASE_TIMER_SECS, true))); commands - .spawn() - .insert(ContributorDisplay) - .insert_bundle(TextBundle { + .spawn((ContributorDisplay,)) + .with_bundle(TextBundle { style: Style { align_self: AlignSelf::FlexEnd, ..Default::default() diff --git a/examples/2d/sprite.rs b/examples/2d/sprite.rs index 4767e6b903b4d1..c2bbe4ebfe4a10 100644 --- a/examples/2d/sprite.rs +++ b/examples/2d/sprite.rs @@ -13,9 +13,10 @@ fn setup( mut materials: ResMut>, ) { let texture_handle = asset_server.load("branding/icon.png"); - commands.spawn_bundle(OrthographicCameraBundle::new_2d()); - commands.spawn_bundle(SpriteBundle { - material: materials.add(texture_handle.into()), - ..Default::default() - }); + commands + .spawn(OrthographicCameraBundle::new_2d()) + .spawn(SpriteBundle { + material: materials.add(texture_handle.into()), + ..Default::default() + }); } diff --git a/examples/2d/sprite_flipping.rs b/examples/2d/sprite_flipping.rs index 59403cc46b3eb3..6db1c759f1164b 100644 --- a/examples/2d/sprite_flipping.rs +++ b/examples/2d/sprite_flipping.rs @@ -13,16 +13,17 @@ fn setup( mut materials: ResMut>, ) { let texture_handle = asset_server.load("branding/icon.png"); - commands.spawn_bundle(OrthographicCameraBundle::new_2d()); - commands.spawn_bundle(SpriteBundle { - material: materials.add(texture_handle.into()), - sprite: Sprite { - // Flip the logo to the left - flip_x: true, - // And don't flip it upside-down ( the default ) - flip_y: false, + commands + .spawn(OrthographicCameraBundle::new_2d()) + .spawn(SpriteBundle { + material: materials.add(texture_handle.into()), + sprite: Sprite { + // Flip the logo to the left + flip_x: true, + // And don't flip it upside-down ( the default ) + flip_y: false, + ..Default::default() + }, ..Default::default() - }, - ..Default::default() - }); + }); } diff --git a/examples/2d/sprite_sheet.rs b/examples/2d/sprite_sheet.rs index a766087cc53645..622c98f7fedbb5 100644 --- a/examples/2d/sprite_sheet.rs +++ b/examples/2d/sprite_sheet.rs @@ -30,12 +30,12 @@ fn setup( let texture_handle = asset_server.load("textures/rpg/chars/gabe/gabe-idle-run.png"); let texture_atlas = TextureAtlas::from_grid(texture_handle, Vec2::new(24.0, 24.0), 7, 1); let texture_atlas_handle = texture_atlases.add(texture_atlas); - commands.spawn_bundle(OrthographicCameraBundle::new_2d()); commands - .spawn_bundle(SpriteSheetBundle { + .spawn(OrthographicCameraBundle::new_2d()) + .spawn(SpriteSheetBundle { texture_atlas: texture_atlas_handle, transform: Transform::from_scale(Vec3::splat(6.0)), ..Default::default() }) - .insert(Timer::from_seconds(0.1, true)); + .with(Timer::from_seconds(0.1, true)); } diff --git a/examples/2d/text2d.rs b/examples/2d/text2d.rs index a8cbf3c38a2c9e..22c9f156e73610 100644 --- a/examples/2d/text2d.rs +++ b/examples/2d/text2d.rs @@ -9,23 +9,24 @@ fn main() { } fn setup(mut commands: Commands, asset_server: Res) { - // 2d camera - commands.spawn_bundle(OrthographicCameraBundle::new_2d()); - commands.spawn_bundle(Text2dBundle { - text: Text::with_section( - "This text is in the 2D scene.", - TextStyle { - font: asset_server.load("fonts/FiraSans-Bold.ttf"), - font_size: 60.0, - color: Color::WHITE, - }, - TextAlignment { - vertical: VerticalAlign::Center, - horizontal: HorizontalAlign::Center, - }, - ), - ..Default::default() - }); + commands + // 2d camera + .spawn(OrthographicCameraBundle::new_2d()) + .spawn(Text2dBundle { + text: Text::with_section( + "This text is in the 2D scene.", + TextStyle { + font: asset_server.load("fonts/FiraSans-Bold.ttf"), + font_size: 60.0, + color: Color::WHITE, + }, + TextAlignment { + vertical: VerticalAlign::Center, + horizontal: HorizontalAlign::Center, + }, + ), + ..Default::default() + }); } fn animate(time: Res