Add insert_children and push_children to EntityMut (#1728)
The only API to add a parent/child relationship between existing entities is through commands, there is no easy way to do it from `World`. Manually inserting the components is not completely possible since `PreviousParent` has no public constructor. This PR adds two methods to set entities as children of an `EntityMut`: `insert_children` and `push_children`. ~~The API is similar to the one on `Commands`, except that the parent is the `EntityMut`.~~ The API is the same as in #1703. However, the `Parent` and `Children` components are defined in `bevy_transform` which depends on `bevy_ecs`, while `EntityMut` is defined in `bevy_ecs`, so the methods are added to the `BuildWorldChildren` trait instead. If #1545 is merged this should be fixed too. I'm aware cart was experimenting with entity hierarchies, but unless it's a coming soon this PR would be useful to have meanwhile. Co-authored-by: Carter Anderson <mcanders1@gmail.com>
This commit is contained in:
parent
d90d19f1c7
commit
0c374df712
@ -19,6 +19,7 @@ impl Command for InsertChildren {
|
|||||||
for child in self.children.iter() {
|
for child in self.children.iter() {
|
||||||
world
|
world
|
||||||
.entity_mut(*child)
|
.entity_mut(*child)
|
||||||
|
// FIXME: don't erase the previous parent (see #1545)
|
||||||
.insert_bundle((Parent(self.parent), PreviousParent(self.parent)));
|
.insert_bundle((Parent(self.parent), PreviousParent(self.parent)));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@ -55,6 +56,7 @@ impl Command for PushChildren {
|
|||||||
for child in self.children.iter() {
|
for child in self.children.iter() {
|
||||||
world
|
world
|
||||||
.entity_mut(*child)
|
.entity_mut(*child)
|
||||||
|
// FIXME: don't erase the previous parent (see #1545)
|
||||||
.insert_bundle((Parent(self.parent), PreviousParent(self.parent)));
|
.insert_bundle((Parent(self.parent), PreviousParent(self.parent)));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@ -198,6 +200,8 @@ impl<'w> WorldChildBuilder<'w> {
|
|||||||
|
|
||||||
pub trait BuildWorldChildren {
|
pub trait BuildWorldChildren {
|
||||||
fn with_children(&mut self, spawn_children: impl FnOnce(&mut WorldChildBuilder)) -> &mut Self;
|
fn with_children(&mut self, spawn_children: impl FnOnce(&mut WorldChildBuilder)) -> &mut Self;
|
||||||
|
fn push_children(&mut self, children: &[Entity]) -> &mut Self;
|
||||||
|
fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w> BuildWorldChildren for EntityMut<'w> {
|
impl<'w> BuildWorldChildren for EntityMut<'w> {
|
||||||
@ -217,6 +221,47 @@ impl<'w> BuildWorldChildren for EntityMut<'w> {
|
|||||||
self.update_location();
|
self.update_location();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn push_children(&mut self, children: &[Entity]) -> &mut Self {
|
||||||
|
let parent = self.id();
|
||||||
|
{
|
||||||
|
// SAFE: parent entity is not modified
|
||||||
|
let world = unsafe { self.world_mut() };
|
||||||
|
for child in children.iter() {
|
||||||
|
world
|
||||||
|
.entity_mut(*child)
|
||||||
|
// FIXME: don't erase the previous parent (see #1545)
|
||||||
|
.insert_bundle((Parent(parent), PreviousParent(parent)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(mut children_component) = self.get_mut::<Children>() {
|
||||||
|
children_component.0.extend(children.iter().cloned());
|
||||||
|
} else {
|
||||||
|
self.insert(Children::with(children));
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self {
|
||||||
|
let parent = self.id();
|
||||||
|
{
|
||||||
|
// SAFE: parent entity is not modified
|
||||||
|
let world = unsafe { self.world_mut() };
|
||||||
|
for child in children.iter() {
|
||||||
|
world
|
||||||
|
.entity_mut(*child)
|
||||||
|
// FIXME: don't erase the previous parent (see #1545)
|
||||||
|
.insert_bundle((Parent(parent), PreviousParent(parent)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(mut children_component) = self.get_mut::<Children>() {
|
||||||
|
children_component.0.insert_from_slice(index, children);
|
||||||
|
} else {
|
||||||
|
self.insert(Children::with(children));
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w> BuildWorldChildren for WorldChildBuilder<'w> {
|
impl<'w> BuildWorldChildren for WorldChildBuilder<'w> {
|
||||||
@ -235,11 +280,52 @@ impl<'w> BuildWorldChildren for WorldChildBuilder<'w> {
|
|||||||
self.current_entity = self.parent_entities.pop();
|
self.current_entity = self.parent_entities.pop();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn push_children(&mut self, children: &[Entity]) -> &mut Self {
|
||||||
|
let parent = self
|
||||||
|
.current_entity
|
||||||
|
.expect("Cannot add children without a parent. Try creating an entity first.");
|
||||||
|
for child in children.iter() {
|
||||||
|
self.world
|
||||||
|
.entity_mut(*child)
|
||||||
|
// FIXME: don't erase the previous parent (see #1545)
|
||||||
|
.insert_bundle((Parent(parent), PreviousParent(parent)));
|
||||||
|
}
|
||||||
|
if let Some(mut children_component) = self.world.get_mut::<Children>(parent) {
|
||||||
|
children_component.0.extend(children.iter().cloned());
|
||||||
|
} else {
|
||||||
|
self.world
|
||||||
|
.entity_mut(parent)
|
||||||
|
.insert(Children::with(children));
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self {
|
||||||
|
let parent = self
|
||||||
|
.current_entity
|
||||||
|
.expect("Cannot add children without a parent. Try creating an entity first.");
|
||||||
|
|
||||||
|
for child in children.iter() {
|
||||||
|
self.world
|
||||||
|
.entity_mut(*child)
|
||||||
|
// FIXME: don't erase the previous parent (see #1545)
|
||||||
|
.insert_bundle((Parent(parent), PreviousParent(parent)));
|
||||||
|
}
|
||||||
|
if let Some(mut children_component) = self.world.get_mut::<Children>(parent) {
|
||||||
|
children_component.0.insert_from_slice(index, children);
|
||||||
|
} else {
|
||||||
|
self.world
|
||||||
|
.entity_mut(parent)
|
||||||
|
.insert(Children::with(children));
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::BuildChildren;
|
use super::{BuildChildren, BuildWorldChildren};
|
||||||
use crate::prelude::{Children, Parent, PreviousParent};
|
use crate::prelude::{Children, Parent, PreviousParent};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
@ -281,7 +367,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn push_and_insert_children() {
|
fn push_and_insert_children_commands() {
|
||||||
let mut world = World::default();
|
let mut world = World::default();
|
||||||
|
|
||||||
let entities = world
|
let entities = world
|
||||||
@ -340,4 +426,55 @@ mod tests {
|
|||||||
PreviousParent(parent)
|
PreviousParent(parent)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn push_and_insert_children_world() {
|
||||||
|
let mut world = World::default();
|
||||||
|
|
||||||
|
let entities = world
|
||||||
|
.spawn_batch(vec![(1,), (2,), (3,), (4,), (5,)])
|
||||||
|
.collect::<Vec<Entity>>();
|
||||||
|
|
||||||
|
world.entity_mut(entities[0]).push_children(&entities[1..3]);
|
||||||
|
|
||||||
|
let parent = entities[0];
|
||||||
|
let child1 = entities[1];
|
||||||
|
let child2 = entities[2];
|
||||||
|
let child3 = entities[3];
|
||||||
|
let child4 = entities[4];
|
||||||
|
|
||||||
|
let expected_children: SmallVec<[Entity; 8]> = smallvec![child1, child2];
|
||||||
|
assert_eq!(
|
||||||
|
world.get::<Children>(parent).unwrap().0.clone(),
|
||||||
|
expected_children
|
||||||
|
);
|
||||||
|
assert_eq!(*world.get::<Parent>(child1).unwrap(), Parent(parent));
|
||||||
|
assert_eq!(*world.get::<Parent>(child2).unwrap(), Parent(parent));
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
*world.get::<PreviousParent>(child1).unwrap(),
|
||||||
|
PreviousParent(parent)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
*world.get::<PreviousParent>(child2).unwrap(),
|
||||||
|
PreviousParent(parent)
|
||||||
|
);
|
||||||
|
|
||||||
|
world.entity_mut(parent).insert_children(1, &entities[3..]);
|
||||||
|
let expected_children: SmallVec<[Entity; 8]> = smallvec![child1, child3, child4, child2];
|
||||||
|
assert_eq!(
|
||||||
|
world.get::<Children>(parent).unwrap().0.clone(),
|
||||||
|
expected_children
|
||||||
|
);
|
||||||
|
assert_eq!(*world.get::<Parent>(child3).unwrap(), Parent(parent));
|
||||||
|
assert_eq!(*world.get::<Parent>(child4).unwrap(), Parent(parent));
|
||||||
|
assert_eq!(
|
||||||
|
*world.get::<PreviousParent>(child3).unwrap(),
|
||||||
|
PreviousParent(parent)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
*world.get::<PreviousParent>(child4).unwrap(),
|
||||||
|
PreviousParent(parent)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user