Skip to content

Commit

Permalink
Fix duplicated chilren in Scene spawn (#904)
Browse files Browse the repository at this point in the history
Fix duplicated chilren in Scene spawn
  • Loading branch information
lassade authored Nov 22, 2020
1 parent 46fac78 commit c1e499d
Show file tree
Hide file tree
Showing 8 changed files with 42 additions and 24 deletions.
19 changes: 9 additions & 10 deletions crates/bevy_transform/src/components/children.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use bevy_ecs::{Entity, MapEntities};
use bevy_property::Properties;
use smallvec::SmallVec;
use std::ops::{Deref, DerefMut};
use std::ops::Deref;

#[derive(Default, Clone, Properties, Debug)]
pub struct Children(pub SmallVec<[Entity; 8]>);
pub struct Children(pub(crate) SmallVec<[Entity; 8]>);

impl MapEntities for Children {
fn map_entities(
Expand All @@ -23,18 +23,17 @@ impl Children {
pub fn with(entity: &[Entity]) -> Self {
Self(SmallVec::from_slice(entity))
}

/// Swaps the child at `a_index` with the child at `b_index`
pub fn swap(&mut self, a_index: usize, b_index: usize) {
self.0.swap(a_index, b_index);
}
}

impl Deref for Children {
type Target = SmallVec<[Entity; 8]>;
type Target = [Entity];

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl DerefMut for Children {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
&self.0[..]
}
}
23 changes: 20 additions & 3 deletions crates/bevy_transform/src/components/parent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ impl MapEntities for Parent {
}
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct PreviousParent(pub Entity);

impl Deref for Parent {
type Target = Entity;

Expand All @@ -41,3 +38,23 @@ impl DerefMut for Parent {
&mut self.0
}
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Properties)]
pub struct PreviousParent(pub(crate) Entity);

impl MapEntities for PreviousParent {
fn map_entities(
&mut self,
entity_map: &bevy_ecs::EntityMap,
) -> Result<(), bevy_ecs::MapEntitiesError> {
self.0 = entity_map.get(self.0)?;
Ok(())
}
}

// TODO: Better handle this case see `impl FromResources for Parent`
impl FromResources for PreviousParent {
fn from_resources(_resources: &bevy_ecs::Resources) -> Self {
PreviousParent(Entity::new(u32::MAX))
}
}
4 changes: 2 additions & 2 deletions crates/bevy_transform/src/hierarchy/child_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ impl Command for InsertChildren {
{
let mut added = false;
if let Ok(mut children) = world.get_mut::<Children>(self.parent) {
children.insert_from_slice(self.index, &self.children);
children.0.insert_from_slice(self.index, &self.children);
added = true;
}

Expand Down Expand Up @@ -54,7 +54,7 @@ impl Command for PushChildren {
{
let mut added = false;
if let Ok(mut children) = world.get_mut::<Children>(self.parent) {
children.extend(self.children.iter().cloned());
children.0.extend(self.children.iter().cloned());
added = true;
}

Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_transform/src/hierarchy/hierarchy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ fn despawn_with_children_recursive(world: &mut World, entity: Entity) {
// first, make the entity's own parent forget about it
if let Ok(parent) = world.get::<Parent>(entity).map(|parent| parent.0) {
if let Ok(mut children) = world.get_mut::<Children>(parent) {
children.retain(|c| *c != entity);
children.0.retain(|c| *c != entity);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ pub fn parent_update_system(
// `children_additions`).
if let Ok(mut new_parent_children) = children_query.get_mut(parent.0) {
// This is the parent
debug_assert!(
!(*new_parent_children).0.contains(&entity),
"children already added"
);
(*new_parent_children).0.push(entity);
} else {
// The parent doesn't have a children entity, lets add it
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_transform/src/hierarchy/world_child_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ impl<'a, 'b> WorldChildBuilder<'a, 'b> {
let world = &mut self.world_builder.world;
let mut added = false;
if let Ok(mut children) = world.get_mut::<Children>(parent_entity) {
children.push(entity);
children.0.push(entity);
added = true;
}

Expand Down
3 changes: 2 additions & 1 deletion crates/bevy_transform/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub mod prelude {

use bevy_app::prelude::*;
use bevy_type_registry::RegisterType;
use prelude::{parent_update_system, Children, GlobalTransform, Parent, Transform};
use prelude::{parent_update_system, Children, GlobalTransform, Parent, PreviousParent, Transform};

#[derive(Default)]
pub struct TransformPlugin;
Expand All @@ -17,6 +17,7 @@ impl Plugin for TransformPlugin {
fn build(&self, app: &mut AppBuilder) {
app.register_component_with::<Children>(|reg| reg.map_entities())
.register_component_with::<Parent>(|reg| reg.map_entities())
.register_component_with::<PreviousParent>(|reg| reg.map_entities())
.register_component::<Transform>()
.register_component::<GlobalTransform>()
// add transform systems to startup so the first update is "correct"
Expand Down
9 changes: 3 additions & 6 deletions examples/ecs/hierarchy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,11 @@ fn setup(
fn rotate(
commands: &mut Commands,
time: Res<Time>,
mut parents_query: Query<(Entity, &mut Children), With<Sprite>>,
mut parents_query: Query<(Entity, &Children), With<Sprite>>,
mut transform_query: Query<&mut Transform, With<Sprite>>,
) {
let angle = std::f32::consts::PI / 2.0;
for (parent, mut children) in parents_query.iter_mut() {
for (parent, children) in parents_query.iter_mut() {
if let Ok(mut transform) = transform_query.get_mut(parent) {
transform.rotate(Quat::from_rotation_z(-angle * time.delta_seconds));
}
Expand All @@ -110,10 +110,7 @@ fn rotate(

// To demonstrate removing children, we'll start to remove the children after a couple of seconds
if time.seconds_since_startup >= 2.0 && children.len() == 3 {
// Using .despawn() on an entity does not remove it from its parent's list of children!
// It must be done manually if using .despawn()
// NOTE: This is a bug. Eventually Bevy will update the children list automatically
let child = children.pop().unwrap();
let child = children.last().copied().unwrap();
commands.despawn(child);
}

Expand Down

0 comments on commit c1e499d

Please sign in to comment.