diff --git a/crates/bevy_hierarchy/src/child_builder.rs b/crates/bevy_hierarchy/src/child_builder.rs index ba772d328d..95298f0d71 100644 --- a/crates/bevy_hierarchy/src/child_builder.rs +++ b/crates/bevy_hierarchy/src/child_builder.rs @@ -341,6 +341,9 @@ pub trait BuildChildren { /// Takes a closure which builds children for this entity using [`ChildBuild`]. fn with_children(&mut self, f: impl FnOnce(&mut Self::Builder<'_>)) -> &mut Self; + /// Spawns the passed bundle and adds it to this entity as a child. + fn with_child(&mut self, bundle: B) -> &mut Self; + /// Pushes children to the back of the builder's children. For any entities that are /// already a child of this one, this method does nothing. /// @@ -432,6 +435,13 @@ impl BuildChildren for EntityCommands<'_> { self } + fn with_child(&mut self, bundle: B) -> &mut Self { + let parent = self.id(); + let child = self.commands().spawn(bundle).id(); + self.commands().add(PushChild { parent, child }); + self + } + fn push_children(&mut self, children: &[Entity]) -> &mut Self { let parent = self.id(); if children.contains(&parent) { @@ -566,6 +576,17 @@ impl BuildChildren for EntityWorldMut<'_> { self } + fn with_child(&mut self, bundle: B) -> &mut Self { + let child = self.world_scope(|world| world.spawn(bundle).id()); + if let Some(mut children_component) = self.get_mut::() { + children_component.0.retain(|value| child != *value); + children_component.0.push(child); + } else { + self.insert(Children::from_entities(&[child])); + } + self + } + fn add_child(&mut self, child: Entity) -> &mut Self { let parent = self.id(); if child == parent { @@ -692,6 +713,14 @@ mod tests { assert_eq!(world.get::(parent).map(|c| &**c), children); } + /// Assert the number of children in the parent's [`Children`] component if it exists. + fn assert_num_children(world: &World, parent: Entity, num_children: usize) { + assert_eq!( + world.get::(parent).map(|c| c.len()).unwrap_or(0), + num_children + ); + } + /// Used to omit a number of events that are not relevant to a particular test. fn omit_events(world: &mut World, number: usize) { let mut events_resource = world.resource_mut::>(); @@ -859,6 +888,19 @@ mod tests { assert_eq!(*world.get::(children[1]).unwrap(), Parent(parent)); } + #[test] + fn build_child() { + let mut world = World::default(); + let mut queue = CommandQueue::default(); + let mut commands = Commands::new(&mut queue, &world); + + let parent = commands.spawn(C(1)).id(); + commands.entity(parent).with_child(C(2)); + + queue.apply(&mut world); + assert_eq!(world.get::(parent).unwrap().0.len(), 1); + } + #[test] fn push_and_insert_and_remove_children_commands() { let mut world = World::default(); @@ -1228,4 +1270,23 @@ mod tests { let children = query.get(&world, parent); assert!(children.is_err()); } + + #[test] + fn with_child() { + let world = &mut World::new(); + world.insert_resource(Events::::default()); + + let a = world.spawn_empty().id(); + let b = (); + let c = (); + let d = (); + + world.entity_mut(a).with_child(b); + + assert_num_children(world, a, 1); + + world.entity_mut(a).with_child(c).with_child(d); + + assert_num_children(world, a, 3); + } } diff --git a/examples/ui/button.rs b/examples/ui/button.rs index edcb4909cd..0a984f7a50 100644 --- a/examples/ui/button.rs +++ b/examples/ui/button.rs @@ -83,15 +83,13 @@ fn setup(mut commands: Commands, asset_server: Res) { background_color: NORMAL_BUTTON.into(), ..default() }) - .with_children(|parent| { - parent.spawn(TextBundle::from_section( - "Button", - TextStyle { - font: asset_server.load("fonts/FiraSans-Bold.ttf"), - font_size: 40.0, - color: Color::srgb(0.9, 0.9, 0.9), - }, - )); - }); + .with_child(TextBundle::from_section( + "Button", + TextStyle { + font: asset_server.load("fonts/FiraSans-Bold.ttf"), + font_size: 40.0, + color: Color::srgb(0.9, 0.9, 0.9), + }, + )); }); }