From d9ed0180ea74d7eb5a049cf67b64defd4a95fa3c Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Wed, 9 Mar 2022 22:39:03 -0500 Subject: [PATCH 01/22] Clone bevy_transform contents into bevy_hierarchy --- crates/bevy_hierarchy/.gitignore | 24 + crates/bevy_hierarchy/Cargo.toml | 20 + .../bevy_hierarchy/src/components/children.rs | 43 ++ .../src/components/global_transform.rs | 279 ++++++++ crates/bevy_hierarchy/src/components/mod.rs | 9 + .../bevy_hierarchy/src/components/parent.rs | 64 ++ .../src/components/transform.rs | 280 ++++++++ .../src/hierarchy/child_builder.rs | 667 ++++++++++++++++++ .../bevy_hierarchy/src/hierarchy/hierarchy.rs | 203 ++++++ .../hierarchy/hierarchy_maintenance_system.rs | 170 +++++ crates/bevy_hierarchy/src/hierarchy/mod.rs | 8 + crates/bevy_hierarchy/src/lib.rs | 126 ++++ .../src/transform_propagate_system.rs | 177 +++++ crates/bevy_transform/Cargo.toml | 2 +- 14 files changed, 2071 insertions(+), 1 deletion(-) create mode 100644 crates/bevy_hierarchy/.gitignore create mode 100644 crates/bevy_hierarchy/Cargo.toml create mode 100644 crates/bevy_hierarchy/src/components/children.rs create mode 100644 crates/bevy_hierarchy/src/components/global_transform.rs create mode 100644 crates/bevy_hierarchy/src/components/mod.rs create mode 100644 crates/bevy_hierarchy/src/components/parent.rs create mode 100644 crates/bevy_hierarchy/src/components/transform.rs create mode 100644 crates/bevy_hierarchy/src/hierarchy/child_builder.rs create mode 100644 crates/bevy_hierarchy/src/hierarchy/hierarchy.rs create mode 100644 crates/bevy_hierarchy/src/hierarchy/hierarchy_maintenance_system.rs create mode 100644 crates/bevy_hierarchy/src/hierarchy/mod.rs create mode 100644 crates/bevy_hierarchy/src/lib.rs create mode 100644 crates/bevy_hierarchy/src/transform_propagate_system.rs diff --git a/crates/bevy_hierarchy/.gitignore b/crates/bevy_hierarchy/.gitignore new file mode 100644 index 0000000000000..af368c3d50227 --- /dev/null +++ b/crates/bevy_hierarchy/.gitignore @@ -0,0 +1,24 @@ +book/book +target +Cargo.lock +*.log + +# Backup files +.DS_Store +thumbs.db +*~ +*.rs.bk +*.swp + +# IDE / Editor files +*.iml +.idea +.vscode + + +#Added by cargo +# +#already existing elements are commented out + +/target +**/*.rs.bk diff --git a/crates/bevy_hierarchy/Cargo.toml b/crates/bevy_hierarchy/Cargo.toml new file mode 100644 index 0000000000000..87f4892a64fcf --- /dev/null +++ b/crates/bevy_hierarchy/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "bevy_hierarchy" +version = "0.6.0" +edition = "2021" +description = "Provides hierarchy functionality for Bevy Engine" +homepage = "https://bevyengine.org" +repository = "https://github.com/bevyengine/bevy" +license = "MIT OR Apache-2.0" +keywords = ["bevy"] + +[dependencies] +# bevy +bevy_app = { path = "../bevy_app", version = "0.6.0" } +bevy_ecs = { path = "../bevy_ecs", version = "0.6.0", features = ["bevy_reflect"] } +bevy_math = { path = "../bevy_math", version = "0.6.0" } +bevy_reflect = { path = "../bevy_reflect", version = "0.6.0", features = ["bevy"] } +bevy_utils = { path = "../bevy_utils", version = "0.6.0" } + +# other +smallvec = { version = "1.6", features = ["serde", "union", "const_generics"] } diff --git a/crates/bevy_hierarchy/src/components/children.rs b/crates/bevy_hierarchy/src/components/children.rs new file mode 100644 index 0000000000000..96097a1da8a59 --- /dev/null +++ b/crates/bevy_hierarchy/src/components/children.rs @@ -0,0 +1,43 @@ +use bevy_ecs::{ + component::Component, + entity::{Entity, EntityMap, MapEntities, MapEntitiesError}, + reflect::{ReflectComponent, ReflectMapEntities}, +}; +use bevy_reflect::Reflect; +use smallvec::SmallVec; +use std::ops::Deref; + +/// Contains references to the child entities of this entity +#[derive(Component, Default, Clone, Debug, Reflect)] +#[reflect(Component, MapEntities)] +pub struct Children(pub(crate) SmallVec<[Entity; 8]>); + +impl MapEntities for Children { + fn map_entities(&mut self, entity_map: &EntityMap) -> Result<(), MapEntitiesError> { + for entity in self.0.iter_mut() { + *entity = entity_map.get(*entity)?; + } + + Ok(()) + } +} + +impl Children { + /// Builds and returns a [`Children`] component with the given entities + 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 = [Entity]; + + fn deref(&self) -> &Self::Target { + &self.0[..] + } +} diff --git a/crates/bevy_hierarchy/src/components/global_transform.rs b/crates/bevy_hierarchy/src/components/global_transform.rs new file mode 100644 index 0000000000000..68664507d4455 --- /dev/null +++ b/crates/bevy_hierarchy/src/components/global_transform.rs @@ -0,0 +1,279 @@ +use super::Transform; +use bevy_ecs::{component::Component, reflect::ReflectComponent}; +use bevy_math::{const_vec3, Mat3, Mat4, Quat, Vec3}; +use bevy_reflect::Reflect; +use std::ops::Mul; + +/// Describe the position of an entity relative to the reference frame. +/// +/// * To place or move an entity, you should set its [`Transform`]. +/// * To get the global position of an entity, you should get its [`GlobalTransform`]. +/// * For transform hierarchies to work correctly, you must have both a [`Transform`] and a [`GlobalTransform`]. +/// * You may use the [`TransformBundle`](crate::TransformBundle) to guarantee this. +/// +/// ## [`Transform`] and [`GlobalTransform`] +/// +/// [`Transform`] is the position of an entity relative to its parent position, or the reference +/// frame if it doesn't have a [`Parent`](super::Parent). +/// +/// [`GlobalTransform`] is the position of an entity relative to the reference frame. +/// +/// [`GlobalTransform`] is updated from [`Transform`] in the system +/// [`transform_propagate_system`](crate::transform_propagate_system::transform_propagate_system). +/// +/// This system runs in stage [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate). If you +/// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag +/// before the [`GlobalTransform`] is updated. +#[derive(Component, Debug, PartialEq, Clone, Copy, Reflect)] +#[reflect(Component, PartialEq)] +pub struct GlobalTransform { + /// The position of the global transform + pub translation: Vec3, + /// The rotation of the global transform + pub rotation: Quat, + /// The scale of the global transform + pub scale: Vec3, +} + +impl GlobalTransform { + #[doc(hidden)] + #[inline] + pub const fn from_xyz(x: f32, y: f32, z: f32) -> Self { + Self::from_translation(const_vec3!([x, y, z])) + } + + /// Creates a new identity [`GlobalTransform`], with no translation, rotation, and a scale of 1 + /// on all axes. + #[inline] + pub const fn identity() -> Self { + GlobalTransform { + translation: Vec3::ZERO, + rotation: Quat::IDENTITY, + scale: Vec3::ONE, + } + } + + #[doc(hidden)] + #[inline] + pub fn from_matrix(matrix: Mat4) -> Self { + let (scale, rotation, translation) = matrix.to_scale_rotation_translation(); + + GlobalTransform { + translation, + rotation, + scale, + } + } + + #[doc(hidden)] + #[inline] + pub const fn from_translation(translation: Vec3) -> Self { + GlobalTransform { + translation, + ..Self::identity() + } + } + + #[doc(hidden)] + #[inline] + pub const fn from_rotation(rotation: Quat) -> Self { + GlobalTransform { + rotation, + ..Self::identity() + } + } + + #[doc(hidden)] + #[inline] + pub const fn from_scale(scale: Vec3) -> Self { + GlobalTransform { + scale, + ..Self::identity() + } + } + + #[doc(hidden)] + #[inline] + #[must_use] + pub fn looking_at(mut self, target: Vec3, up: Vec3) -> Self { + self.look_at(target, up); + self + } + + #[doc(hidden)] + #[inline] + pub const fn with_translation(mut self, translation: Vec3) -> Self { + self.translation = translation; + self + } + + #[doc(hidden)] + #[inline] + pub const fn with_rotation(mut self, rotation: Quat) -> Self { + self.rotation = rotation; + self + } + + #[doc(hidden)] + #[inline] + pub const fn with_scale(mut self, scale: Vec3) -> Self { + self.scale = scale; + self + } + + /// Returns the 3d affine transformation matrix from this transforms translation, + /// rotation, and scale. + #[inline] + pub fn compute_matrix(&self) -> Mat4 { + Mat4::from_scale_rotation_translation(self.scale, self.rotation, self.translation) + } + + /// Get the unit vector in the local x direction + #[inline] + pub fn local_x(&self) -> Vec3 { + self.rotation * Vec3::X + } + + /// Equivalent to [`-local_x()`][GlobalTransform::local_x] + #[inline] + pub fn left(&self) -> Vec3 { + -self.local_x() + } + + /// Equivalent to [`local_x()`][GlobalTransform::local_x] + #[inline] + pub fn right(&self) -> Vec3 { + self.local_x() + } + + /// Get the unit vector in the local y direction + #[inline] + pub fn local_y(&self) -> Vec3 { + self.rotation * Vec3::Y + } + + /// Equivalent to [`local_y()`][GlobalTransform::local_y] + #[inline] + pub fn up(&self) -> Vec3 { + self.local_y() + } + + /// Equivalent to [`-local_y()`][GlobalTransform::local_y] + #[inline] + pub fn down(&self) -> Vec3 { + -self.local_y() + } + + /// Get the unit vector in the local z direction + #[inline] + pub fn local_z(&self) -> Vec3 { + self.rotation * Vec3::Z + } + + /// Equivalent to [`-local_z()`][GlobalTransform::local_z] + #[inline] + pub fn forward(&self) -> Vec3 { + -self.local_z() + } + + /// Equivalent to [`local_z()`][GlobalTransform::local_z] + #[inline] + pub fn back(&self) -> Vec3 { + self.local_z() + } + + #[doc(hidden)] + #[inline] + pub fn rotate(&mut self, rotation: Quat) { + self.rotation = rotation * self.rotation; + } + + #[doc(hidden)] + #[inline] + pub fn rotate_around(&mut self, point: Vec3, rotation: Quat) { + self.translation = point + rotation * (self.translation - point); + self.rotation *= rotation; + } + + /// Multiplies `self` with `transform` component by component, returning the + /// resulting [`GlobalTransform`] + #[inline] + #[must_use] + pub fn mul_transform(&self, transform: Transform) -> Self { + let translation = self.mul_vec3(transform.translation); + let rotation = self.rotation * transform.rotation; + let scale = self.scale * transform.scale; + Self { + translation, + rotation, + scale, + } + } + + /// Returns a [`Vec3`] of this [`Transform`] applied to `value`. + #[inline] + pub fn mul_vec3(&self, mut value: Vec3) -> Vec3 { + value = self.scale * value; + value = self.rotation * value; + value += self.translation; + value + } + + #[doc(hidden)] + #[inline] + pub fn apply_non_uniform_scale(&mut self, scale: Vec3) { + self.scale *= scale; + } + + #[doc(hidden)] + #[inline] + pub fn look_at(&mut self, target: Vec3, up: Vec3) { + let forward = Vec3::normalize(self.translation - target); + let right = up.cross(forward).normalize(); + let up = forward.cross(right); + self.rotation = Quat::from_mat3(&Mat3::from_cols(right, up, forward)); + } +} + +impl Default for GlobalTransform { + fn default() -> Self { + Self::identity() + } +} + +impl From for GlobalTransform { + fn from(transform: Transform) -> Self { + Self { + translation: transform.translation, + rotation: transform.rotation, + scale: transform.scale, + } + } +} + +impl Mul for GlobalTransform { + type Output = GlobalTransform; + + #[inline] + fn mul(self, global_transform: GlobalTransform) -> Self::Output { + self.mul_transform(global_transform.into()) + } +} + +impl Mul for GlobalTransform { + type Output = GlobalTransform; + + #[inline] + fn mul(self, transform: Transform) -> Self::Output { + self.mul_transform(transform) + } +} + +impl Mul for GlobalTransform { + type Output = Vec3; + + #[inline] + fn mul(self, value: Vec3) -> Self::Output { + self.mul_vec3(value) + } +} diff --git a/crates/bevy_hierarchy/src/components/mod.rs b/crates/bevy_hierarchy/src/components/mod.rs new file mode 100644 index 0000000000000..67720a2b4e08e --- /dev/null +++ b/crates/bevy_hierarchy/src/components/mod.rs @@ -0,0 +1,9 @@ +mod children; +mod global_transform; +mod parent; +mod transform; + +pub use children::Children; +pub use global_transform::*; +pub use parent::{Parent, PreviousParent}; +pub use transform::*; diff --git a/crates/bevy_hierarchy/src/components/parent.rs b/crates/bevy_hierarchy/src/components/parent.rs new file mode 100644 index 0000000000000..ddc0e2a634ee6 --- /dev/null +++ b/crates/bevy_hierarchy/src/components/parent.rs @@ -0,0 +1,64 @@ +use bevy_ecs::{ + component::Component, + entity::{Entity, EntityMap, MapEntities, MapEntitiesError}, + reflect::{ReflectComponent, ReflectMapEntities}, + world::{FromWorld, World}, +}; +use bevy_reflect::Reflect; +use std::ops::{Deref, DerefMut}; + +/// Holds a reference to the parent entity of this entity. +/// This component should only be present on entities that actually have a parent entity. +#[derive(Component, Debug, Copy, Clone, Eq, PartialEq, Reflect)] +#[reflect(Component, MapEntities, PartialEq)] +pub struct Parent(pub Entity); + +// TODO: We need to impl either FromWorld or Default so Parent can be registered as Properties. +// This is because Properties deserialize by creating an instance and apply a patch on top. +// However Parent should only ever be set with a real user-defined entity. Its worth looking into +// better ways to handle cases like this. +impl FromWorld for Parent { + fn from_world(_world: &mut World) -> Self { + Parent(Entity::from_raw(u32::MAX)) + } +} + +impl MapEntities for Parent { + fn map_entities(&mut self, entity_map: &EntityMap) -> Result<(), MapEntitiesError> { + self.0 = entity_map.get(self.0)?; + Ok(()) + } +} + +impl Deref for Parent { + type Target = Entity; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Parent { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +/// Component that holds the [`Parent`] this entity had previously +#[derive(Component, Debug, Copy, Clone, Eq, PartialEq, Reflect)] +#[reflect(Component, MapEntities, PartialEq)] +pub struct PreviousParent(pub(crate) Entity); + +impl MapEntities for PreviousParent { + fn map_entities(&mut self, entity_map: &EntityMap) -> Result<(), MapEntitiesError> { + self.0 = entity_map.get(self.0)?; + Ok(()) + } +} + +// TODO: Better handle this case see `impl FromWorld for Parent` +impl FromWorld for PreviousParent { + fn from_world(_world: &mut World) -> Self { + PreviousParent(Entity::from_raw(u32::MAX)) + } +} diff --git a/crates/bevy_hierarchy/src/components/transform.rs b/crates/bevy_hierarchy/src/components/transform.rs new file mode 100644 index 0000000000000..f0c6d536f3982 --- /dev/null +++ b/crates/bevy_hierarchy/src/components/transform.rs @@ -0,0 +1,280 @@ +use super::GlobalTransform; +use bevy_ecs::{component::Component, reflect::ReflectComponent}; +use bevy_math::{const_vec3, Mat3, Mat4, Quat, Vec3}; +use bevy_reflect::Reflect; +use std::ops::Mul; + +/// Describe the position of an entity. If the entity has a parent, the position is relative +/// to its parent position. +/// +/// * To place or move an entity, you should set its [`Transform`]. +/// * To get the global position of an entity, you should get its [`GlobalTransform`]. +/// * To be displayed, an entity must have both a [`Transform`] and a [`GlobalTransform`]. +/// * You may use the [`TransformBundle`](crate::TransformBundle) to guarantee this. +/// +/// ## [`Transform`] and [`GlobalTransform`] +/// +/// [`Transform`] is the position of an entity relative to its parent position, or the reference +/// frame if it doesn't have a [`Parent`](super::Parent). +/// +/// [`GlobalTransform`] is the position of an entity relative to the reference frame. +/// +/// [`GlobalTransform`] is updated from [`Transform`] in the system +/// [`transform_propagate_system`](crate::transform_propagate_system::transform_propagate_system). +/// +/// This system runs in stage [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate). If you +/// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag +/// before the [`GlobalTransform`] is updated. +#[derive(Component, Debug, PartialEq, Clone, Copy, Reflect)] +#[reflect(Component, PartialEq)] +pub struct Transform { + /// Position of the entity. In 2d, the last value of the `Vec3` is used for z-ordering. + pub translation: Vec3, + /// Rotation of the entity. + pub rotation: Quat, + /// Scale of the entity. + pub scale: Vec3, +} + +impl Transform { + /// Creates a new [`Transform`] at the position `(x, y, z)`. In 2d, the `z` component + /// is used for z-ordering elements: higher `z`-value will be in front of lower + /// `z`-value. + #[inline] + pub const fn from_xyz(x: f32, y: f32, z: f32) -> Self { + Self::from_translation(const_vec3!([x, y, z])) + } + + /// Creates a new identity [`Transform`], with no translation, rotation, and a scale of 1 on + /// all axes. + #[inline] + pub const fn identity() -> Self { + Transform { + translation: Vec3::ZERO, + rotation: Quat::IDENTITY, + scale: Vec3::ONE, + } + } + + /// Extracts the translation, rotation, and scale from `matrix`. It must be a 3d affine + /// transformation matrix. + #[inline] + pub fn from_matrix(matrix: Mat4) -> Self { + let (scale, rotation, translation) = matrix.to_scale_rotation_translation(); + + Transform { + translation, + rotation, + scale, + } + } + + /// Creates a new [`Transform`], with `translation`. Rotation will be 0 and scale 1 on + /// all axes. + #[inline] + pub const fn from_translation(translation: Vec3) -> Self { + Transform { + translation, + ..Self::identity() + } + } + + /// Creates a new [`Transform`], with `rotation`. Translation will be 0 and scale 1 on + /// all axes. + #[inline] + pub const fn from_rotation(rotation: Quat) -> Self { + Transform { + rotation, + ..Self::identity() + } + } + + /// Creates a new [`Transform`], with `scale`. Translation will be 0 and rotation 0 on + /// all axes. + #[inline] + pub const fn from_scale(scale: Vec3) -> Self { + Transform { + scale, + ..Self::identity() + } + } + + /// Updates and returns this [`Transform`] by rotating it so that its unit vector in the + /// local z direction is toward `target` and its unit vector in the local y direction + /// is toward `up`. + #[inline] + #[must_use] + pub fn looking_at(mut self, target: Vec3, up: Vec3) -> Self { + self.look_at(target, up); + self + } + + /// Returns this [`Transform`] with a new translation. + #[inline] + pub const fn with_translation(mut self, translation: Vec3) -> Self { + self.translation = translation; + self + } + + /// Returns this [`Transform`] with a new rotation. + #[inline] + pub const fn with_rotation(mut self, rotation: Quat) -> Self { + self.rotation = rotation; + self + } + + /// Returns this [`Transform`] with a new scale. + #[inline] + pub const fn with_scale(mut self, scale: Vec3) -> Self { + self.scale = scale; + self + } + + /// Returns the 3d affine transformation matrix from this transforms translation, + /// rotation, and scale. + #[inline] + pub fn compute_matrix(&self) -> Mat4 { + Mat4::from_scale_rotation_translation(self.scale, self.rotation, self.translation) + } + + /// Get the unit vector in the local x direction. + #[inline] + pub fn local_x(&self) -> Vec3 { + self.rotation * Vec3::X + } + + /// Equivalent to [`-local_x()`][Transform::local_x()] + #[inline] + pub fn left(&self) -> Vec3 { + -self.local_x() + } + + /// Equivalent to [`local_x()`][Transform::local_x()] + #[inline] + pub fn right(&self) -> Vec3 { + self.local_x() + } + + /// Get the unit vector in the local y direction. + #[inline] + pub fn local_y(&self) -> Vec3 { + self.rotation * Vec3::Y + } + + /// Equivalent to [`local_y()`][Transform::local_y] + #[inline] + pub fn up(&self) -> Vec3 { + self.local_y() + } + + /// Equivalent to [`-local_y()`][Transform::local_y] + #[inline] + pub fn down(&self) -> Vec3 { + -self.local_y() + } + + /// Get the unit vector in the local z direction. + #[inline] + pub fn local_z(&self) -> Vec3 { + self.rotation * Vec3::Z + } + + /// Equivalent to [`-local_z()`][Transform::local_z] + #[inline] + pub fn forward(&self) -> Vec3 { + -self.local_z() + } + + /// Equivalent to [`local_z()`][Transform::local_z] + #[inline] + pub fn back(&self) -> Vec3 { + self.local_z() + } + + /// Rotates the transform by the given rotation. + #[inline] + pub fn rotate(&mut self, rotation: Quat) { + self.rotation = rotation * self.rotation; + } + + /// Rotates this [`Transform`] around a point in space. + /// If the point is a zero vector, this will rotate around the parent (if any) or the origin. + #[inline] + pub fn rotate_around(&mut self, point: Vec3, rotation: Quat) { + self.translation = point + rotation * (self.translation - point); + self.rotation *= rotation; + } + + /// Multiplies `self` with `transform` component by component, returning the + /// resulting [`Transform`] + #[inline] + #[must_use] + pub fn mul_transform(&self, transform: Transform) -> Self { + let translation = self.mul_vec3(transform.translation); + let rotation = self.rotation * transform.rotation; + let scale = self.scale * transform.scale; + Transform { + translation, + rotation, + scale, + } + } + + /// Returns a [`Vec3`] of this [`Transform`] applied to `value`. + #[inline] + pub fn mul_vec3(&self, mut value: Vec3) -> Vec3 { + value = self.scale * value; + value = self.rotation * value; + value += self.translation; + value + } + + /// Changes the `scale` of this [`Transform`], multiplying the current `scale` by + /// `scale_factor`. + #[inline] + pub fn apply_non_uniform_scale(&mut self, scale_factor: Vec3) { + self.scale *= scale_factor; + } + + /// Rotates this [`Transform`] so that its local z direction is toward + /// `target` and its local y direction is toward `up`. + #[inline] + pub fn look_at(&mut self, target: Vec3, up: Vec3) { + let forward = Vec3::normalize(self.translation - target); + let right = up.cross(forward).normalize(); + let up = forward.cross(right); + self.rotation = Quat::from_mat3(&Mat3::from_cols(right, up, forward)); + } +} + +impl Default for Transform { + fn default() -> Self { + Self::identity() + } +} + +impl From for Transform { + fn from(transform: GlobalTransform) -> Self { + Self { + translation: transform.translation, + rotation: transform.rotation, + scale: transform.scale, + } + } +} + +impl Mul for Transform { + type Output = Transform; + + fn mul(self, transform: Transform) -> Self::Output { + self.mul_transform(transform) + } +} + +impl Mul for Transform { + type Output = Vec3; + + fn mul(self, value: Vec3) -> Self::Output { + self.mul_vec3(value) + } +} diff --git a/crates/bevy_hierarchy/src/hierarchy/child_builder.rs b/crates/bevy_hierarchy/src/hierarchy/child_builder.rs new file mode 100644 index 0000000000000..3dd47da3878a6 --- /dev/null +++ b/crates/bevy_hierarchy/src/hierarchy/child_builder.rs @@ -0,0 +1,667 @@ +use crate::prelude::{Children, Parent, PreviousParent}; +use bevy_ecs::{ + bundle::Bundle, + entity::Entity, + system::{Command, Commands, EntityCommands}, + world::{EntityMut, World}, +}; +use smallvec::SmallVec; + +/// Command that adds a child to an entity +#[derive(Debug)] +pub struct AddChild { + /// Parent entity to add the child to + pub parent: Entity, + /// Child entity to add + pub child: Entity, +} + +impl Command for AddChild { + fn write(self, world: &mut World) { + world + .entity_mut(self.child) + // FIXME: don't erase the previous parent (see #1545) + .insert_bundle((Parent(self.parent), PreviousParent(self.parent))); + if let Some(mut children) = world.get_mut::(self.parent) { + children.0.push(self.child); + } else { + world + .entity_mut(self.parent) + .insert(Children(smallvec::smallvec![self.child])); + } + } +} + +/// Command that inserts a child at a given index of a parent's children, shifting following children back +#[derive(Debug)] +pub struct InsertChildren { + parent: Entity, + children: SmallVec<[Entity; 8]>, + index: usize, +} + +impl Command for InsertChildren { + fn write(self, world: &mut World) { + for child in self.children.iter() { + world + .entity_mut(*child) + // FIXME: don't erase the previous parent (see #1545) + .insert_bundle((Parent(self.parent), PreviousParent(self.parent))); + } + { + if let Some(mut children) = world.get_mut::(self.parent) { + children.0.insert_from_slice(self.index, &self.children); + } else { + world + .entity_mut(self.parent) + .insert(Children(self.children)); + } + } + } +} + +/// Command that pushes children to the end of the entity's children +#[derive(Debug)] +pub struct PushChildren { + parent: Entity, + children: SmallVec<[Entity; 8]>, +} + +impl Command for PushChildren { + fn write(self, world: &mut World) { + for child in self.children.iter() { + world + .entity_mut(*child) + // FIXME: don't erase the previous parent (see #1545) + .insert_bundle((Parent(self.parent), PreviousParent(self.parent))); + } + { + let mut added = false; + if let Some(mut children) = world.get_mut::(self.parent) { + children.0.extend(self.children.iter().cloned()); + added = true; + } + + // NOTE: ideally this is just an else statement, but currently that _incorrectly_ fails + // borrow-checking + if !added { + world + .entity_mut(self.parent) + .insert(Children(self.children)); + } + } + } +} + +/// Command that removes children from an entity, and removes that child's parent and inserts it into the previous parent component +pub struct RemoveChildren { + parent: Entity, + children: SmallVec<[Entity; 8]>, +} + +fn remove_children(parent: Entity, children: &[Entity], world: &mut World) { + for child in children.iter() { + let mut child = world.entity_mut(*child); + let mut remove_parent = false; + if let Some(child_parent) = child.get_mut::() { + if child_parent.0 == parent { + remove_parent = true; + } + } + if remove_parent { + if let Some(parent) = child.remove::() { + child.insert(PreviousParent(parent.0)); + } + } + } + // Remove the children from the parents. + if let Some(mut parent_children) = world.get_mut::(parent) { + parent_children + .0 + .retain(|parent_child| !children.contains(parent_child)); + } +} + +impl Command for RemoveChildren { + fn write(self, world: &mut World) { + // Remove any matching Parent components from the children + remove_children(self.parent, &self.children, world); + } +} + +/// Struct for building children onto an entity +pub struct ChildBuilder<'w, 's, 'a> { + commands: &'a mut Commands<'w, 's>, + push_children: PushChildren, +} + +impl<'w, 's, 'a> ChildBuilder<'w, 's, 'a> { + /// Spawns an entity with the given bundle and inserts it into the children defined by the [`ChildBuilder`] + pub fn spawn_bundle(&mut self, bundle: impl Bundle) -> EntityCommands<'w, 's, '_> { + let e = self.commands.spawn_bundle(bundle); + self.push_children.children.push(e.id()); + e + } + + /// Spawns an [`Entity`] with no components and inserts it into the children defined by the [`ChildBuilder`] which adds the [`Parent`] component to it. + pub fn spawn(&mut self) -> EntityCommands<'w, 's, '_> { + let e = self.commands.spawn(); + self.push_children.children.push(e.id()); + e + } + + /// Returns the parent entity of this [`ChildBuilder`] + pub fn parent_entity(&self) -> Entity { + self.push_children.parent + } + + /// Adds a command to this [`ChildBuilder`] + pub fn add_command(&mut self, command: C) -> &mut Self { + self.commands.add(command); + self + } +} + +/// Trait defining how to build children +pub trait BuildChildren { + /// Creates a [`ChildBuilder`] with the given children built in the given closure + fn with_children(&mut self, f: impl FnOnce(&mut ChildBuilder)) -> &mut Self; + /// Pushes children to the back of the builder's children + fn push_children(&mut self, children: &[Entity]) -> &mut Self; + /// Inserts children at the given index + fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self; + /// Removes the given children + fn remove_children(&mut self, children: &[Entity]) -> &mut Self; + /// Adds a single child + fn add_child(&mut self, child: Entity) -> &mut Self; +} + +impl<'w, 's, 'a> BuildChildren for EntityCommands<'w, 's, 'a> { + fn with_children(&mut self, spawn_children: impl FnOnce(&mut ChildBuilder)) -> &mut Self { + let parent = self.id(); + let push_children = { + let mut builder = ChildBuilder { + commands: self.commands(), + push_children: PushChildren { + children: SmallVec::default(), + parent, + }, + }; + spawn_children(&mut builder); + builder.push_children + }; + + self.commands().add(push_children); + self + } + + fn push_children(&mut self, children: &[Entity]) -> &mut Self { + let parent = self.id(); + self.commands().add(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 { + children: SmallVec::from(children), + index, + parent, + }); + self + } + + fn remove_children(&mut self, children: &[Entity]) -> &mut Self { + let parent = self.id(); + self.commands().add(RemoveChildren { + children: SmallVec::from(children), + parent, + }); + self + } + + fn add_child(&mut self, child: Entity) -> &mut Self { + let parent = self.id(); + self.commands().add(AddChild { child, parent }); + self + } +} + +/// Struct for adding children to an entity directly through the [`World`] for use in exclusive systems +#[derive(Debug)] +pub struct WorldChildBuilder<'w> { + world: &'w mut World, + current_entity: Option, + parent_entities: Vec, +} + +impl<'w> WorldChildBuilder<'w> { + /// Spawns an entity with the given bundle and inserts it into the children defined by the [`WorldChildBuilder`] + pub fn spawn_bundle(&mut self, bundle: impl Bundle + Send + Sync + 'static) -> EntityMut<'_> { + let parent_entity = self.parent_entity(); + let entity = self + .world + .spawn() + .insert_bundle(bundle) + .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) + } + + /// Spawns an [`Entity`] with no components and inserts it into the children defined by the [`WorldChildBuilder`] which adds the [`Parent`] component to it. + 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) + } + + /// Returns the parent entity of this [`WorldChildBuilder`] + pub fn parent_entity(&self) -> Entity { + self.parent_entities + .last() + .cloned() + .expect("There should always be a parent at this point.") + } +} + +/// Trait that defines adding children to an entity directly through the [`World`] +pub trait BuildWorldChildren { + /// Creates a [`WorldChildBuilder`] with the given children built in the given closure + fn with_children(&mut self, spawn_children: impl FnOnce(&mut WorldChildBuilder)) -> &mut Self; + /// Pushes children to the back of the builder's children + fn push_children(&mut self, children: &[Entity]) -> &mut Self; + /// Inserts children at the given index + fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self; + /// Removes the given children + fn remove_children(&mut self, children: &[Entity]) -> &mut Self; +} + +impl<'w> BuildWorldChildren for EntityMut<'w> { + fn with_children(&mut self, spawn_children: impl FnOnce(&mut WorldChildBuilder)) -> &mut Self { + { + let entity = self.id(); + let mut builder = WorldChildBuilder { + current_entity: None, + parent_entities: vec![entity], + // SAFE: self.update_location() is called below. It is impossible to make EntityMut + // function calls on `self` within the scope defined here + world: unsafe { self.world_mut() }, + }; + + spawn_children(&mut builder); + } + self.update_location(); + self + } + + fn push_children(&mut self, children: &[Entity]) -> &mut Self { + let parent = self.id(); + { + // SAFE: parent entity is not modified and its location is updated manually + 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))); + } + // Inserting a bundle in the children entities may change the parent entity's location if they were of the same archetype + self.update_location(); + } + if let Some(mut children_component) = self.get_mut::() { + 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 and its location is updated manually + 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))); + } + // Inserting a bundle in the children entities may change the parent entity's location if they were of the same archetype + self.update_location(); + } + + if let Some(mut children_component) = self.get_mut::() { + children_component.0.insert_from_slice(index, children); + } else { + self.insert(Children::with(children)); + } + self + } + + fn remove_children(&mut self, children: &[Entity]) -> &mut Self { + let parent = self.id(); + // SAFE: This doesn't change the parent's location + let world = unsafe { self.world_mut() }; + for child in children.iter() { + let mut child = world.entity_mut(*child); + let mut remove_parent = false; + if let Some(child_parent) = child.get_mut::() { + if child_parent.0 == parent { + remove_parent = true; + } + } + if remove_parent { + if let Some(parent) = child.remove::() { + child.insert(PreviousParent(parent.0)); + } + } + } + // Remove the children from the parents. + if let Some(mut parent_children) = world.get_mut::(parent) { + parent_children + .0 + .retain(|parent_child| !children.contains(parent_child)); + } + self + } +} + +impl<'w> BuildWorldChildren for WorldChildBuilder<'w> { + fn with_children( + &mut self, + spawn_children: impl FnOnce(&mut WorldChildBuilder<'w>), + ) -> &mut Self { + let current_entity = self + .current_entity + .expect("Cannot add children without a parent. Try creating an entity first."); + self.parent_entities.push(current_entity); + self.current_entity = None; + + spawn_children(self); + + self.current_entity = self.parent_entities.pop(); + 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::(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::(parent) { + children_component.0.insert_from_slice(index, children); + } else { + self.world + .entity_mut(parent) + .insert(Children::with(children)); + } + self + } + + fn remove_children(&mut self, children: &[Entity]) -> &mut Self { + let parent = self + .current_entity + .expect("Cannot remove children without a parent. Try creating an entity first."); + + remove_children(parent, children, self.world); + self + } +} + +#[cfg(test)] +mod tests { + use super::{BuildChildren, BuildWorldChildren}; + use crate::prelude::{Children, Parent, PreviousParent}; + use bevy_ecs::{ + component::Component, + entity::Entity, + system::{CommandQueue, Commands}, + world::World, + }; + use smallvec::{smallvec, SmallVec}; + + #[derive(Component)] + struct C(u32); + + #[test] + fn build_children() { + let mut world = World::default(); + let mut queue = CommandQueue::default(); + let mut commands = Commands::new(&mut queue, &world); + + let mut children = Vec::new(); + let parent = commands.spawn().insert(C(1)).id(); + commands.entity(parent).with_children(|parent| { + children.push(parent.spawn().insert(C(2)).id()); + children.push(parent.spawn().insert(C(3)).id()); + children.push(parent.spawn().insert(C(4)).id()); + }); + + queue.apply(&mut world); + assert_eq!( + world.get::(parent).unwrap().0.as_slice(), + children.as_slice(), + ); + assert_eq!(*world.get::(children[0]).unwrap(), Parent(parent)); + assert_eq!(*world.get::(children[1]).unwrap(), Parent(parent)); + + assert_eq!( + *world.get::(children[0]).unwrap(), + PreviousParent(parent) + ); + assert_eq!( + *world.get::(children[1]).unwrap(), + PreviousParent(parent) + ); + } + + #[test] + fn push_and_insert_and_remove_children_commands() { + let mut world = World::default(); + + let entities = world + .spawn_batch(vec![(C(1),), (C(2),), (C(3),), (C(4),), (C(5),)]) + .collect::>(); + + let mut queue = CommandQueue::default(); + { + let mut commands = Commands::new(&mut queue, &world); + commands.entity(entities[0]).push_children(&entities[1..3]); + } + queue.apply(&mut world); + + 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::(parent).unwrap().0.clone(), + expected_children + ); + assert_eq!(*world.get::(child1).unwrap(), Parent(parent)); + assert_eq!(*world.get::(child2).unwrap(), Parent(parent)); + + assert_eq!( + *world.get::(child1).unwrap(), + PreviousParent(parent) + ); + assert_eq!( + *world.get::(child2).unwrap(), + PreviousParent(parent) + ); + + { + let mut commands = Commands::new(&mut queue, &world); + commands.entity(parent).insert_children(1, &entities[3..]); + } + queue.apply(&mut world); + + let expected_children: SmallVec<[Entity; 8]> = smallvec![child1, child3, child4, child2]; + assert_eq!( + world.get::(parent).unwrap().0.clone(), + expected_children + ); + assert_eq!(*world.get::(child3).unwrap(), Parent(parent)); + assert_eq!(*world.get::(child4).unwrap(), Parent(parent)); + assert_eq!( + *world.get::(child3).unwrap(), + PreviousParent(parent) + ); + assert_eq!( + *world.get::(child4).unwrap(), + PreviousParent(parent) + ); + + let remove_children = [child1, child4]; + { + let mut commands = Commands::new(&mut queue, &world); + commands.entity(parent).remove_children(&remove_children); + } + queue.apply(&mut world); + + let expected_children: SmallVec<[Entity; 8]> = smallvec![child3, child2]; + assert_eq!( + world.get::(parent).unwrap().0.clone(), + expected_children + ); + assert!(world.get::(child1).is_none()); + assert!(world.get::(child4).is_none()); + assert_eq!( + *world.get::(child1).unwrap(), + PreviousParent(parent) + ); + assert_eq!( + *world.get::(child4).unwrap(), + PreviousParent(parent) + ); + } + + #[test] + fn push_and_insert_and_remove_children_world() { + let mut world = World::default(); + + let entities = world + .spawn_batch(vec![(C(1),), (C(2),), (C(3),), (C(4),), (C(5),)]) + .collect::>(); + + 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::(parent).unwrap().0.clone(), + expected_children + ); + assert_eq!(*world.get::(child1).unwrap(), Parent(parent)); + assert_eq!(*world.get::(child2).unwrap(), Parent(parent)); + + assert_eq!( + *world.get::(child1).unwrap(), + PreviousParent(parent) + ); + assert_eq!( + *world.get::(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::(parent).unwrap().0.clone(), + expected_children + ); + assert_eq!(*world.get::(child3).unwrap(), Parent(parent)); + assert_eq!(*world.get::(child4).unwrap(), Parent(parent)); + assert_eq!( + *world.get::(child3).unwrap(), + PreviousParent(parent) + ); + assert_eq!( + *world.get::(child4).unwrap(), + PreviousParent(parent) + ); + + let remove_children = [child1, child4]; + world.entity_mut(parent).remove_children(&remove_children); + let expected_children: SmallVec<[Entity; 8]> = smallvec![child3, child2]; + assert_eq!( + world.get::(parent).unwrap().0.clone(), + expected_children + ); + assert!(world.get::(child1).is_none()); + assert!(world.get::(child4).is_none()); + assert_eq!( + *world.get::(child1).unwrap(), + PreviousParent(parent) + ); + assert_eq!( + *world.get::(child4).unwrap(), + PreviousParent(parent) + ); + } + + #[test] + fn regression_push_children_same_archetype() { + let mut world = World::new(); + let child = world.spawn().id(); + world.spawn().push_children(&[child]); + } +} diff --git a/crates/bevy_hierarchy/src/hierarchy/hierarchy.rs b/crates/bevy_hierarchy/src/hierarchy/hierarchy.rs new file mode 100644 index 0000000000000..0820742c34b75 --- /dev/null +++ b/crates/bevy_hierarchy/src/hierarchy/hierarchy.rs @@ -0,0 +1,203 @@ +use crate::components::{Children, Parent}; +use bevy_ecs::{ + entity::Entity, + system::{Command, EntityCommands}, + world::{EntityMut, World}, +}; +use bevy_utils::tracing::debug; + +/// Despawns the given entity and all its children recursively +#[derive(Debug)] +pub struct DespawnRecursive { + entity: Entity, +} + +/// Despawns the given entity's children recursively +#[derive(Debug)] +pub struct DespawnChildrenRecursive { + entity: Entity, +} + +/// Function for despawning an entity and all its children +pub fn despawn_with_children_recursive(world: &mut World, entity: Entity) { + // first, make the entity's own parent forget about it + if let Some(parent) = world.get::(entity).map(|parent| parent.0) { + if let Some(mut children) = world.get_mut::(parent) { + children.0.retain(|c| *c != entity); + } + } + + // then despawn the entity and all of its children + despawn_with_children_recursive_inner(world, entity); +} + +// Should only be called by `despawn_with_children_recursive`! +fn despawn_with_children_recursive_inner(world: &mut World, entity: Entity) { + if let Some(mut children) = world.get_mut::(entity) { + for e in std::mem::take(&mut children.0) { + despawn_with_children_recursive_inner(world, e); + } + } + + if !world.despawn(entity) { + debug!("Failed to despawn entity {:?}", entity); + } +} + +fn despawn_children(world: &mut World, entity: Entity) { + if let Some(mut children) = world.get_mut::(entity) { + for e in std::mem::take(&mut children.0) { + despawn_with_children_recursive_inner(world, e); + } + } +} + +impl Command for DespawnRecursive { + fn write(self, world: &mut World) { + despawn_with_children_recursive(world, self.entity); + } +} + +impl Command for DespawnChildrenRecursive { + fn write(self, world: &mut World) { + despawn_children(world, self.entity); + } +} + +/// Trait that holds functions for despawning recursively down the transform hierarchy +pub trait DespawnRecursiveExt { + /// Despawns the provided entity alongside all descendants. + fn despawn_recursive(self); + + /// Despawns all descendants of the given entity. + fn despawn_descendants(&mut self); +} + +impl<'w, 's, 'a> DespawnRecursiveExt for EntityCommands<'w, 's, 'a> { + /// Despawns the provided entity and its children. + fn despawn_recursive(mut self) { + let entity = self.id(); + self.commands().add(DespawnRecursive { entity }); + } + + fn despawn_descendants(&mut self) { + let entity = self.id(); + self.commands().add(DespawnChildrenRecursive { entity }); + } +} + +impl<'w> DespawnRecursiveExt for EntityMut<'w> { + /// Despawns the provided entity and its children. + fn despawn_recursive(mut self) { + let entity = self.id(); + // SAFE: EntityMut is consumed so even though the location is no longer + // valid, it cannot be accessed again with the invalid location. + unsafe { + despawn_with_children_recursive(self.world_mut(), entity); + } + } + + fn despawn_descendants(&mut self) { + let entity = self.id(); + // SAFE: The location is updated. + unsafe { + despawn_children(self.world_mut(), entity); + self.update_location(); + } + } +} + +#[cfg(test)] +mod tests { + use bevy_ecs::{ + component::Component, + system::{CommandQueue, Commands}, + world::World, + }; + + use super::DespawnRecursiveExt; + use crate::{components::Children, hierarchy::BuildChildren}; + + #[derive(Component, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Debug)] + struct Idx(u32); + + #[derive(Component, Clone, PartialEq, Eq, Ord, PartialOrd, Debug)] + struct N(String); + + #[test] + fn despawn_recursive() { + let mut world = World::default(); + let mut queue = CommandQueue::default(); + let grandparent_entity; + { + let mut commands = Commands::new(&mut queue, &world); + + commands + .spawn_bundle((N("Another parent".to_owned()), Idx(0))) + .with_children(|parent| { + parent.spawn_bundle((N("Another child".to_owned()), Idx(1))); + }); + + // Create a grandparent entity which will _not_ be deleted + grandparent_entity = commands + .spawn_bundle((N("Grandparent".to_owned()), Idx(2))) + .id(); + commands.entity(grandparent_entity).with_children(|parent| { + // Add a child to the grandparent (the "parent"), which will get deleted + parent + .spawn_bundle((N("Parent, to be deleted".to_owned()), Idx(3))) + // All descendents of the "parent" should also be deleted. + .with_children(|parent| { + parent + .spawn_bundle((N("First Child, to be deleted".to_owned()), Idx(4))) + .with_children(|parent| { + // child + parent.spawn_bundle(( + N("First grand child, to be deleted".to_owned()), + Idx(5), + )); + }); + parent.spawn_bundle((N("Second child, to be deleted".to_owned()), Idx(6))); + }); + }); + + commands.spawn_bundle((N("An innocent bystander".to_owned()), Idx(7))); + } + queue.apply(&mut world); + + let parent_entity = world.get::(grandparent_entity).unwrap()[0]; + + { + 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(); + } + queue.apply(&mut world); + + let mut results = world + .query::<(&N, &Idx)>() + .iter(&world) + .map(|(a, b)| (a.clone(), *b)) + .collect::>(); + results.sort_unstable_by_key(|(_, index)| *index); + + { + let children = world.get::(grandparent_entity).unwrap(); + assert!( + !children.iter().any(|&i| i == parent_entity), + "grandparent should no longer know about its child which has been removed" + ); + } + + assert_eq!( + results, + vec![ + (N("Another parent".to_owned()), Idx(0)), + (N("Another child".to_owned()), Idx(1)), + (N("Grandparent".to_owned()), Idx(2)), + (N("An innocent bystander".to_owned()), Idx(7)) + ] + ); + } +} diff --git a/crates/bevy_hierarchy/src/hierarchy/hierarchy_maintenance_system.rs b/crates/bevy_hierarchy/src/hierarchy/hierarchy_maintenance_system.rs new file mode 100644 index 0000000000000..dbbeacab12e8f --- /dev/null +++ b/crates/bevy_hierarchy/src/hierarchy/hierarchy_maintenance_system.rs @@ -0,0 +1,170 @@ +use crate::components::*; +use bevy_ecs::{ + entity::Entity, + prelude::Changed, + query::Without, + system::{Commands, Query}, +}; +use bevy_utils::HashMap; +use smallvec::SmallVec; + +/// Updates parents when the hierarchy is changed +pub fn parent_update_system( + mut commands: Commands, + removed_parent_query: Query<(Entity, &PreviousParent), Without>, + mut parent_query: Query<(Entity, &Parent, Option<&mut PreviousParent>), Changed>, + mut children_query: Query<&mut Children>, +) { + // Entities with a missing `Parent` (ie. ones that have a `PreviousParent`), remove + // them from the `Children` of the `PreviousParent`. + 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::(); + } + } + + // Tracks all newly created `Children` Components this frame. + let mut children_additions = HashMap::>::default(); + + // Entities with a changed Parent (that also have a PreviousParent, even if None) + for (entity, parent, possible_previous_parent) in parent_query.iter_mut() { + if let Some(mut previous_parent) = possible_previous_parent { + // New and previous point to the same Entity, carry on, nothing to see here. + if previous_parent.0 == parent.0 { + continue; + } + + // Remove from `PreviousParent.Children`. + if let Ok(mut previous_parent_children) = children_query.get_mut(previous_parent.0) { + (*previous_parent_children).0.retain(|e| *e != entity); + } + + // Set `PreviousParent = Parent`. + *previous_parent = PreviousParent(parent.0); + } else { + commands.entity(entity).insert(PreviousParent(parent.0)); + }; + + // Add to the parent's `Children` (either the real component, or + // `children_additions`). + if let Ok(mut new_parent_children) = children_query.get_mut(parent.0) { + // This is the parent + // PERF: Ideally we shouldn't need to check for duplicates + if !(*new_parent_children).0.contains(&entity) { + (*new_parent_children).0.push(entity); + } + } else { + // The parent doesn't have a children entity, lets add it + children_additions + .entry(parent.0) + .or_insert_with(Default::default) + .push(entity); + } + } + + // Flush the `children_additions` to the command buffer. It is stored separate to + // collect multiple new children that point to the same parent into the same + // SmallVec, and to prevent redundant add+remove operations. + children_additions.iter().for_each(|(e, v)| { + commands.entity(*e).insert(Children::with(v)); + }); +} +#[cfg(test)] +mod test { + use bevy_ecs::{ + schedule::{Schedule, Stage, SystemStage}, + system::CommandQueue, + world::World, + }; + + use super::*; + use crate::{hierarchy::BuildChildren, transform_propagate_system::transform_propagate_system}; + + #[test] + fn correct_children() { + let mut world = World::default(); + + let mut update_stage = SystemStage::parallel(); + update_stage.add_system(parent_update_system); + update_stage.add_system(transform_propagate_system); + + let mut schedule = Schedule::default(); + schedule.add_stage("update", update_stage); + + // Add parent entities + let mut command_queue = CommandQueue::default(); + let mut commands = Commands::new(&mut command_queue, &world); + 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( + 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(), + ); + }); + command_queue.apply(&mut world); + schedule.run(&mut world); + + assert_eq!( + world + .get::(parent) + .unwrap() + .0 + .iter() + .cloned() + .collect::>(), + children, + ); + + // Parent `e1` to `e2`. + (*world.get_mut::(children[0]).unwrap()).0 = children[1]; + + schedule.run(&mut world); + + assert_eq!( + world + .get::(parent) + .unwrap() + .iter() + .cloned() + .collect::>(), + vec![children[1]] + ); + + assert_eq!( + world + .get::(children[1]) + .unwrap() + .iter() + .cloned() + .collect::>(), + vec![children[0]] + ); + + assert!(world.despawn(children[0])); + + schedule.run(&mut world); + + assert_eq!( + world + .get::(parent) + .unwrap() + .iter() + .cloned() + .collect::>(), + vec![children[1]] + ); + } +} diff --git a/crates/bevy_hierarchy/src/hierarchy/mod.rs b/crates/bevy_hierarchy/src/hierarchy/mod.rs new file mode 100644 index 0000000000000..23e9108e2dec2 --- /dev/null +++ b/crates/bevy_hierarchy/src/hierarchy/mod.rs @@ -0,0 +1,8 @@ +mod child_builder; +#[allow(clippy::module_inception)] +mod hierarchy; +mod hierarchy_maintenance_system; + +pub use child_builder::*; +pub use hierarchy::*; +pub use hierarchy_maintenance_system::*; diff --git a/crates/bevy_hierarchy/src/lib.rs b/crates/bevy_hierarchy/src/lib.rs new file mode 100644 index 0000000000000..45ab1f2ab7988 --- /dev/null +++ b/crates/bevy_hierarchy/src/lib.rs @@ -0,0 +1,126 @@ +#![warn(missing_docs)] +#![doc = include_str!("../README.md")] + +/// The basic components of the transform crate +pub mod components; +/// Establishing and updating the transform hierarchy +pub mod hierarchy; +/// Propagating transform changes down the transform hierarchy +pub mod transform_propagate_system; + +#[doc(hidden)] +pub mod prelude { + #[doc(hidden)] + pub use crate::{components::*, hierarchy::*, TransformBundle, TransformPlugin}; +} + +use bevy_app::prelude::*; +use bevy_ecs::{ + bundle::Bundle, + schedule::{ParallelSystemDescriptorCoercion, SystemLabel}, +}; +use prelude::{parent_update_system, Children, GlobalTransform, Parent, PreviousParent, Transform}; + +/// A [`Bundle`] of the [`Transform`] and [`GlobalTransform`] +/// [`Component`](bevy_ecs::component::Component)s, which describe the position of an entity. +/// +/// * To place or move an entity, you should set its [`Transform`]. +/// * To get the global position of an entity, you should get its [`GlobalTransform`]. +/// * For transform hierarchies to work correctly, you must have both a [`Transform`] and a [`GlobalTransform`]. +/// * You may use the [`TransformBundle`] to guarantee this. +/// +/// ## [`Transform`] and [`GlobalTransform`] +/// +/// [`Transform`] is the position of an entity relative to its parent position, or the reference +/// frame if it doesn't have a [`Parent`](Parent). +/// +/// [`GlobalTransform`] is the position of an entity relative to the reference frame. +/// +/// [`GlobalTransform`] is updated from [`Transform`] in the system +/// [`transform_propagate_system`](crate::transform_propagate_system::transform_propagate_system). +/// +/// This system runs in stage [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate). If you +/// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag +/// before the [`GlobalTransform`] is updated. +#[derive(Bundle, Clone, Copy, Debug, Default)] +pub struct TransformBundle { + /// The transform of the entity. + pub local: Transform, + /// The global transform of the entity. + pub global: GlobalTransform, +} + +impl TransformBundle { + /// Creates a new [`TransformBundle`] from a [`Transform`]. + /// + /// This initializes [`GlobalTransform`] as identity, to be updated later by the + /// [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate) stage. + #[inline] + pub const fn from_transform(transform: Transform) -> Self { + TransformBundle { + local: transform, + // Note: `..Default::default()` cannot be used here, because it isn't const + ..Self::identity() + } + } + + /// Creates a new identity [`TransformBundle`], with no translation, rotation, and a scale of 1 + /// on all axes. + #[inline] + pub const fn identity() -> Self { + TransformBundle { + local: Transform::identity(), + global: GlobalTransform::identity(), + } + } +} + +impl From for TransformBundle { + #[inline] + fn from(transform: Transform) -> Self { + Self::from_transform(transform) + } +} +/// The base plugin for handling [`Transform`] components +#[derive(Default)] +pub struct TransformPlugin; + +/// Label enum for the types of systems relating to transform +#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)] +pub enum TransformSystem { + /// Propagates changes in transform to childrens' [`GlobalTransform`] + TransformPropagate, + /// Updates [`Parent`] when changes in the hierarchy occur + ParentUpdate, +} + +impl Plugin for TransformPlugin { + fn build(&self, app: &mut App) { + app.register_type::() + .register_type::() + .register_type::() + .register_type::() + .register_type::() + // add transform systems to startup so the first update is "correct" + .add_startup_system_to_stage( + StartupStage::PostStartup, + parent_update_system.label(TransformSystem::ParentUpdate), + ) + .add_startup_system_to_stage( + StartupStage::PostStartup, + transform_propagate_system::transform_propagate_system + .label(TransformSystem::TransformPropagate) + .after(TransformSystem::ParentUpdate), + ) + .add_system_to_stage( + CoreStage::PostUpdate, + parent_update_system.label(TransformSystem::ParentUpdate), + ) + .add_system_to_stage( + CoreStage::PostUpdate, + transform_propagate_system::transform_propagate_system + .label(TransformSystem::TransformPropagate) + .after(TransformSystem::ParentUpdate), + ); + } +} diff --git a/crates/bevy_hierarchy/src/transform_propagate_system.rs b/crates/bevy_hierarchy/src/transform_propagate_system.rs new file mode 100644 index 0000000000000..fb6ef6b1db7f8 --- /dev/null +++ b/crates/bevy_hierarchy/src/transform_propagate_system.rs @@ -0,0 +1,177 @@ +use crate::components::{Children, GlobalTransform, Parent, Transform}; +use bevy_ecs::{ + entity::Entity, + query::{Changed, With, Without}, + system::Query, +}; + +/// Update [`GlobalTransform`] component of entities based on entity hierarchy and +/// [`Transform`] component. +pub fn transform_propagate_system( + mut root_query: Query< + (Entity, Option<&Children>, &Transform, &mut GlobalTransform), + Without, + >, + mut transform_query: Query<(&Transform, &mut GlobalTransform), With>, + changed_transform_query: Query>, + children_query: Query, (With, With)>, +) { + for (entity, children, transform, mut global_transform) in root_query.iter_mut() { + let mut changed = false; + if changed_transform_query.get(entity).is_ok() { + *global_transform = GlobalTransform::from(*transform); + changed = true; + } + + if let Some(children) = children { + for child in children.0.iter() { + propagate_recursive( + &global_transform, + &changed_transform_query, + &mut transform_query, + &children_query, + *child, + changed, + ); + } + } + } +} + +fn propagate_recursive( + parent: &GlobalTransform, + changed_transform_query: &Query>, + transform_query: &mut Query<(&Transform, &mut GlobalTransform), With>, + children_query: &Query, (With, With)>, + entity: Entity, + mut changed: bool, +) { + changed |= changed_transform_query.get(entity).is_ok(); + + let global_matrix = { + if let Ok((transform, mut global_transform)) = transform_query.get_mut(entity) { + if changed { + *global_transform = parent.mul_transform(*transform); + } + *global_transform + } else { + return; + } + }; + + if let Ok(Some(children)) = children_query.get(entity) { + for child in children.0.iter() { + propagate_recursive( + &global_matrix, + changed_transform_query, + transform_query, + children_query, + *child, + changed, + ); + } + } +} + +#[cfg(test)] +mod test { + use bevy_ecs::{ + schedule::{Schedule, Stage, SystemStage}, + system::{CommandQueue, Commands}, + world::World, + }; + + use super::*; + use crate::{ + hierarchy::{parent_update_system, BuildChildren, BuildWorldChildren}, + TransformBundle, + }; + + #[test] + fn did_propagate() { + let mut world = World::default(); + + let mut update_stage = SystemStage::parallel(); + update_stage.add_system(parent_update_system); + update_stage.add_system(transform_propagate_system); + + let mut schedule = Schedule::default(); + schedule.add_stage("update", update_stage); + + // Root entity + world + .spawn() + .insert_bundle(TransformBundle::from(Transform::from_xyz(1.0, 0.0, 0.0))); + + let mut children = Vec::new(); + world + .spawn() + .insert_bundle(TransformBundle::from(Transform::from_xyz(1.0, 0.0, 0.0))) + .with_children(|parent| { + children.push( + parent + .spawn_bundle(TransformBundle::from(Transform::from_xyz(0.0, 2.0, 0.))) + .id(), + ); + children.push( + parent + .spawn_bundle(TransformBundle::from(Transform::from_xyz(0.0, 0.0, 3.))) + .id(), + ); + }); + schedule.run(&mut world); + + assert_eq!( + *world.get::(children[0]).unwrap(), + GlobalTransform::from_xyz(1.0, 0.0, 0.0) * Transform::from_xyz(0.0, 2.0, 0.0) + ); + + assert_eq!( + *world.get::(children[1]).unwrap(), + GlobalTransform::from_xyz(1.0, 0.0, 0.0) * Transform::from_xyz(0.0, 0.0, 3.0) + ); + } + + #[test] + fn did_propagate_command_buffer() { + let mut world = World::default(); + + let mut update_stage = SystemStage::parallel(); + update_stage.add_system(parent_update_system); + update_stage.add_system(transform_propagate_system); + + let mut schedule = Schedule::default(); + schedule.add_stage("update", update_stage); + + // Root entity + let mut queue = CommandQueue::default(); + let mut commands = Commands::new(&mut queue, &world); + let mut children = Vec::new(); + commands + .spawn_bundle(TransformBundle::from(Transform::from_xyz(1.0, 0.0, 0.0))) + .with_children(|parent| { + children.push( + parent + .spawn_bundle(TransformBundle::from(Transform::from_xyz(0.0, 2.0, 0.0))) + .id(), + ); + children.push( + parent + .spawn_bundle(TransformBundle::from(Transform::from_xyz(0.0, 0.0, 3.0))) + .id(), + ); + }); + queue.apply(&mut world); + schedule.run(&mut world); + + assert_eq!( + *world.get::(children[0]).unwrap(), + GlobalTransform::from_xyz(1.0, 0.0, 0.0) * Transform::from_xyz(0.0, 2.0, 0.0) + ); + + assert_eq!( + *world.get::(children[1]).unwrap(), + GlobalTransform::from_xyz(1.0, 0.0, 0.0) * Transform::from_xyz(0.0, 0.0, 3.0) + ); + } +} diff --git a/crates/bevy_transform/Cargo.toml b/crates/bevy_transform/Cargo.toml index c09078e211411..63e5641331b71 100644 --- a/crates/bevy_transform/Cargo.toml +++ b/crates/bevy_transform/Cargo.toml @@ -2,7 +2,7 @@ name = "bevy_transform" version = "0.6.0" edition = "2021" -description = "Provides hierarchy and transform functionality for Bevy Engine" +description = "Provides transform functionality for Bevy Engine" homepage = "https://bevyengine.org" repository = "https://github.com/bevyengine/bevy" license = "MIT OR Apache-2.0" From d84370327c055234de7016f67169879133a08a82 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Wed, 9 Mar 2022 22:48:30 -0500 Subject: [PATCH 02/22] Remove Transform types from bevy_hierarchy --- crates/bevy_hierarchy/Cargo.toml | 1 + .../src/components/global_transform.rs | 279 ----------------- crates/bevy_hierarchy/src/components/mod.rs | 4 - .../src/components/transform.rs | 280 ------------------ .../hierarchy/hierarchy_maintenance_system.rs | 2 + crates/bevy_hierarchy/src/lib.rs | 84 +----- .../src/transform_propagate_system.rs | 9 +- 7 files changed, 18 insertions(+), 641 deletions(-) delete mode 100644 crates/bevy_hierarchy/src/components/global_transform.rs delete mode 100644 crates/bevy_hierarchy/src/components/transform.rs diff --git a/crates/bevy_hierarchy/Cargo.toml b/crates/bevy_hierarchy/Cargo.toml index 87f4892a64fcf..541f69fdfa4e9 100644 --- a/crates/bevy_hierarchy/Cargo.toml +++ b/crates/bevy_hierarchy/Cargo.toml @@ -15,6 +15,7 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.6.0", features = ["bevy_reflect" bevy_math = { path = "../bevy_math", version = "0.6.0" } bevy_reflect = { path = "../bevy_reflect", version = "0.6.0", features = ["bevy"] } bevy_utils = { path = "../bevy_utils", version = "0.6.0" } +bevy_transform = {path = "../bevy_transform", version = "0.6.0"} # other smallvec = { version = "1.6", features = ["serde", "union", "const_generics"] } diff --git a/crates/bevy_hierarchy/src/components/global_transform.rs b/crates/bevy_hierarchy/src/components/global_transform.rs deleted file mode 100644 index 68664507d4455..0000000000000 --- a/crates/bevy_hierarchy/src/components/global_transform.rs +++ /dev/null @@ -1,279 +0,0 @@ -use super::Transform; -use bevy_ecs::{component::Component, reflect::ReflectComponent}; -use bevy_math::{const_vec3, Mat3, Mat4, Quat, Vec3}; -use bevy_reflect::Reflect; -use std::ops::Mul; - -/// Describe the position of an entity relative to the reference frame. -/// -/// * To place or move an entity, you should set its [`Transform`]. -/// * To get the global position of an entity, you should get its [`GlobalTransform`]. -/// * For transform hierarchies to work correctly, you must have both a [`Transform`] and a [`GlobalTransform`]. -/// * You may use the [`TransformBundle`](crate::TransformBundle) to guarantee this. -/// -/// ## [`Transform`] and [`GlobalTransform`] -/// -/// [`Transform`] is the position of an entity relative to its parent position, or the reference -/// frame if it doesn't have a [`Parent`](super::Parent). -/// -/// [`GlobalTransform`] is the position of an entity relative to the reference frame. -/// -/// [`GlobalTransform`] is updated from [`Transform`] in the system -/// [`transform_propagate_system`](crate::transform_propagate_system::transform_propagate_system). -/// -/// This system runs in stage [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate). If you -/// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag -/// before the [`GlobalTransform`] is updated. -#[derive(Component, Debug, PartialEq, Clone, Copy, Reflect)] -#[reflect(Component, PartialEq)] -pub struct GlobalTransform { - /// The position of the global transform - pub translation: Vec3, - /// The rotation of the global transform - pub rotation: Quat, - /// The scale of the global transform - pub scale: Vec3, -} - -impl GlobalTransform { - #[doc(hidden)] - #[inline] - pub const fn from_xyz(x: f32, y: f32, z: f32) -> Self { - Self::from_translation(const_vec3!([x, y, z])) - } - - /// Creates a new identity [`GlobalTransform`], with no translation, rotation, and a scale of 1 - /// on all axes. - #[inline] - pub const fn identity() -> Self { - GlobalTransform { - translation: Vec3::ZERO, - rotation: Quat::IDENTITY, - scale: Vec3::ONE, - } - } - - #[doc(hidden)] - #[inline] - pub fn from_matrix(matrix: Mat4) -> Self { - let (scale, rotation, translation) = matrix.to_scale_rotation_translation(); - - GlobalTransform { - translation, - rotation, - scale, - } - } - - #[doc(hidden)] - #[inline] - pub const fn from_translation(translation: Vec3) -> Self { - GlobalTransform { - translation, - ..Self::identity() - } - } - - #[doc(hidden)] - #[inline] - pub const fn from_rotation(rotation: Quat) -> Self { - GlobalTransform { - rotation, - ..Self::identity() - } - } - - #[doc(hidden)] - #[inline] - pub const fn from_scale(scale: Vec3) -> Self { - GlobalTransform { - scale, - ..Self::identity() - } - } - - #[doc(hidden)] - #[inline] - #[must_use] - pub fn looking_at(mut self, target: Vec3, up: Vec3) -> Self { - self.look_at(target, up); - self - } - - #[doc(hidden)] - #[inline] - pub const fn with_translation(mut self, translation: Vec3) -> Self { - self.translation = translation; - self - } - - #[doc(hidden)] - #[inline] - pub const fn with_rotation(mut self, rotation: Quat) -> Self { - self.rotation = rotation; - self - } - - #[doc(hidden)] - #[inline] - pub const fn with_scale(mut self, scale: Vec3) -> Self { - self.scale = scale; - self - } - - /// Returns the 3d affine transformation matrix from this transforms translation, - /// rotation, and scale. - #[inline] - pub fn compute_matrix(&self) -> Mat4 { - Mat4::from_scale_rotation_translation(self.scale, self.rotation, self.translation) - } - - /// Get the unit vector in the local x direction - #[inline] - pub fn local_x(&self) -> Vec3 { - self.rotation * Vec3::X - } - - /// Equivalent to [`-local_x()`][GlobalTransform::local_x] - #[inline] - pub fn left(&self) -> Vec3 { - -self.local_x() - } - - /// Equivalent to [`local_x()`][GlobalTransform::local_x] - #[inline] - pub fn right(&self) -> Vec3 { - self.local_x() - } - - /// Get the unit vector in the local y direction - #[inline] - pub fn local_y(&self) -> Vec3 { - self.rotation * Vec3::Y - } - - /// Equivalent to [`local_y()`][GlobalTransform::local_y] - #[inline] - pub fn up(&self) -> Vec3 { - self.local_y() - } - - /// Equivalent to [`-local_y()`][GlobalTransform::local_y] - #[inline] - pub fn down(&self) -> Vec3 { - -self.local_y() - } - - /// Get the unit vector in the local z direction - #[inline] - pub fn local_z(&self) -> Vec3 { - self.rotation * Vec3::Z - } - - /// Equivalent to [`-local_z()`][GlobalTransform::local_z] - #[inline] - pub fn forward(&self) -> Vec3 { - -self.local_z() - } - - /// Equivalent to [`local_z()`][GlobalTransform::local_z] - #[inline] - pub fn back(&self) -> Vec3 { - self.local_z() - } - - #[doc(hidden)] - #[inline] - pub fn rotate(&mut self, rotation: Quat) { - self.rotation = rotation * self.rotation; - } - - #[doc(hidden)] - #[inline] - pub fn rotate_around(&mut self, point: Vec3, rotation: Quat) { - self.translation = point + rotation * (self.translation - point); - self.rotation *= rotation; - } - - /// Multiplies `self` with `transform` component by component, returning the - /// resulting [`GlobalTransform`] - #[inline] - #[must_use] - pub fn mul_transform(&self, transform: Transform) -> Self { - let translation = self.mul_vec3(transform.translation); - let rotation = self.rotation * transform.rotation; - let scale = self.scale * transform.scale; - Self { - translation, - rotation, - scale, - } - } - - /// Returns a [`Vec3`] of this [`Transform`] applied to `value`. - #[inline] - pub fn mul_vec3(&self, mut value: Vec3) -> Vec3 { - value = self.scale * value; - value = self.rotation * value; - value += self.translation; - value - } - - #[doc(hidden)] - #[inline] - pub fn apply_non_uniform_scale(&mut self, scale: Vec3) { - self.scale *= scale; - } - - #[doc(hidden)] - #[inline] - pub fn look_at(&mut self, target: Vec3, up: Vec3) { - let forward = Vec3::normalize(self.translation - target); - let right = up.cross(forward).normalize(); - let up = forward.cross(right); - self.rotation = Quat::from_mat3(&Mat3::from_cols(right, up, forward)); - } -} - -impl Default for GlobalTransform { - fn default() -> Self { - Self::identity() - } -} - -impl From for GlobalTransform { - fn from(transform: Transform) -> Self { - Self { - translation: transform.translation, - rotation: transform.rotation, - scale: transform.scale, - } - } -} - -impl Mul for GlobalTransform { - type Output = GlobalTransform; - - #[inline] - fn mul(self, global_transform: GlobalTransform) -> Self::Output { - self.mul_transform(global_transform.into()) - } -} - -impl Mul for GlobalTransform { - type Output = GlobalTransform; - - #[inline] - fn mul(self, transform: Transform) -> Self::Output { - self.mul_transform(transform) - } -} - -impl Mul for GlobalTransform { - type Output = Vec3; - - #[inline] - fn mul(self, value: Vec3) -> Self::Output { - self.mul_vec3(value) - } -} diff --git a/crates/bevy_hierarchy/src/components/mod.rs b/crates/bevy_hierarchy/src/components/mod.rs index 67720a2b4e08e..3d6928ea3f0ae 100644 --- a/crates/bevy_hierarchy/src/components/mod.rs +++ b/crates/bevy_hierarchy/src/components/mod.rs @@ -1,9 +1,5 @@ mod children; -mod global_transform; mod parent; -mod transform; pub use children::Children; -pub use global_transform::*; pub use parent::{Parent, PreviousParent}; -pub use transform::*; diff --git a/crates/bevy_hierarchy/src/components/transform.rs b/crates/bevy_hierarchy/src/components/transform.rs deleted file mode 100644 index f0c6d536f3982..0000000000000 --- a/crates/bevy_hierarchy/src/components/transform.rs +++ /dev/null @@ -1,280 +0,0 @@ -use super::GlobalTransform; -use bevy_ecs::{component::Component, reflect::ReflectComponent}; -use bevy_math::{const_vec3, Mat3, Mat4, Quat, Vec3}; -use bevy_reflect::Reflect; -use std::ops::Mul; - -/// Describe the position of an entity. If the entity has a parent, the position is relative -/// to its parent position. -/// -/// * To place or move an entity, you should set its [`Transform`]. -/// * To get the global position of an entity, you should get its [`GlobalTransform`]. -/// * To be displayed, an entity must have both a [`Transform`] and a [`GlobalTransform`]. -/// * You may use the [`TransformBundle`](crate::TransformBundle) to guarantee this. -/// -/// ## [`Transform`] and [`GlobalTransform`] -/// -/// [`Transform`] is the position of an entity relative to its parent position, or the reference -/// frame if it doesn't have a [`Parent`](super::Parent). -/// -/// [`GlobalTransform`] is the position of an entity relative to the reference frame. -/// -/// [`GlobalTransform`] is updated from [`Transform`] in the system -/// [`transform_propagate_system`](crate::transform_propagate_system::transform_propagate_system). -/// -/// This system runs in stage [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate). If you -/// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag -/// before the [`GlobalTransform`] is updated. -#[derive(Component, Debug, PartialEq, Clone, Copy, Reflect)] -#[reflect(Component, PartialEq)] -pub struct Transform { - /// Position of the entity. In 2d, the last value of the `Vec3` is used for z-ordering. - pub translation: Vec3, - /// Rotation of the entity. - pub rotation: Quat, - /// Scale of the entity. - pub scale: Vec3, -} - -impl Transform { - /// Creates a new [`Transform`] at the position `(x, y, z)`. In 2d, the `z` component - /// is used for z-ordering elements: higher `z`-value will be in front of lower - /// `z`-value. - #[inline] - pub const fn from_xyz(x: f32, y: f32, z: f32) -> Self { - Self::from_translation(const_vec3!([x, y, z])) - } - - /// Creates a new identity [`Transform`], with no translation, rotation, and a scale of 1 on - /// all axes. - #[inline] - pub const fn identity() -> Self { - Transform { - translation: Vec3::ZERO, - rotation: Quat::IDENTITY, - scale: Vec3::ONE, - } - } - - /// Extracts the translation, rotation, and scale from `matrix`. It must be a 3d affine - /// transformation matrix. - #[inline] - pub fn from_matrix(matrix: Mat4) -> Self { - let (scale, rotation, translation) = matrix.to_scale_rotation_translation(); - - Transform { - translation, - rotation, - scale, - } - } - - /// Creates a new [`Transform`], with `translation`. Rotation will be 0 and scale 1 on - /// all axes. - #[inline] - pub const fn from_translation(translation: Vec3) -> Self { - Transform { - translation, - ..Self::identity() - } - } - - /// Creates a new [`Transform`], with `rotation`. Translation will be 0 and scale 1 on - /// all axes. - #[inline] - pub const fn from_rotation(rotation: Quat) -> Self { - Transform { - rotation, - ..Self::identity() - } - } - - /// Creates a new [`Transform`], with `scale`. Translation will be 0 and rotation 0 on - /// all axes. - #[inline] - pub const fn from_scale(scale: Vec3) -> Self { - Transform { - scale, - ..Self::identity() - } - } - - /// Updates and returns this [`Transform`] by rotating it so that its unit vector in the - /// local z direction is toward `target` and its unit vector in the local y direction - /// is toward `up`. - #[inline] - #[must_use] - pub fn looking_at(mut self, target: Vec3, up: Vec3) -> Self { - self.look_at(target, up); - self - } - - /// Returns this [`Transform`] with a new translation. - #[inline] - pub const fn with_translation(mut self, translation: Vec3) -> Self { - self.translation = translation; - self - } - - /// Returns this [`Transform`] with a new rotation. - #[inline] - pub const fn with_rotation(mut self, rotation: Quat) -> Self { - self.rotation = rotation; - self - } - - /// Returns this [`Transform`] with a new scale. - #[inline] - pub const fn with_scale(mut self, scale: Vec3) -> Self { - self.scale = scale; - self - } - - /// Returns the 3d affine transformation matrix from this transforms translation, - /// rotation, and scale. - #[inline] - pub fn compute_matrix(&self) -> Mat4 { - Mat4::from_scale_rotation_translation(self.scale, self.rotation, self.translation) - } - - /// Get the unit vector in the local x direction. - #[inline] - pub fn local_x(&self) -> Vec3 { - self.rotation * Vec3::X - } - - /// Equivalent to [`-local_x()`][Transform::local_x()] - #[inline] - pub fn left(&self) -> Vec3 { - -self.local_x() - } - - /// Equivalent to [`local_x()`][Transform::local_x()] - #[inline] - pub fn right(&self) -> Vec3 { - self.local_x() - } - - /// Get the unit vector in the local y direction. - #[inline] - pub fn local_y(&self) -> Vec3 { - self.rotation * Vec3::Y - } - - /// Equivalent to [`local_y()`][Transform::local_y] - #[inline] - pub fn up(&self) -> Vec3 { - self.local_y() - } - - /// Equivalent to [`-local_y()`][Transform::local_y] - #[inline] - pub fn down(&self) -> Vec3 { - -self.local_y() - } - - /// Get the unit vector in the local z direction. - #[inline] - pub fn local_z(&self) -> Vec3 { - self.rotation * Vec3::Z - } - - /// Equivalent to [`-local_z()`][Transform::local_z] - #[inline] - pub fn forward(&self) -> Vec3 { - -self.local_z() - } - - /// Equivalent to [`local_z()`][Transform::local_z] - #[inline] - pub fn back(&self) -> Vec3 { - self.local_z() - } - - /// Rotates the transform by the given rotation. - #[inline] - pub fn rotate(&mut self, rotation: Quat) { - self.rotation = rotation * self.rotation; - } - - /// Rotates this [`Transform`] around a point in space. - /// If the point is a zero vector, this will rotate around the parent (if any) or the origin. - #[inline] - pub fn rotate_around(&mut self, point: Vec3, rotation: Quat) { - self.translation = point + rotation * (self.translation - point); - self.rotation *= rotation; - } - - /// Multiplies `self` with `transform` component by component, returning the - /// resulting [`Transform`] - #[inline] - #[must_use] - pub fn mul_transform(&self, transform: Transform) -> Self { - let translation = self.mul_vec3(transform.translation); - let rotation = self.rotation * transform.rotation; - let scale = self.scale * transform.scale; - Transform { - translation, - rotation, - scale, - } - } - - /// Returns a [`Vec3`] of this [`Transform`] applied to `value`. - #[inline] - pub fn mul_vec3(&self, mut value: Vec3) -> Vec3 { - value = self.scale * value; - value = self.rotation * value; - value += self.translation; - value - } - - /// Changes the `scale` of this [`Transform`], multiplying the current `scale` by - /// `scale_factor`. - #[inline] - pub fn apply_non_uniform_scale(&mut self, scale_factor: Vec3) { - self.scale *= scale_factor; - } - - /// Rotates this [`Transform`] so that its local z direction is toward - /// `target` and its local y direction is toward `up`. - #[inline] - pub fn look_at(&mut self, target: Vec3, up: Vec3) { - let forward = Vec3::normalize(self.translation - target); - let right = up.cross(forward).normalize(); - let up = forward.cross(right); - self.rotation = Quat::from_mat3(&Mat3::from_cols(right, up, forward)); - } -} - -impl Default for Transform { - fn default() -> Self { - Self::identity() - } -} - -impl From for Transform { - fn from(transform: GlobalTransform) -> Self { - Self { - translation: transform.translation, - rotation: transform.rotation, - scale: transform.scale, - } - } -} - -impl Mul for Transform { - type Output = Transform; - - fn mul(self, transform: Transform) -> Self::Output { - self.mul_transform(transform) - } -} - -impl Mul for Transform { - type Output = Vec3; - - fn mul(self, value: Vec3) -> Self::Output { - self.mul_vec3(value) - } -} diff --git a/crates/bevy_hierarchy/src/hierarchy/hierarchy_maintenance_system.rs b/crates/bevy_hierarchy/src/hierarchy/hierarchy_maintenance_system.rs index dbbeacab12e8f..1e8c2f84e9ed0 100644 --- a/crates/bevy_hierarchy/src/hierarchy/hierarchy_maintenance_system.rs +++ b/crates/bevy_hierarchy/src/hierarchy/hierarchy_maintenance_system.rs @@ -78,6 +78,8 @@ mod test { world::World, }; + use bevy_transform::components::Transform; + use super::*; use crate::{hierarchy::BuildChildren, transform_propagate_system::transform_propagate_system}; diff --git a/crates/bevy_hierarchy/src/lib.rs b/crates/bevy_hierarchy/src/lib.rs index 45ab1f2ab7988..9c4e99f949215 100644 --- a/crates/bevy_hierarchy/src/lib.rs +++ b/crates/bevy_hierarchy/src/lib.rs @@ -1,7 +1,10 @@ #![warn(missing_docs)] -#![doc = include_str!("../README.md")] +//! `bevy_hierarchy` can be used to define hierarchies of entities. +//! +//! Most commonly, these hierarchies are used for inheriting [`Transform`](bevy_transform::components::Transform) values +//! from the [`Parent`] to its [`Children`]. -/// The basic components of the transform crate +/// The basic components of the hierarchy pub mod components; /// Establishing and updating the transform hierarchy pub mod hierarchy; @@ -11,79 +14,16 @@ pub mod transform_propagate_system; #[doc(hidden)] pub mod prelude { #[doc(hidden)] - pub use crate::{components::*, hierarchy::*, TransformBundle, TransformPlugin}; + pub use crate::{components::*, hierarchy::*, HierarchyPlugin}; } use bevy_app::prelude::*; -use bevy_ecs::{ - bundle::Bundle, - schedule::{ParallelSystemDescriptorCoercion, SystemLabel}, -}; -use prelude::{parent_update_system, Children, GlobalTransform, Parent, PreviousParent, Transform}; +use bevy_ecs::schedule::{ParallelSystemDescriptorCoercion, SystemLabel}; +use prelude::{parent_update_system, Children, Parent, PreviousParent}; -/// A [`Bundle`] of the [`Transform`] and [`GlobalTransform`] -/// [`Component`](bevy_ecs::component::Component)s, which describe the position of an entity. -/// -/// * To place or move an entity, you should set its [`Transform`]. -/// * To get the global position of an entity, you should get its [`GlobalTransform`]. -/// * For transform hierarchies to work correctly, you must have both a [`Transform`] and a [`GlobalTransform`]. -/// * You may use the [`TransformBundle`] to guarantee this. -/// -/// ## [`Transform`] and [`GlobalTransform`] -/// -/// [`Transform`] is the position of an entity relative to its parent position, or the reference -/// frame if it doesn't have a [`Parent`](Parent). -/// -/// [`GlobalTransform`] is the position of an entity relative to the reference frame. -/// -/// [`GlobalTransform`] is updated from [`Transform`] in the system -/// [`transform_propagate_system`](crate::transform_propagate_system::transform_propagate_system). -/// -/// This system runs in stage [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate). If you -/// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag -/// before the [`GlobalTransform`] is updated. -#[derive(Bundle, Clone, Copy, Debug, Default)] -pub struct TransformBundle { - /// The transform of the entity. - pub local: Transform, - /// The global transform of the entity. - pub global: GlobalTransform, -} - -impl TransformBundle { - /// Creates a new [`TransformBundle`] from a [`Transform`]. - /// - /// This initializes [`GlobalTransform`] as identity, to be updated later by the - /// [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate) stage. - #[inline] - pub const fn from_transform(transform: Transform) -> Self { - TransformBundle { - local: transform, - // Note: `..Default::default()` cannot be used here, because it isn't const - ..Self::identity() - } - } - - /// Creates a new identity [`TransformBundle`], with no translation, rotation, and a scale of 1 - /// on all axes. - #[inline] - pub const fn identity() -> Self { - TransformBundle { - local: Transform::identity(), - global: GlobalTransform::identity(), - } - } -} - -impl From for TransformBundle { - #[inline] - fn from(transform: Transform) -> Self { - Self::from_transform(transform) - } -} -/// The base plugin for handling [`Transform`] components +/// The base plugin for handling [`Parent`] and [`Children`] components #[derive(Default)] -pub struct TransformPlugin; +pub struct HierarchyPlugin; /// Label enum for the types of systems relating to transform #[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)] @@ -94,13 +34,11 @@ pub enum TransformSystem { ParentUpdate, } -impl Plugin for TransformPlugin { +impl Plugin for HierarchyPlugin { fn build(&self, app: &mut App) { app.register_type::() .register_type::() .register_type::() - .register_type::() - .register_type::() // add transform systems to startup so the first update is "correct" .add_startup_system_to_stage( StartupStage::PostStartup, diff --git a/crates/bevy_hierarchy/src/transform_propagate_system.rs b/crates/bevy_hierarchy/src/transform_propagate_system.rs index fb6ef6b1db7f8..40e0cf0bea8a0 100644 --- a/crates/bevy_hierarchy/src/transform_propagate_system.rs +++ b/crates/bevy_hierarchy/src/transform_propagate_system.rs @@ -1,9 +1,10 @@ -use crate::components::{Children, GlobalTransform, Parent, Transform}; +use crate::components::{Children, Parent}; use bevy_ecs::{ entity::Entity, query::{Changed, With, Without}, system::Query, }; +use bevy_transform::components::{GlobalTransform, Transform}; /// Update [`GlobalTransform`] component of entities based on entity hierarchy and /// [`Transform`] component. @@ -82,10 +83,8 @@ mod test { }; use super::*; - use crate::{ - hierarchy::{parent_update_system, BuildChildren, BuildWorldChildren}, - TransformBundle, - }; + use crate::hierarchy::{parent_update_system, BuildChildren, BuildWorldChildren}; + use bevy_transform::TransformBundle; #[test] fn did_propagate() { From 54e43f0290d001754d2c966a6b4b99a619f562ba Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Wed, 9 Mar 2022 22:50:57 -0500 Subject: [PATCH 03/22] Remove hierarchy code from bevy_transform --- .../bevy_transform/src/components/children.rs | 43 -- crates/bevy_transform/src/components/mod.rs | 4 - .../bevy_transform/src/components/parent.rs | 64 -- .../src/hierarchy/child_builder.rs | 667 ------------------ .../bevy_transform/src/hierarchy/hierarchy.rs | 203 ------ .../hierarchy/hierarchy_maintenance_system.rs | 170 ----- crates/bevy_transform/src/hierarchy/mod.rs | 8 - crates/bevy_transform/src/lib.rs | 41 +- .../src/transform_propagate_system.rs | 177 ----- 9 files changed, 5 insertions(+), 1372 deletions(-) delete mode 100644 crates/bevy_transform/src/components/children.rs delete mode 100644 crates/bevy_transform/src/components/parent.rs delete mode 100644 crates/bevy_transform/src/hierarchy/child_builder.rs delete mode 100644 crates/bevy_transform/src/hierarchy/hierarchy.rs delete mode 100644 crates/bevy_transform/src/hierarchy/hierarchy_maintenance_system.rs delete mode 100644 crates/bevy_transform/src/hierarchy/mod.rs delete mode 100644 crates/bevy_transform/src/transform_propagate_system.rs diff --git a/crates/bevy_transform/src/components/children.rs b/crates/bevy_transform/src/components/children.rs deleted file mode 100644 index 96097a1da8a59..0000000000000 --- a/crates/bevy_transform/src/components/children.rs +++ /dev/null @@ -1,43 +0,0 @@ -use bevy_ecs::{ - component::Component, - entity::{Entity, EntityMap, MapEntities, MapEntitiesError}, - reflect::{ReflectComponent, ReflectMapEntities}, -}; -use bevy_reflect::Reflect; -use smallvec::SmallVec; -use std::ops::Deref; - -/// Contains references to the child entities of this entity -#[derive(Component, Default, Clone, Debug, Reflect)] -#[reflect(Component, MapEntities)] -pub struct Children(pub(crate) SmallVec<[Entity; 8]>); - -impl MapEntities for Children { - fn map_entities(&mut self, entity_map: &EntityMap) -> Result<(), MapEntitiesError> { - for entity in self.0.iter_mut() { - *entity = entity_map.get(*entity)?; - } - - Ok(()) - } -} - -impl Children { - /// Builds and returns a [`Children`] component with the given entities - 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 = [Entity]; - - fn deref(&self) -> &Self::Target { - &self.0[..] - } -} diff --git a/crates/bevy_transform/src/components/mod.rs b/crates/bevy_transform/src/components/mod.rs index 67720a2b4e08e..10d3f72e3a463 100644 --- a/crates/bevy_transform/src/components/mod.rs +++ b/crates/bevy_transform/src/components/mod.rs @@ -1,9 +1,5 @@ -mod children; mod global_transform; -mod parent; mod transform; -pub use children::Children; pub use global_transform::*; -pub use parent::{Parent, PreviousParent}; pub use transform::*; diff --git a/crates/bevy_transform/src/components/parent.rs b/crates/bevy_transform/src/components/parent.rs deleted file mode 100644 index ddc0e2a634ee6..0000000000000 --- a/crates/bevy_transform/src/components/parent.rs +++ /dev/null @@ -1,64 +0,0 @@ -use bevy_ecs::{ - component::Component, - entity::{Entity, EntityMap, MapEntities, MapEntitiesError}, - reflect::{ReflectComponent, ReflectMapEntities}, - world::{FromWorld, World}, -}; -use bevy_reflect::Reflect; -use std::ops::{Deref, DerefMut}; - -/// Holds a reference to the parent entity of this entity. -/// This component should only be present on entities that actually have a parent entity. -#[derive(Component, Debug, Copy, Clone, Eq, PartialEq, Reflect)] -#[reflect(Component, MapEntities, PartialEq)] -pub struct Parent(pub Entity); - -// TODO: We need to impl either FromWorld or Default so Parent can be registered as Properties. -// This is because Properties deserialize by creating an instance and apply a patch on top. -// However Parent should only ever be set with a real user-defined entity. Its worth looking into -// better ways to handle cases like this. -impl FromWorld for Parent { - fn from_world(_world: &mut World) -> Self { - Parent(Entity::from_raw(u32::MAX)) - } -} - -impl MapEntities for Parent { - fn map_entities(&mut self, entity_map: &EntityMap) -> Result<(), MapEntitiesError> { - self.0 = entity_map.get(self.0)?; - Ok(()) - } -} - -impl Deref for Parent { - type Target = Entity; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for Parent { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -/// Component that holds the [`Parent`] this entity had previously -#[derive(Component, Debug, Copy, Clone, Eq, PartialEq, Reflect)] -#[reflect(Component, MapEntities, PartialEq)] -pub struct PreviousParent(pub(crate) Entity); - -impl MapEntities for PreviousParent { - fn map_entities(&mut self, entity_map: &EntityMap) -> Result<(), MapEntitiesError> { - self.0 = entity_map.get(self.0)?; - Ok(()) - } -} - -// TODO: Better handle this case see `impl FromWorld for Parent` -impl FromWorld for PreviousParent { - fn from_world(_world: &mut World) -> Self { - PreviousParent(Entity::from_raw(u32::MAX)) - } -} diff --git a/crates/bevy_transform/src/hierarchy/child_builder.rs b/crates/bevy_transform/src/hierarchy/child_builder.rs deleted file mode 100644 index 3dd47da3878a6..0000000000000 --- a/crates/bevy_transform/src/hierarchy/child_builder.rs +++ /dev/null @@ -1,667 +0,0 @@ -use crate::prelude::{Children, Parent, PreviousParent}; -use bevy_ecs::{ - bundle::Bundle, - entity::Entity, - system::{Command, Commands, EntityCommands}, - world::{EntityMut, World}, -}; -use smallvec::SmallVec; - -/// Command that adds a child to an entity -#[derive(Debug)] -pub struct AddChild { - /// Parent entity to add the child to - pub parent: Entity, - /// Child entity to add - pub child: Entity, -} - -impl Command for AddChild { - fn write(self, world: &mut World) { - world - .entity_mut(self.child) - // FIXME: don't erase the previous parent (see #1545) - .insert_bundle((Parent(self.parent), PreviousParent(self.parent))); - if let Some(mut children) = world.get_mut::(self.parent) { - children.0.push(self.child); - } else { - world - .entity_mut(self.parent) - .insert(Children(smallvec::smallvec![self.child])); - } - } -} - -/// Command that inserts a child at a given index of a parent's children, shifting following children back -#[derive(Debug)] -pub struct InsertChildren { - parent: Entity, - children: SmallVec<[Entity; 8]>, - index: usize, -} - -impl Command for InsertChildren { - fn write(self, world: &mut World) { - for child in self.children.iter() { - world - .entity_mut(*child) - // FIXME: don't erase the previous parent (see #1545) - .insert_bundle((Parent(self.parent), PreviousParent(self.parent))); - } - { - if let Some(mut children) = world.get_mut::(self.parent) { - children.0.insert_from_slice(self.index, &self.children); - } else { - world - .entity_mut(self.parent) - .insert(Children(self.children)); - } - } - } -} - -/// Command that pushes children to the end of the entity's children -#[derive(Debug)] -pub struct PushChildren { - parent: Entity, - children: SmallVec<[Entity; 8]>, -} - -impl Command for PushChildren { - fn write(self, world: &mut World) { - for child in self.children.iter() { - world - .entity_mut(*child) - // FIXME: don't erase the previous parent (see #1545) - .insert_bundle((Parent(self.parent), PreviousParent(self.parent))); - } - { - let mut added = false; - if let Some(mut children) = world.get_mut::(self.parent) { - children.0.extend(self.children.iter().cloned()); - added = true; - } - - // NOTE: ideally this is just an else statement, but currently that _incorrectly_ fails - // borrow-checking - if !added { - world - .entity_mut(self.parent) - .insert(Children(self.children)); - } - } - } -} - -/// Command that removes children from an entity, and removes that child's parent and inserts it into the previous parent component -pub struct RemoveChildren { - parent: Entity, - children: SmallVec<[Entity; 8]>, -} - -fn remove_children(parent: Entity, children: &[Entity], world: &mut World) { - for child in children.iter() { - let mut child = world.entity_mut(*child); - let mut remove_parent = false; - if let Some(child_parent) = child.get_mut::() { - if child_parent.0 == parent { - remove_parent = true; - } - } - if remove_parent { - if let Some(parent) = child.remove::() { - child.insert(PreviousParent(parent.0)); - } - } - } - // Remove the children from the parents. - if let Some(mut parent_children) = world.get_mut::(parent) { - parent_children - .0 - .retain(|parent_child| !children.contains(parent_child)); - } -} - -impl Command for RemoveChildren { - fn write(self, world: &mut World) { - // Remove any matching Parent components from the children - remove_children(self.parent, &self.children, world); - } -} - -/// Struct for building children onto an entity -pub struct ChildBuilder<'w, 's, 'a> { - commands: &'a mut Commands<'w, 's>, - push_children: PushChildren, -} - -impl<'w, 's, 'a> ChildBuilder<'w, 's, 'a> { - /// Spawns an entity with the given bundle and inserts it into the children defined by the [`ChildBuilder`] - pub fn spawn_bundle(&mut self, bundle: impl Bundle) -> EntityCommands<'w, 's, '_> { - let e = self.commands.spawn_bundle(bundle); - self.push_children.children.push(e.id()); - e - } - - /// Spawns an [`Entity`] with no components and inserts it into the children defined by the [`ChildBuilder`] which adds the [`Parent`] component to it. - pub fn spawn(&mut self) -> EntityCommands<'w, 's, '_> { - let e = self.commands.spawn(); - self.push_children.children.push(e.id()); - e - } - - /// Returns the parent entity of this [`ChildBuilder`] - pub fn parent_entity(&self) -> Entity { - self.push_children.parent - } - - /// Adds a command to this [`ChildBuilder`] - pub fn add_command(&mut self, command: C) -> &mut Self { - self.commands.add(command); - self - } -} - -/// Trait defining how to build children -pub trait BuildChildren { - /// Creates a [`ChildBuilder`] with the given children built in the given closure - fn with_children(&mut self, f: impl FnOnce(&mut ChildBuilder)) -> &mut Self; - /// Pushes children to the back of the builder's children - fn push_children(&mut self, children: &[Entity]) -> &mut Self; - /// Inserts children at the given index - fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self; - /// Removes the given children - fn remove_children(&mut self, children: &[Entity]) -> &mut Self; - /// Adds a single child - fn add_child(&mut self, child: Entity) -> &mut Self; -} - -impl<'w, 's, 'a> BuildChildren for EntityCommands<'w, 's, 'a> { - fn with_children(&mut self, spawn_children: impl FnOnce(&mut ChildBuilder)) -> &mut Self { - let parent = self.id(); - let push_children = { - let mut builder = ChildBuilder { - commands: self.commands(), - push_children: PushChildren { - children: SmallVec::default(), - parent, - }, - }; - spawn_children(&mut builder); - builder.push_children - }; - - self.commands().add(push_children); - self - } - - fn push_children(&mut self, children: &[Entity]) -> &mut Self { - let parent = self.id(); - self.commands().add(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 { - children: SmallVec::from(children), - index, - parent, - }); - self - } - - fn remove_children(&mut self, children: &[Entity]) -> &mut Self { - let parent = self.id(); - self.commands().add(RemoveChildren { - children: SmallVec::from(children), - parent, - }); - self - } - - fn add_child(&mut self, child: Entity) -> &mut Self { - let parent = self.id(); - self.commands().add(AddChild { child, parent }); - self - } -} - -/// Struct for adding children to an entity directly through the [`World`] for use in exclusive systems -#[derive(Debug)] -pub struct WorldChildBuilder<'w> { - world: &'w mut World, - current_entity: Option, - parent_entities: Vec, -} - -impl<'w> WorldChildBuilder<'w> { - /// Spawns an entity with the given bundle and inserts it into the children defined by the [`WorldChildBuilder`] - pub fn spawn_bundle(&mut self, bundle: impl Bundle + Send + Sync + 'static) -> EntityMut<'_> { - let parent_entity = self.parent_entity(); - let entity = self - .world - .spawn() - .insert_bundle(bundle) - .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) - } - - /// Spawns an [`Entity`] with no components and inserts it into the children defined by the [`WorldChildBuilder`] which adds the [`Parent`] component to it. - 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) - } - - /// Returns the parent entity of this [`WorldChildBuilder`] - pub fn parent_entity(&self) -> Entity { - self.parent_entities - .last() - .cloned() - .expect("There should always be a parent at this point.") - } -} - -/// Trait that defines adding children to an entity directly through the [`World`] -pub trait BuildWorldChildren { - /// Creates a [`WorldChildBuilder`] with the given children built in the given closure - fn with_children(&mut self, spawn_children: impl FnOnce(&mut WorldChildBuilder)) -> &mut Self; - /// Pushes children to the back of the builder's children - fn push_children(&mut self, children: &[Entity]) -> &mut Self; - /// Inserts children at the given index - fn insert_children(&mut self, index: usize, children: &[Entity]) -> &mut Self; - /// Removes the given children - fn remove_children(&mut self, children: &[Entity]) -> &mut Self; -} - -impl<'w> BuildWorldChildren for EntityMut<'w> { - fn with_children(&mut self, spawn_children: impl FnOnce(&mut WorldChildBuilder)) -> &mut Self { - { - let entity = self.id(); - let mut builder = WorldChildBuilder { - current_entity: None, - parent_entities: vec![entity], - // SAFE: self.update_location() is called below. It is impossible to make EntityMut - // function calls on `self` within the scope defined here - world: unsafe { self.world_mut() }, - }; - - spawn_children(&mut builder); - } - self.update_location(); - self - } - - fn push_children(&mut self, children: &[Entity]) -> &mut Self { - let parent = self.id(); - { - // SAFE: parent entity is not modified and its location is updated manually - 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))); - } - // Inserting a bundle in the children entities may change the parent entity's location if they were of the same archetype - self.update_location(); - } - if let Some(mut children_component) = self.get_mut::() { - 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 and its location is updated manually - 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))); - } - // Inserting a bundle in the children entities may change the parent entity's location if they were of the same archetype - self.update_location(); - } - - if let Some(mut children_component) = self.get_mut::() { - children_component.0.insert_from_slice(index, children); - } else { - self.insert(Children::with(children)); - } - self - } - - fn remove_children(&mut self, children: &[Entity]) -> &mut Self { - let parent = self.id(); - // SAFE: This doesn't change the parent's location - let world = unsafe { self.world_mut() }; - for child in children.iter() { - let mut child = world.entity_mut(*child); - let mut remove_parent = false; - if let Some(child_parent) = child.get_mut::() { - if child_parent.0 == parent { - remove_parent = true; - } - } - if remove_parent { - if let Some(parent) = child.remove::() { - child.insert(PreviousParent(parent.0)); - } - } - } - // Remove the children from the parents. - if let Some(mut parent_children) = world.get_mut::(parent) { - parent_children - .0 - .retain(|parent_child| !children.contains(parent_child)); - } - self - } -} - -impl<'w> BuildWorldChildren for WorldChildBuilder<'w> { - fn with_children( - &mut self, - spawn_children: impl FnOnce(&mut WorldChildBuilder<'w>), - ) -> &mut Self { - let current_entity = self - .current_entity - .expect("Cannot add children without a parent. Try creating an entity first."); - self.parent_entities.push(current_entity); - self.current_entity = None; - - spawn_children(self); - - self.current_entity = self.parent_entities.pop(); - 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::(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::(parent) { - children_component.0.insert_from_slice(index, children); - } else { - self.world - .entity_mut(parent) - .insert(Children::with(children)); - } - self - } - - fn remove_children(&mut self, children: &[Entity]) -> &mut Self { - let parent = self - .current_entity - .expect("Cannot remove children without a parent. Try creating an entity first."); - - remove_children(parent, children, self.world); - self - } -} - -#[cfg(test)] -mod tests { - use super::{BuildChildren, BuildWorldChildren}; - use crate::prelude::{Children, Parent, PreviousParent}; - use bevy_ecs::{ - component::Component, - entity::Entity, - system::{CommandQueue, Commands}, - world::World, - }; - use smallvec::{smallvec, SmallVec}; - - #[derive(Component)] - struct C(u32); - - #[test] - fn build_children() { - let mut world = World::default(); - let mut queue = CommandQueue::default(); - let mut commands = Commands::new(&mut queue, &world); - - let mut children = Vec::new(); - let parent = commands.spawn().insert(C(1)).id(); - commands.entity(parent).with_children(|parent| { - children.push(parent.spawn().insert(C(2)).id()); - children.push(parent.spawn().insert(C(3)).id()); - children.push(parent.spawn().insert(C(4)).id()); - }); - - queue.apply(&mut world); - assert_eq!( - world.get::(parent).unwrap().0.as_slice(), - children.as_slice(), - ); - assert_eq!(*world.get::(children[0]).unwrap(), Parent(parent)); - assert_eq!(*world.get::(children[1]).unwrap(), Parent(parent)); - - assert_eq!( - *world.get::(children[0]).unwrap(), - PreviousParent(parent) - ); - assert_eq!( - *world.get::(children[1]).unwrap(), - PreviousParent(parent) - ); - } - - #[test] - fn push_and_insert_and_remove_children_commands() { - let mut world = World::default(); - - let entities = world - .spawn_batch(vec![(C(1),), (C(2),), (C(3),), (C(4),), (C(5),)]) - .collect::>(); - - let mut queue = CommandQueue::default(); - { - let mut commands = Commands::new(&mut queue, &world); - commands.entity(entities[0]).push_children(&entities[1..3]); - } - queue.apply(&mut world); - - 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::(parent).unwrap().0.clone(), - expected_children - ); - assert_eq!(*world.get::(child1).unwrap(), Parent(parent)); - assert_eq!(*world.get::(child2).unwrap(), Parent(parent)); - - assert_eq!( - *world.get::(child1).unwrap(), - PreviousParent(parent) - ); - assert_eq!( - *world.get::(child2).unwrap(), - PreviousParent(parent) - ); - - { - let mut commands = Commands::new(&mut queue, &world); - commands.entity(parent).insert_children(1, &entities[3..]); - } - queue.apply(&mut world); - - let expected_children: SmallVec<[Entity; 8]> = smallvec![child1, child3, child4, child2]; - assert_eq!( - world.get::(parent).unwrap().0.clone(), - expected_children - ); - assert_eq!(*world.get::(child3).unwrap(), Parent(parent)); - assert_eq!(*world.get::(child4).unwrap(), Parent(parent)); - assert_eq!( - *world.get::(child3).unwrap(), - PreviousParent(parent) - ); - assert_eq!( - *world.get::(child4).unwrap(), - PreviousParent(parent) - ); - - let remove_children = [child1, child4]; - { - let mut commands = Commands::new(&mut queue, &world); - commands.entity(parent).remove_children(&remove_children); - } - queue.apply(&mut world); - - let expected_children: SmallVec<[Entity; 8]> = smallvec![child3, child2]; - assert_eq!( - world.get::(parent).unwrap().0.clone(), - expected_children - ); - assert!(world.get::(child1).is_none()); - assert!(world.get::(child4).is_none()); - assert_eq!( - *world.get::(child1).unwrap(), - PreviousParent(parent) - ); - assert_eq!( - *world.get::(child4).unwrap(), - PreviousParent(parent) - ); - } - - #[test] - fn push_and_insert_and_remove_children_world() { - let mut world = World::default(); - - let entities = world - .spawn_batch(vec![(C(1),), (C(2),), (C(3),), (C(4),), (C(5),)]) - .collect::>(); - - 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::(parent).unwrap().0.clone(), - expected_children - ); - assert_eq!(*world.get::(child1).unwrap(), Parent(parent)); - assert_eq!(*world.get::(child2).unwrap(), Parent(parent)); - - assert_eq!( - *world.get::(child1).unwrap(), - PreviousParent(parent) - ); - assert_eq!( - *world.get::(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::(parent).unwrap().0.clone(), - expected_children - ); - assert_eq!(*world.get::(child3).unwrap(), Parent(parent)); - assert_eq!(*world.get::(child4).unwrap(), Parent(parent)); - assert_eq!( - *world.get::(child3).unwrap(), - PreviousParent(parent) - ); - assert_eq!( - *world.get::(child4).unwrap(), - PreviousParent(parent) - ); - - let remove_children = [child1, child4]; - world.entity_mut(parent).remove_children(&remove_children); - let expected_children: SmallVec<[Entity; 8]> = smallvec![child3, child2]; - assert_eq!( - world.get::(parent).unwrap().0.clone(), - expected_children - ); - assert!(world.get::(child1).is_none()); - assert!(world.get::(child4).is_none()); - assert_eq!( - *world.get::(child1).unwrap(), - PreviousParent(parent) - ); - assert_eq!( - *world.get::(child4).unwrap(), - PreviousParent(parent) - ); - } - - #[test] - fn regression_push_children_same_archetype() { - let mut world = World::new(); - let child = world.spawn().id(); - world.spawn().push_children(&[child]); - } -} diff --git a/crates/bevy_transform/src/hierarchy/hierarchy.rs b/crates/bevy_transform/src/hierarchy/hierarchy.rs deleted file mode 100644 index 0820742c34b75..0000000000000 --- a/crates/bevy_transform/src/hierarchy/hierarchy.rs +++ /dev/null @@ -1,203 +0,0 @@ -use crate::components::{Children, Parent}; -use bevy_ecs::{ - entity::Entity, - system::{Command, EntityCommands}, - world::{EntityMut, World}, -}; -use bevy_utils::tracing::debug; - -/// Despawns the given entity and all its children recursively -#[derive(Debug)] -pub struct DespawnRecursive { - entity: Entity, -} - -/// Despawns the given entity's children recursively -#[derive(Debug)] -pub struct DespawnChildrenRecursive { - entity: Entity, -} - -/// Function for despawning an entity and all its children -pub fn despawn_with_children_recursive(world: &mut World, entity: Entity) { - // first, make the entity's own parent forget about it - if let Some(parent) = world.get::(entity).map(|parent| parent.0) { - if let Some(mut children) = world.get_mut::(parent) { - children.0.retain(|c| *c != entity); - } - } - - // then despawn the entity and all of its children - despawn_with_children_recursive_inner(world, entity); -} - -// Should only be called by `despawn_with_children_recursive`! -fn despawn_with_children_recursive_inner(world: &mut World, entity: Entity) { - if let Some(mut children) = world.get_mut::(entity) { - for e in std::mem::take(&mut children.0) { - despawn_with_children_recursive_inner(world, e); - } - } - - if !world.despawn(entity) { - debug!("Failed to despawn entity {:?}", entity); - } -} - -fn despawn_children(world: &mut World, entity: Entity) { - if let Some(mut children) = world.get_mut::(entity) { - for e in std::mem::take(&mut children.0) { - despawn_with_children_recursive_inner(world, e); - } - } -} - -impl Command for DespawnRecursive { - fn write(self, world: &mut World) { - despawn_with_children_recursive(world, self.entity); - } -} - -impl Command for DespawnChildrenRecursive { - fn write(self, world: &mut World) { - despawn_children(world, self.entity); - } -} - -/// Trait that holds functions for despawning recursively down the transform hierarchy -pub trait DespawnRecursiveExt { - /// Despawns the provided entity alongside all descendants. - fn despawn_recursive(self); - - /// Despawns all descendants of the given entity. - fn despawn_descendants(&mut self); -} - -impl<'w, 's, 'a> DespawnRecursiveExt for EntityCommands<'w, 's, 'a> { - /// Despawns the provided entity and its children. - fn despawn_recursive(mut self) { - let entity = self.id(); - self.commands().add(DespawnRecursive { entity }); - } - - fn despawn_descendants(&mut self) { - let entity = self.id(); - self.commands().add(DespawnChildrenRecursive { entity }); - } -} - -impl<'w> DespawnRecursiveExt for EntityMut<'w> { - /// Despawns the provided entity and its children. - fn despawn_recursive(mut self) { - let entity = self.id(); - // SAFE: EntityMut is consumed so even though the location is no longer - // valid, it cannot be accessed again with the invalid location. - unsafe { - despawn_with_children_recursive(self.world_mut(), entity); - } - } - - fn despawn_descendants(&mut self) { - let entity = self.id(); - // SAFE: The location is updated. - unsafe { - despawn_children(self.world_mut(), entity); - self.update_location(); - } - } -} - -#[cfg(test)] -mod tests { - use bevy_ecs::{ - component::Component, - system::{CommandQueue, Commands}, - world::World, - }; - - use super::DespawnRecursiveExt; - use crate::{components::Children, hierarchy::BuildChildren}; - - #[derive(Component, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Debug)] - struct Idx(u32); - - #[derive(Component, Clone, PartialEq, Eq, Ord, PartialOrd, Debug)] - struct N(String); - - #[test] - fn despawn_recursive() { - let mut world = World::default(); - let mut queue = CommandQueue::default(); - let grandparent_entity; - { - let mut commands = Commands::new(&mut queue, &world); - - commands - .spawn_bundle((N("Another parent".to_owned()), Idx(0))) - .with_children(|parent| { - parent.spawn_bundle((N("Another child".to_owned()), Idx(1))); - }); - - // Create a grandparent entity which will _not_ be deleted - grandparent_entity = commands - .spawn_bundle((N("Grandparent".to_owned()), Idx(2))) - .id(); - commands.entity(grandparent_entity).with_children(|parent| { - // Add a child to the grandparent (the "parent"), which will get deleted - parent - .spawn_bundle((N("Parent, to be deleted".to_owned()), Idx(3))) - // All descendents of the "parent" should also be deleted. - .with_children(|parent| { - parent - .spawn_bundle((N("First Child, to be deleted".to_owned()), Idx(4))) - .with_children(|parent| { - // child - parent.spawn_bundle(( - N("First grand child, to be deleted".to_owned()), - Idx(5), - )); - }); - parent.spawn_bundle((N("Second child, to be deleted".to_owned()), Idx(6))); - }); - }); - - commands.spawn_bundle((N("An innocent bystander".to_owned()), Idx(7))); - } - queue.apply(&mut world); - - let parent_entity = world.get::(grandparent_entity).unwrap()[0]; - - { - 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(); - } - queue.apply(&mut world); - - let mut results = world - .query::<(&N, &Idx)>() - .iter(&world) - .map(|(a, b)| (a.clone(), *b)) - .collect::>(); - results.sort_unstable_by_key(|(_, index)| *index); - - { - let children = world.get::(grandparent_entity).unwrap(); - assert!( - !children.iter().any(|&i| i == parent_entity), - "grandparent should no longer know about its child which has been removed" - ); - } - - assert_eq!( - results, - vec![ - (N("Another parent".to_owned()), Idx(0)), - (N("Another child".to_owned()), Idx(1)), - (N("Grandparent".to_owned()), Idx(2)), - (N("An innocent bystander".to_owned()), Idx(7)) - ] - ); - } -} diff --git a/crates/bevy_transform/src/hierarchy/hierarchy_maintenance_system.rs b/crates/bevy_transform/src/hierarchy/hierarchy_maintenance_system.rs deleted file mode 100644 index dbbeacab12e8f..0000000000000 --- a/crates/bevy_transform/src/hierarchy/hierarchy_maintenance_system.rs +++ /dev/null @@ -1,170 +0,0 @@ -use crate::components::*; -use bevy_ecs::{ - entity::Entity, - prelude::Changed, - query::Without, - system::{Commands, Query}, -}; -use bevy_utils::HashMap; -use smallvec::SmallVec; - -/// Updates parents when the hierarchy is changed -pub fn parent_update_system( - mut commands: Commands, - removed_parent_query: Query<(Entity, &PreviousParent), Without>, - mut parent_query: Query<(Entity, &Parent, Option<&mut PreviousParent>), Changed>, - mut children_query: Query<&mut Children>, -) { - // Entities with a missing `Parent` (ie. ones that have a `PreviousParent`), remove - // them from the `Children` of the `PreviousParent`. - 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::(); - } - } - - // Tracks all newly created `Children` Components this frame. - let mut children_additions = HashMap::>::default(); - - // Entities with a changed Parent (that also have a PreviousParent, even if None) - for (entity, parent, possible_previous_parent) in parent_query.iter_mut() { - if let Some(mut previous_parent) = possible_previous_parent { - // New and previous point to the same Entity, carry on, nothing to see here. - if previous_parent.0 == parent.0 { - continue; - } - - // Remove from `PreviousParent.Children`. - if let Ok(mut previous_parent_children) = children_query.get_mut(previous_parent.0) { - (*previous_parent_children).0.retain(|e| *e != entity); - } - - // Set `PreviousParent = Parent`. - *previous_parent = PreviousParent(parent.0); - } else { - commands.entity(entity).insert(PreviousParent(parent.0)); - }; - - // Add to the parent's `Children` (either the real component, or - // `children_additions`). - if let Ok(mut new_parent_children) = children_query.get_mut(parent.0) { - // This is the parent - // PERF: Ideally we shouldn't need to check for duplicates - if !(*new_parent_children).0.contains(&entity) { - (*new_parent_children).0.push(entity); - } - } else { - // The parent doesn't have a children entity, lets add it - children_additions - .entry(parent.0) - .or_insert_with(Default::default) - .push(entity); - } - } - - // Flush the `children_additions` to the command buffer. It is stored separate to - // collect multiple new children that point to the same parent into the same - // SmallVec, and to prevent redundant add+remove operations. - children_additions.iter().for_each(|(e, v)| { - commands.entity(*e).insert(Children::with(v)); - }); -} -#[cfg(test)] -mod test { - use bevy_ecs::{ - schedule::{Schedule, Stage, SystemStage}, - system::CommandQueue, - world::World, - }; - - use super::*; - use crate::{hierarchy::BuildChildren, transform_propagate_system::transform_propagate_system}; - - #[test] - fn correct_children() { - let mut world = World::default(); - - let mut update_stage = SystemStage::parallel(); - update_stage.add_system(parent_update_system); - update_stage.add_system(transform_propagate_system); - - let mut schedule = Schedule::default(); - schedule.add_stage("update", update_stage); - - // Add parent entities - let mut command_queue = CommandQueue::default(); - let mut commands = Commands::new(&mut command_queue, &world); - 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( - 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(), - ); - }); - command_queue.apply(&mut world); - schedule.run(&mut world); - - assert_eq!( - world - .get::(parent) - .unwrap() - .0 - .iter() - .cloned() - .collect::>(), - children, - ); - - // Parent `e1` to `e2`. - (*world.get_mut::(children[0]).unwrap()).0 = children[1]; - - schedule.run(&mut world); - - assert_eq!( - world - .get::(parent) - .unwrap() - .iter() - .cloned() - .collect::>(), - vec![children[1]] - ); - - assert_eq!( - world - .get::(children[1]) - .unwrap() - .iter() - .cloned() - .collect::>(), - vec![children[0]] - ); - - assert!(world.despawn(children[0])); - - schedule.run(&mut world); - - assert_eq!( - world - .get::(parent) - .unwrap() - .iter() - .cloned() - .collect::>(), - vec![children[1]] - ); - } -} diff --git a/crates/bevy_transform/src/hierarchy/mod.rs b/crates/bevy_transform/src/hierarchy/mod.rs deleted file mode 100644 index 23e9108e2dec2..0000000000000 --- a/crates/bevy_transform/src/hierarchy/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -mod child_builder; -#[allow(clippy::module_inception)] -mod hierarchy; -mod hierarchy_maintenance_system; - -pub use child_builder::*; -pub use hierarchy::*; -pub use hierarchy_maintenance_system::*; diff --git a/crates/bevy_transform/src/lib.rs b/crates/bevy_transform/src/lib.rs index 45ab1f2ab7988..ae4ca87f9b294 100644 --- a/crates/bevy_transform/src/lib.rs +++ b/crates/bevy_transform/src/lib.rs @@ -3,23 +3,16 @@ /// The basic components of the transform crate pub mod components; -/// Establishing and updating the transform hierarchy -pub mod hierarchy; -/// Propagating transform changes down the transform hierarchy -pub mod transform_propagate_system; #[doc(hidden)] pub mod prelude { #[doc(hidden)] - pub use crate::{components::*, hierarchy::*, TransformBundle, TransformPlugin}; + pub use crate::{components::*, TransformBundle, TransformPlugin}; } use bevy_app::prelude::*; -use bevy_ecs::{ - bundle::Bundle, - schedule::{ParallelSystemDescriptorCoercion, SystemLabel}, -}; -use prelude::{parent_update_system, Children, GlobalTransform, Parent, PreviousParent, Transform}; +use bevy_ecs::{bundle::Bundle, schedule::SystemLabel}; +use prelude::{GlobalTransform, Transform}; /// A [`Bundle`] of the [`Transform`] and [`GlobalTransform`] /// [`Component`](bevy_ecs::component::Component)s, which describe the position of an entity. @@ -96,31 +89,7 @@ pub enum TransformSystem { impl Plugin for TransformPlugin { fn build(&self, app: &mut App) { - app.register_type::() - .register_type::() - .register_type::() - .register_type::() - .register_type::() - // add transform systems to startup so the first update is "correct" - .add_startup_system_to_stage( - StartupStage::PostStartup, - parent_update_system.label(TransformSystem::ParentUpdate), - ) - .add_startup_system_to_stage( - StartupStage::PostStartup, - transform_propagate_system::transform_propagate_system - .label(TransformSystem::TransformPropagate) - .after(TransformSystem::ParentUpdate), - ) - .add_system_to_stage( - CoreStage::PostUpdate, - parent_update_system.label(TransformSystem::ParentUpdate), - ) - .add_system_to_stage( - CoreStage::PostUpdate, - transform_propagate_system::transform_propagate_system - .label(TransformSystem::TransformPropagate) - .after(TransformSystem::ParentUpdate), - ); + app.register_type::() + .register_type::(); } } diff --git a/crates/bevy_transform/src/transform_propagate_system.rs b/crates/bevy_transform/src/transform_propagate_system.rs deleted file mode 100644 index fb6ef6b1db7f8..0000000000000 --- a/crates/bevy_transform/src/transform_propagate_system.rs +++ /dev/null @@ -1,177 +0,0 @@ -use crate::components::{Children, GlobalTransform, Parent, Transform}; -use bevy_ecs::{ - entity::Entity, - query::{Changed, With, Without}, - system::Query, -}; - -/// Update [`GlobalTransform`] component of entities based on entity hierarchy and -/// [`Transform`] component. -pub fn transform_propagate_system( - mut root_query: Query< - (Entity, Option<&Children>, &Transform, &mut GlobalTransform), - Without, - >, - mut transform_query: Query<(&Transform, &mut GlobalTransform), With>, - changed_transform_query: Query>, - children_query: Query, (With, With)>, -) { - for (entity, children, transform, mut global_transform) in root_query.iter_mut() { - let mut changed = false; - if changed_transform_query.get(entity).is_ok() { - *global_transform = GlobalTransform::from(*transform); - changed = true; - } - - if let Some(children) = children { - for child in children.0.iter() { - propagate_recursive( - &global_transform, - &changed_transform_query, - &mut transform_query, - &children_query, - *child, - changed, - ); - } - } - } -} - -fn propagate_recursive( - parent: &GlobalTransform, - changed_transform_query: &Query>, - transform_query: &mut Query<(&Transform, &mut GlobalTransform), With>, - children_query: &Query, (With, With)>, - entity: Entity, - mut changed: bool, -) { - changed |= changed_transform_query.get(entity).is_ok(); - - let global_matrix = { - if let Ok((transform, mut global_transform)) = transform_query.get_mut(entity) { - if changed { - *global_transform = parent.mul_transform(*transform); - } - *global_transform - } else { - return; - } - }; - - if let Ok(Some(children)) = children_query.get(entity) { - for child in children.0.iter() { - propagate_recursive( - &global_matrix, - changed_transform_query, - transform_query, - children_query, - *child, - changed, - ); - } - } -} - -#[cfg(test)] -mod test { - use bevy_ecs::{ - schedule::{Schedule, Stage, SystemStage}, - system::{CommandQueue, Commands}, - world::World, - }; - - use super::*; - use crate::{ - hierarchy::{parent_update_system, BuildChildren, BuildWorldChildren}, - TransformBundle, - }; - - #[test] - fn did_propagate() { - let mut world = World::default(); - - let mut update_stage = SystemStage::parallel(); - update_stage.add_system(parent_update_system); - update_stage.add_system(transform_propagate_system); - - let mut schedule = Schedule::default(); - schedule.add_stage("update", update_stage); - - // Root entity - world - .spawn() - .insert_bundle(TransformBundle::from(Transform::from_xyz(1.0, 0.0, 0.0))); - - let mut children = Vec::new(); - world - .spawn() - .insert_bundle(TransformBundle::from(Transform::from_xyz(1.0, 0.0, 0.0))) - .with_children(|parent| { - children.push( - parent - .spawn_bundle(TransformBundle::from(Transform::from_xyz(0.0, 2.0, 0.))) - .id(), - ); - children.push( - parent - .spawn_bundle(TransformBundle::from(Transform::from_xyz(0.0, 0.0, 3.))) - .id(), - ); - }); - schedule.run(&mut world); - - assert_eq!( - *world.get::(children[0]).unwrap(), - GlobalTransform::from_xyz(1.0, 0.0, 0.0) * Transform::from_xyz(0.0, 2.0, 0.0) - ); - - assert_eq!( - *world.get::(children[1]).unwrap(), - GlobalTransform::from_xyz(1.0, 0.0, 0.0) * Transform::from_xyz(0.0, 0.0, 3.0) - ); - } - - #[test] - fn did_propagate_command_buffer() { - let mut world = World::default(); - - let mut update_stage = SystemStage::parallel(); - update_stage.add_system(parent_update_system); - update_stage.add_system(transform_propagate_system); - - let mut schedule = Schedule::default(); - schedule.add_stage("update", update_stage); - - // Root entity - let mut queue = CommandQueue::default(); - let mut commands = Commands::new(&mut queue, &world); - let mut children = Vec::new(); - commands - .spawn_bundle(TransformBundle::from(Transform::from_xyz(1.0, 0.0, 0.0))) - .with_children(|parent| { - children.push( - parent - .spawn_bundle(TransformBundle::from(Transform::from_xyz(0.0, 2.0, 0.0))) - .id(), - ); - children.push( - parent - .spawn_bundle(TransformBundle::from(Transform::from_xyz(0.0, 0.0, 3.0))) - .id(), - ); - }); - queue.apply(&mut world); - schedule.run(&mut world); - - assert_eq!( - *world.get::(children[0]).unwrap(), - GlobalTransform::from_xyz(1.0, 0.0, 0.0) * Transform::from_xyz(0.0, 2.0, 0.0) - ); - - assert_eq!( - *world.get::(children[1]).unwrap(), - GlobalTransform::from_xyz(1.0, 0.0, 0.0) * Transform::from_xyz(0.0, 0.0, 3.0) - ); - } -} From b1c51a5e4c74fd27dd628ecd1b5f1a8e4229298f Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Wed, 9 Mar 2022 22:56:43 -0500 Subject: [PATCH 04/22] Fix imports --- crates/bevy_gltf/Cargo.toml | 1 + crates/bevy_gltf/src/loader.rs | 8 +++----- crates/bevy_scene/Cargo.toml | 2 +- crates/bevy_scene/src/command.rs | 2 +- crates/bevy_scene/src/scene_spawner.rs | 2 +- crates/bevy_ui/Cargo.toml | 1 + crates/bevy_ui/src/flex/mod.rs | 3 ++- crates/bevy_ui/src/update.rs | 9 ++++----- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/crates/bevy_gltf/Cargo.toml b/crates/bevy_gltf/Cargo.toml index 79d05e0708c21..4d9e96ab3c71c 100644 --- a/crates/bevy_gltf/Cargo.toml +++ b/crates/bevy_gltf/Cargo.toml @@ -14,6 +14,7 @@ bevy_app = { path = "../bevy_app", version = "0.6.0" } bevy_asset = { path = "../bevy_asset", version = "0.6.0" } bevy_core = { path = "../bevy_core", version = "0.6.0" } bevy_ecs = { path = "../bevy_ecs", version = "0.6.0" } +bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.6.0" } bevy_pbr = { path = "../bevy_pbr", version = "0.6.0" } bevy_reflect = { path = "../bevy_reflect", version = "0.6.0", features = ["bevy"] } bevy_render = { path = "../bevy_render", version = "0.6.0" } diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index 293e4bece8dd1..c5de4df613db1 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -4,6 +4,7 @@ use bevy_asset::{ }; use bevy_core::Name; use bevy_ecs::world::World; +use bevy_hierarchy::hierarchy::{BuildWorldChildren, WorldChildBuilder}; use bevy_log::warn; use bevy_math::{Mat4, Vec3}; use bevy_pbr::{ @@ -24,11 +25,8 @@ use bevy_render::{ view::VisibleEntities, }; use bevy_scene::Scene; -use bevy_transform::{ - hierarchy::{BuildWorldChildren, WorldChildBuilder}, - prelude::Transform, - TransformBundle, -}; +use bevy_transform::{components::Transform, TransformBundle}; + use bevy_utils::{HashMap, HashSet}; use gltf::{ mesh::Mode, diff --git a/crates/bevy_scene/Cargo.toml b/crates/bevy_scene/Cargo.toml index adecdd8f76cb4..e63d7db638a2a 100644 --- a/crates/bevy_scene/Cargo.toml +++ b/crates/bevy_scene/Cargo.toml @@ -14,7 +14,7 @@ bevy_app = { path = "../bevy_app", version = "0.6.0" } bevy_asset = { path = "../bevy_asset", version = "0.6.0" } bevy_ecs = { path = "../bevy_ecs", version = "0.6.0" } bevy_reflect = { path = "../bevy_reflect", version = "0.6.0", features = ["bevy"] } -bevy_transform = { path = "../bevy_transform", version = "0.6.0" } +bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.6.0" } bevy_utils = { path = "../bevy_utils", version = "0.6.0" } # other diff --git a/crates/bevy_scene/src/command.rs b/crates/bevy_scene/src/command.rs index 0bed5edf17e51..a8d9d474eba5e 100644 --- a/crates/bevy_scene/src/command.rs +++ b/crates/bevy_scene/src/command.rs @@ -4,7 +4,7 @@ use bevy_ecs::{ system::{Command, Commands}, world::World, }; -use bevy_transform::hierarchy::ChildBuilder; +use bevy_hierarchy::hierarchy::ChildBuilder; use crate::{Scene, SceneSpawner}; diff --git a/crates/bevy_scene/src/scene_spawner.rs b/crates/bevy_scene/src/scene_spawner.rs index fdaedcead32fa..df2d87154ad60 100644 --- a/crates/bevy_scene/src/scene_spawner.rs +++ b/crates/bevy_scene/src/scene_spawner.rs @@ -7,8 +7,8 @@ use bevy_ecs::{ system::Command, world::{Mut, World}, }; +use bevy_hierarchy::{hierarchy::AddChild, prelude::Parent}; use bevy_reflect::TypeRegistryArc; -use bevy_transform::{hierarchy::AddChild, prelude::Parent}; use bevy_utils::{tracing::error, HashMap}; use thiserror::Error; use uuid::Uuid; diff --git a/crates/bevy_ui/Cargo.toml b/crates/bevy_ui/Cargo.toml index 6954fa9d1be48..4a7fce13a4aaa 100644 --- a/crates/bevy_ui/Cargo.toml +++ b/crates/bevy_ui/Cargo.toml @@ -16,6 +16,7 @@ bevy_core = { path = "../bevy_core", version = "0.6.0" } bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.6.0" } bevy_derive = { path = "../bevy_derive", version = "0.6.0" } bevy_ecs = { path = "../bevy_ecs", version = "0.6.0" } +bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.6.0" } bevy_input = { path = "../bevy_input", version = "0.6.0" } bevy_log = { path = "../bevy_log", version = "0.6.0" } bevy_math = { path = "../bevy_math", version = "0.6.0" } diff --git a/crates/bevy_ui/src/flex/mod.rs b/crates/bevy_ui/src/flex/mod.rs index cda1167e7446c..3222427f7a8f2 100644 --- a/crates/bevy_ui/src/flex/mod.rs +++ b/crates/bevy_ui/src/flex/mod.rs @@ -7,9 +7,10 @@ use bevy_ecs::{ query::{Changed, FilterFetch, With, Without, WorldQuery}, system::{Query, Res, ResMut}, }; +use bevy_hierarchy::components::{Children, Parent}; use bevy_log::warn; use bevy_math::Vec2; -use bevy_transform::prelude::{Children, Parent, Transform}; +use bevy_transform::components::Transform; use bevy_utils::HashMap; use bevy_window::{Window, WindowId, WindowScaleFactorChanged, Windows}; use std::fmt; diff --git a/crates/bevy_ui/src/update.rs b/crates/bevy_ui/src/update.rs index 9fe53009b93a0..7a3bb91d663fb 100644 --- a/crates/bevy_ui/src/update.rs +++ b/crates/bevy_ui/src/update.rs @@ -8,12 +8,10 @@ use bevy_ecs::{ query::{With, Without}, system::{Commands, Query}, }; +use bevy_hierarchy::components::{Children, Parent}; use bevy_math::Vec2; use bevy_sprite::Rect; -use bevy_transform::{ - components::GlobalTransform, - prelude::{Children, Parent, Transform}, -}; +use bevy_transform::components::{GlobalTransform, Transform}; /// The resolution of Z values for UI pub const UI_Z_STEP: f32 = 0.001; @@ -141,7 +139,8 @@ mod tests { system::{CommandQueue, Commands}, world::World, }; - use bevy_transform::{components::Transform, hierarchy::BuildChildren}; + use bevy_hierarchy::hierarchy::BuildChildren; + use bevy_transform::components::Transform; use crate::Node; From a258ef9c6df7e52217cffa749cd16b0726c1ae27 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Wed, 9 Mar 2022 22:56:56 -0500 Subject: [PATCH 05/22] Add `HierarchyPlugin` to `DefaultPlugins` --- crates/bevy_internal/src/default_plugins.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/bevy_internal/src/default_plugins.rs b/crates/bevy_internal/src/default_plugins.rs index 76ccb2954c4be..d4badf887d49c 100644 --- a/crates/bevy_internal/src/default_plugins.rs +++ b/crates/bevy_internal/src/default_plugins.rs @@ -4,6 +4,7 @@ use bevy_app::{PluginGroup, PluginGroupBuilder}; /// * [`LogPlugin`](bevy_log::LogPlugin) /// * [`CorePlugin`](bevy_core::CorePlugin) /// * [`TransformPlugin`](bevy_transform::TransformPlugin) +/// * [`HierarchyPlugin`](bevy_hierarchy::HierarchyPlugin) /// * [`DiagnosticsPlugin`](bevy_diagnostic::DiagnosticsPlugin) /// * [`InputPlugin`](bevy_input::InputPlugin) /// * [`WindowPlugin`](bevy_window::WindowPlugin) @@ -27,6 +28,7 @@ impl PluginGroup for DefaultPlugins { group.add(bevy_log::LogPlugin::default()); group.add(bevy_core::CorePlugin::default()); group.add(bevy_transform::TransformPlugin::default()); + group.add(bevy_hierarchy::HierarchyPlugin::default()); group.add(bevy_diagnostic::DiagnosticsPlugin::default()); group.add(bevy_input::InputPlugin::default()); group.add(bevy_window::WindowPlugin::default()); From 58de51de2d3e75e3c199a54f64fb695a25c4e718 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Wed, 9 Mar 2022 23:02:06 -0500 Subject: [PATCH 06/22] Fix missing import --- crates/bevy_internal/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index 36642c9bc652c..4b9891f3ff065 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -56,6 +56,7 @@ bevy_core = { path = "../bevy_core", version = "0.6.0" } bevy_derive = { path = "../bevy_derive", version = "0.6.0" } bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.6.0" } bevy_ecs = { path = "../bevy_ecs", version = "0.6.0" } +bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.6.0" } bevy_input = { path = "../bevy_input", version = "0.6.0" } bevy_log = { path = "../bevy_log", version = "0.6.0" } bevy_math = { path = "../bevy_math", version = "0.6.0" } From 71382165fb0b1080909c8a3b7d55adee0c92f1ba Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Wed, 9 Mar 2022 23:05:19 -0500 Subject: [PATCH 07/22] Export bevy_hierarchy prelude in bevy::prelude --- crates/bevy_internal/src/lib.rs | 5 +++++ crates/bevy_internal/src/prelude.rs | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/crates/bevy_internal/src/lib.rs b/crates/bevy_internal/src/lib.rs index 3df3d0c2c9ec7..bf65182c7f662 100644 --- a/crates/bevy_internal/src/lib.rs +++ b/crates/bevy_internal/src/lib.rs @@ -65,6 +65,11 @@ pub mod tasks { pub use bevy_tasks::*; } +pub mod hierarchy { + //! Entity hierarchies and property inheritance + pub use bevy_hierarchy::*; +} + pub mod transform { //! Local and global transforms (e.g. translation, scale, rotation). pub use bevy_transform::*; diff --git a/crates/bevy_internal/src/prelude.rs b/crates/bevy_internal/src/prelude.rs index 7bd1170c05ef6..148d245beed45 100644 --- a/crates/bevy_internal/src/prelude.rs +++ b/crates/bevy_internal/src/prelude.rs @@ -1,7 +1,7 @@ #[doc(hidden)] pub use crate::{ - app::prelude::*, asset::prelude::*, core::prelude::*, ecs::prelude::*, input::prelude::*, - log::prelude::*, math::prelude::*, reflect::prelude::*, scene::prelude::*, + app::prelude::*, asset::prelude::*, core::prelude::*, ecs::prelude::*, hierarchy::prelude::*, + input::prelude::*, log::prelude::*, math::prelude::*, reflect::prelude::*, scene::prelude::*, transform::prelude::*, utils::prelude::*, window::prelude::*, DefaultPlugins, MinimalPlugins, }; From de8786de5be723de7a62880cb1ffcc57bf41f597 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Wed, 9 Mar 2022 23:46:42 -0500 Subject: [PATCH 08/22] System labels belong to bevy_hierarchy --- crates/bevy_hierarchy/src/lib.rs | 14 +++++++------- crates/bevy_render/Cargo.toml | 1 + crates/bevy_render/src/view/visibility/mod.rs | 9 +++++---- crates/bevy_transform/src/lib.rs | 9 --------- 4 files changed, 13 insertions(+), 20 deletions(-) diff --git a/crates/bevy_hierarchy/src/lib.rs b/crates/bevy_hierarchy/src/lib.rs index 9c4e99f949215..3808a54a2ba7f 100644 --- a/crates/bevy_hierarchy/src/lib.rs +++ b/crates/bevy_hierarchy/src/lib.rs @@ -27,7 +27,7 @@ pub struct HierarchyPlugin; /// Label enum for the types of systems relating to transform #[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)] -pub enum TransformSystem { +pub enum HierarchySystem { /// Propagates changes in transform to childrens' [`GlobalTransform`] TransformPropagate, /// Updates [`Parent`] when changes in the hierarchy occur @@ -42,23 +42,23 @@ impl Plugin for HierarchyPlugin { // add transform systems to startup so the first update is "correct" .add_startup_system_to_stage( StartupStage::PostStartup, - parent_update_system.label(TransformSystem::ParentUpdate), + parent_update_system.label(HierarchySystem::ParentUpdate), ) .add_startup_system_to_stage( StartupStage::PostStartup, transform_propagate_system::transform_propagate_system - .label(TransformSystem::TransformPropagate) - .after(TransformSystem::ParentUpdate), + .label(HierarchySystem::TransformPropagate) + .after(HierarchySystem::ParentUpdate), ) .add_system_to_stage( CoreStage::PostUpdate, - parent_update_system.label(TransformSystem::ParentUpdate), + parent_update_system.label(HierarchySystem::ParentUpdate), ) .add_system_to_stage( CoreStage::PostUpdate, transform_propagate_system::transform_propagate_system - .label(TransformSystem::TransformPropagate) - .after(TransformSystem::ParentUpdate), + .label(HierarchySystem::TransformPropagate) + .after(HierarchySystem::ParentUpdate), ); } } diff --git a/crates/bevy_render/Cargo.toml b/crates/bevy_render/Cargo.toml index 49b3db948ad20..7d10f08965184 100644 --- a/crates/bevy_render/Cargo.toml +++ b/crates/bevy_render/Cargo.toml @@ -28,6 +28,7 @@ bevy_core = { path = "../bevy_core", version = "0.6.0" } bevy_crevice = { path = "../bevy_crevice", version = "0.6.0", features = ["glam"] } bevy_derive = { path = "../bevy_derive", version = "0.6.0" } bevy_ecs = { path = "../bevy_ecs", version = "0.6.0" } +bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.6.0" } bevy_math = { path = "../bevy_math", version = "0.6.0" } bevy_reflect = { path = "../bevy_reflect", version = "0.6.0", features = ["bevy"] } bevy_transform = { path = "../bevy_transform", version = "0.6.0" } diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index cec6525d1acf2..bb8d8dbde37bf 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -5,8 +5,9 @@ pub use render_layers::*; use bevy_app::{CoreStage, Plugin}; use bevy_asset::{Assets, Handle}; use bevy_ecs::prelude::*; +use bevy_hierarchy::HierarchySystem; use bevy_reflect::Reflect; -use bevy_transform::{components::GlobalTransform, TransformSystem}; +use bevy_transform::components::GlobalTransform; use crate::{ camera::{Camera, CameraProjection, OrthographicProjection, PerspectiveProjection}, @@ -87,13 +88,13 @@ impl Plugin for VisibilityPlugin { CoreStage::PostUpdate, update_frusta:: .label(UpdateOrthographicFrusta) - .after(TransformSystem::TransformPropagate), + .after(HierarchySystem::TransformPropagate), ) .add_system_to_stage( CoreStage::PostUpdate, update_frusta:: .label(UpdatePerspectiveFrusta) - .after(TransformSystem::TransformPropagate), + .after(HierarchySystem::TransformPropagate), ) .add_system_to_stage( CoreStage::PostUpdate, @@ -102,7 +103,7 @@ impl Plugin for VisibilityPlugin { .after(CalculateBounds) .after(UpdateOrthographicFrusta) .after(UpdatePerspectiveFrusta) - .after(TransformSystem::TransformPropagate), + .after(HierarchySystem::TransformPropagate), ); } } diff --git a/crates/bevy_transform/src/lib.rs b/crates/bevy_transform/src/lib.rs index ae4ca87f9b294..bd35220a35100 100644 --- a/crates/bevy_transform/src/lib.rs +++ b/crates/bevy_transform/src/lib.rs @@ -78,15 +78,6 @@ impl From for TransformBundle { #[derive(Default)] pub struct TransformPlugin; -/// Label enum for the types of systems relating to transform -#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)] -pub enum TransformSystem { - /// Propagates changes in transform to childrens' [`GlobalTransform`] - TransformPropagate, - /// Updates [`Parent`] when changes in the hierarchy occur - ParentUpdate, -} - impl Plugin for TransformPlugin { fn build(&self, app: &mut App) { app.register_type::() From 9eba2802129a47fe11087d31c6126a4cf005dd58 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Wed, 9 Mar 2022 23:47:25 -0500 Subject: [PATCH 09/22] Fix broken doc links Cannot link fully because bevy_hierarchy is not a dependency :( --- crates/bevy_transform/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_transform/src/lib.rs b/crates/bevy_transform/src/lib.rs index bd35220a35100..bcfe6519d179f 100644 --- a/crates/bevy_transform/src/lib.rs +++ b/crates/bevy_transform/src/lib.rs @@ -11,7 +11,7 @@ pub mod prelude { } use bevy_app::prelude::*; -use bevy_ecs::{bundle::Bundle, schedule::SystemLabel}; +use bevy_ecs::bundle::Bundle; use prelude::{GlobalTransform, Transform}; /// A [`Bundle`] of the [`Transform`] and [`GlobalTransform`] @@ -25,12 +25,12 @@ use prelude::{GlobalTransform, Transform}; /// ## [`Transform`] and [`GlobalTransform`] /// /// [`Transform`] is the position of an entity relative to its parent position, or the reference -/// frame if it doesn't have a [`Parent`](Parent). +/// frame if it doesn't have a parent. /// /// [`GlobalTransform`] is the position of an entity relative to the reference frame. /// /// [`GlobalTransform`] is updated from [`Transform`] in the system -/// [`transform_propagate_system`](crate::transform_propagate_system::transform_propagate_system). +/// `transform_propagate_system`. /// /// This system runs in stage [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate). If you /// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag From 8559e58f3b26799d0ad0031294690feed9fb407b Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Thu, 10 Mar 2022 11:20:59 -0500 Subject: [PATCH 10/22] Fix label imports --- crates/bevy_pbr/Cargo.toml | 1 + crates/bevy_pbr/src/lib.rs | 10 +++++----- crates/bevy_ui/src/lib.rs | 8 ++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/crates/bevy_pbr/Cargo.toml b/crates/bevy_pbr/Cargo.toml index 4790bb75ab7c8..25f8dfc32a710 100644 --- a/crates/bevy_pbr/Cargo.toml +++ b/crates/bevy_pbr/Cargo.toml @@ -18,6 +18,7 @@ bevy_asset = { path = "../bevy_asset", version = "0.6.0" } bevy_core = { path = "../bevy_core", version = "0.6.0" } bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.6.0" } bevy_ecs = { path = "../bevy_ecs", version = "0.6.0" } +bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.6.0" } bevy_math = { path = "../bevy_math", version = "0.6.0" } bevy_reflect = { path = "../bevy_reflect", version = "0.6.0", features = ["bevy"] } bevy_render = { path = "../bevy_render", version = "0.6.0" } diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 94234fc73388e..15e71a1383de4 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -35,6 +35,7 @@ pub mod draw_3d_graph { use bevy_app::prelude::*; use bevy_asset::{load_internal_asset, Assets, Handle, HandleUntyped}; use bevy_ecs::prelude::*; +use bevy_hierarchy::HierarchySystem; use bevy_reflect::TypeUuid; use bevy_render::{ prelude::Color, @@ -44,7 +45,6 @@ use bevy_render::{ view::VisibilitySystems, RenderApp, RenderStage, }; -use bevy_transform::TransformSystem; pub const PBR_SHADER_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 4805239651767701046); @@ -86,26 +86,26 @@ impl Plugin for PbrPlugin { CoreStage::PostUpdate, assign_lights_to_clusters .label(SimulationLightSystems::AssignLightsToClusters) - .after(TransformSystem::TransformPropagate), + .after(HierarchySystem::TransformPropagate), ) .add_system_to_stage( CoreStage::PostUpdate, update_directional_light_frusta .label(SimulationLightSystems::UpdateDirectionalLightFrusta) - .after(TransformSystem::TransformPropagate), + .after(HierarchySystem::TransformPropagate), ) .add_system_to_stage( CoreStage::PostUpdate, update_point_light_frusta .label(SimulationLightSystems::UpdatePointLightFrusta) - .after(TransformSystem::TransformPropagate) + .after(HierarchySystem::TransformPropagate) .after(SimulationLightSystems::AssignLightsToClusters), ) .add_system_to_stage( CoreStage::PostUpdate, check_light_mesh_visibility .label(SimulationLightSystems::CheckLightVisibility) - .after(TransformSystem::TransformPropagate) + .after(HierarchySystem::TransformPropagate) .after(VisibilitySystems::CalculateBounds) .after(SimulationLightSystems::UpdateDirectionalLightFrusta) .after(SimulationLightSystems::UpdatePointLightFrusta) diff --git a/crates/bevy_ui/src/lib.rs b/crates/bevy_ui/src/lib.rs index 2a44323966a3d..8e2a28f933e92 100644 --- a/crates/bevy_ui/src/lib.rs +++ b/crates/bevy_ui/src/lib.rs @@ -27,9 +27,9 @@ pub mod prelude { use bevy_app::prelude::*; use bevy_ecs::schedule::{ParallelSystemDescriptorCoercion, SystemLabel}; +use bevy_hierarchy::HierarchySystem; use bevy_input::InputSystem; use bevy_math::{Rect, Size}; -use bevy_transform::TransformSystem; use update::{ui_z_system, update_clipping_system}; use crate::prelude::CameraUi; @@ -93,17 +93,17 @@ impl Plugin for UiPlugin { CoreStage::PostUpdate, flex_node_system .label(UiSystem::Flex) - .before(TransformSystem::TransformPropagate), + .before(HierarchySystem::TransformPropagate), ) .add_system_to_stage( CoreStage::PostUpdate, ui_z_system .after(UiSystem::Flex) - .before(TransformSystem::TransformPropagate), + .before(HierarchySystem::TransformPropagate), ) .add_system_to_stage( CoreStage::PostUpdate, - update_clipping_system.after(TransformSystem::TransformPropagate), + update_clipping_system.after(HierarchySystem::TransformPropagate), ); crate::render::build_ui_render(app); From 0484273398e8a93dc80570235aaee744d3372f9d Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Thu, 10 Mar 2022 11:43:51 -0500 Subject: [PATCH 11/22] Remove broken doc links --- crates/bevy_transform/src/components/global_transform.rs | 4 ++-- crates/bevy_transform/src/components/transform.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_transform/src/components/global_transform.rs b/crates/bevy_transform/src/components/global_transform.rs index 68664507d4455..efa01262da85d 100644 --- a/crates/bevy_transform/src/components/global_transform.rs +++ b/crates/bevy_transform/src/components/global_transform.rs @@ -14,12 +14,12 @@ use std::ops::Mul; /// ## [`Transform`] and [`GlobalTransform`] /// /// [`Transform`] is the position of an entity relative to its parent position, or the reference -/// frame if it doesn't have a [`Parent`](super::Parent). +/// frame if it doesn't have a `Parent`. /// /// [`GlobalTransform`] is the position of an entity relative to the reference frame. /// /// [`GlobalTransform`] is updated from [`Transform`] in the system -/// [`transform_propagate_system`](crate::transform_propagate_system::transform_propagate_system). +/// `transform_propagate_system`. /// /// This system runs in stage [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate). If you /// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag diff --git a/crates/bevy_transform/src/components/transform.rs b/crates/bevy_transform/src/components/transform.rs index f0c6d536f3982..9aabbde081f97 100644 --- a/crates/bevy_transform/src/components/transform.rs +++ b/crates/bevy_transform/src/components/transform.rs @@ -15,12 +15,12 @@ use std::ops::Mul; /// ## [`Transform`] and [`GlobalTransform`] /// /// [`Transform`] is the position of an entity relative to its parent position, or the reference -/// frame if it doesn't have a [`Parent`](super::Parent). +/// frame if it doesn't have a `Parent`. /// /// [`GlobalTransform`] is the position of an entity relative to the reference frame. /// /// [`GlobalTransform`] is updated from [`Transform`] in the system -/// [`transform_propagate_system`](crate::transform_propagate_system::transform_propagate_system). +/// `transform_propagate_system`. /// /// This system runs in stage [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate). If you /// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag From c1f279b69c07a209ba1360f11d1571be9d0fc275 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Thu, 10 Mar 2022 12:25:21 -0500 Subject: [PATCH 12/22] Fix broken doc link --- crates/bevy_hierarchy/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_hierarchy/src/lib.rs b/crates/bevy_hierarchy/src/lib.rs index 3808a54a2ba7f..5407bc0b6315b 100644 --- a/crates/bevy_hierarchy/src/lib.rs +++ b/crates/bevy_hierarchy/src/lib.rs @@ -28,7 +28,7 @@ pub struct HierarchyPlugin; /// Label enum for the types of systems relating to transform #[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)] pub enum HierarchySystem { - /// Propagates changes in transform to childrens' [`GlobalTransform`] + /// Propagates changes in transform to childrens' [`GlobalTransform`](bevy_transform::components::GlobalTransform) TransformPropagate, /// Updates [`Parent`] when changes in the hierarchy occur ParentUpdate, From e65f14fdd92ebf71447d183a3e91dfd41b4b7635 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Fri, 11 Mar 2022 13:20:58 -0500 Subject: [PATCH 13/22] Remove redundant .gitignore files --- crates/bevy_hierarchy/.gitignore | 24 ------------------------ crates/bevy_transform/.gitignore | 24 ------------------------ 2 files changed, 48 deletions(-) delete mode 100644 crates/bevy_hierarchy/.gitignore delete mode 100644 crates/bevy_transform/.gitignore diff --git a/crates/bevy_hierarchy/.gitignore b/crates/bevy_hierarchy/.gitignore deleted file mode 100644 index af368c3d50227..0000000000000 --- a/crates/bevy_hierarchy/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -book/book -target -Cargo.lock -*.log - -# Backup files -.DS_Store -thumbs.db -*~ -*.rs.bk -*.swp - -# IDE / Editor files -*.iml -.idea -.vscode - - -#Added by cargo -# -#already existing elements are commented out - -/target -**/*.rs.bk diff --git a/crates/bevy_transform/.gitignore b/crates/bevy_transform/.gitignore deleted file mode 100644 index af368c3d50227..0000000000000 --- a/crates/bevy_transform/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -book/book -target -Cargo.lock -*.log - -# Backup files -.DS_Store -thumbs.db -*~ -*.rs.bk -*.swp - -# IDE / Editor files -*.iml -.idea -.vscode - - -#Added by cargo -# -#already existing elements are commented out - -/target -**/*.rs.bk From 9db9e08399712b04bfa804497ccbbb97eccef360 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Fri, 11 Mar 2022 13:58:58 -0500 Subject: [PATCH 14/22] Move transform_propagate_system back to bevy_transform --- crates/bevy_gltf/src/loader.rs | 2 +- crates/bevy_hierarchy/Cargo.toml | 1 - .../src/{hierarchy => }/child_builder.rs | 0 .../src/{hierarchy => }/hierarchy.rs | 2 +- crates/bevy_hierarchy/src/hierarchy/mod.rs | 8 -- crates/bevy_hierarchy/src/lib.rs | 35 +++--- ...archy_maintenance_system.rs => systems.rs} | 100 ----------------- crates/bevy_pbr/Cargo.toml | 1 - crates/bevy_pbr/src/lib.rs | 10 +- crates/bevy_render/Cargo.toml | 1 - crates/bevy_render/src/view/visibility/mod.rs | 8 +- crates/bevy_scene/src/command.rs | 2 +- crates/bevy_scene/src/scene_spawner.rs | 2 +- crates/bevy_transform/Cargo.toml | 1 + crates/bevy_transform/src/lib.rs | 27 ++++- .../src/systems.rs} | 103 ++++++++++++++++-- crates/bevy_ui/src/flex/mod.rs | 2 +- crates/bevy_ui/src/lib.rs | 8 +- crates/bevy_ui/src/update.rs | 4 +- 19 files changed, 155 insertions(+), 162 deletions(-) rename crates/bevy_hierarchy/src/{hierarchy => }/child_builder.rs (100%) rename crates/bevy_hierarchy/src/{hierarchy => }/hierarchy.rs (98%) delete mode 100644 crates/bevy_hierarchy/src/hierarchy/mod.rs rename crates/bevy_hierarchy/src/{hierarchy/hierarchy_maintenance_system.rs => systems.rs} (52%) rename crates/{bevy_hierarchy/src/transform_propagate_system.rs => bevy_transform/src/systems.rs} (66%) diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index c5de4df613db1..464f89c4a9be6 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -4,7 +4,7 @@ use bevy_asset::{ }; use bevy_core::Name; use bevy_ecs::world::World; -use bevy_hierarchy::hierarchy::{BuildWorldChildren, WorldChildBuilder}; +use bevy_hierarchy::{BuildWorldChildren, WorldChildBuilder}; use bevy_log::warn; use bevy_math::{Mat4, Vec3}; use bevy_pbr::{ diff --git a/crates/bevy_hierarchy/Cargo.toml b/crates/bevy_hierarchy/Cargo.toml index 541f69fdfa4e9..87f4892a64fcf 100644 --- a/crates/bevy_hierarchy/Cargo.toml +++ b/crates/bevy_hierarchy/Cargo.toml @@ -15,7 +15,6 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.6.0", features = ["bevy_reflect" bevy_math = { path = "../bevy_math", version = "0.6.0" } bevy_reflect = { path = "../bevy_reflect", version = "0.6.0", features = ["bevy"] } bevy_utils = { path = "../bevy_utils", version = "0.6.0" } -bevy_transform = {path = "../bevy_transform", version = "0.6.0"} # other smallvec = { version = "1.6", features = ["serde", "union", "const_generics"] } diff --git a/crates/bevy_hierarchy/src/hierarchy/child_builder.rs b/crates/bevy_hierarchy/src/child_builder.rs similarity index 100% rename from crates/bevy_hierarchy/src/hierarchy/child_builder.rs rename to crates/bevy_hierarchy/src/child_builder.rs diff --git a/crates/bevy_hierarchy/src/hierarchy/hierarchy.rs b/crates/bevy_hierarchy/src/hierarchy.rs similarity index 98% rename from crates/bevy_hierarchy/src/hierarchy/hierarchy.rs rename to crates/bevy_hierarchy/src/hierarchy.rs index 0820742c34b75..56c9b0f8ad938 100644 --- a/crates/bevy_hierarchy/src/hierarchy/hierarchy.rs +++ b/crates/bevy_hierarchy/src/hierarchy.rs @@ -116,7 +116,7 @@ mod tests { }; use super::DespawnRecursiveExt; - use crate::{components::Children, hierarchy::BuildChildren}; + use crate::{child_builder::BuildChildren, components::Children}; #[derive(Component, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Debug)] struct Idx(u32); diff --git a/crates/bevy_hierarchy/src/hierarchy/mod.rs b/crates/bevy_hierarchy/src/hierarchy/mod.rs deleted file mode 100644 index 23e9108e2dec2..0000000000000 --- a/crates/bevy_hierarchy/src/hierarchy/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -mod child_builder; -#[allow(clippy::module_inception)] -mod hierarchy; -mod hierarchy_maintenance_system; - -pub use child_builder::*; -pub use hierarchy::*; -pub use hierarchy_maintenance_system::*; diff --git a/crates/bevy_hierarchy/src/lib.rs b/crates/bevy_hierarchy/src/lib.rs index 5407bc0b6315b..e61ec3acea98e 100644 --- a/crates/bevy_hierarchy/src/lib.rs +++ b/crates/bevy_hierarchy/src/lib.rs @@ -5,11 +5,18 @@ //! from the [`Parent`] to its [`Children`]. /// The basic components of the hierarchy -pub mod components; +mod components; +pub use components::*; + /// Establishing and updating the transform hierarchy -pub mod hierarchy; -/// Propagating transform changes down the transform hierarchy -pub mod transform_propagate_system; +mod hierarchy; +pub use hierarchy::*; + +mod child_builder; +pub use child_builder::*; + +mod systems; +pub use systems::*; #[doc(hidden)] pub mod prelude { @@ -18,18 +25,15 @@ pub mod prelude { } use bevy_app::prelude::*; -use bevy_ecs::schedule::{ParallelSystemDescriptorCoercion, SystemLabel}; -use prelude::{parent_update_system, Children, Parent, PreviousParent}; +use bevy_ecs::prelude::*; /// The base plugin for handling [`Parent`] and [`Children`] components #[derive(Default)] pub struct HierarchyPlugin; -/// Label enum for the types of systems relating to transform +/// Label enum for the systems relating to hierarchy upkeep #[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)] pub enum HierarchySystem { - /// Propagates changes in transform to childrens' [`GlobalTransform`](bevy_transform::components::GlobalTransform) - TransformPropagate, /// Updates [`Parent`] when changes in the hierarchy occur ParentUpdate, } @@ -39,26 +43,13 @@ impl Plugin for HierarchyPlugin { app.register_type::() .register_type::() .register_type::() - // add transform systems to startup so the first update is "correct" .add_startup_system_to_stage( StartupStage::PostStartup, parent_update_system.label(HierarchySystem::ParentUpdate), ) - .add_startup_system_to_stage( - StartupStage::PostStartup, - transform_propagate_system::transform_propagate_system - .label(HierarchySystem::TransformPropagate) - .after(HierarchySystem::ParentUpdate), - ) .add_system_to_stage( CoreStage::PostUpdate, parent_update_system.label(HierarchySystem::ParentUpdate), - ) - .add_system_to_stage( - CoreStage::PostUpdate, - transform_propagate_system::transform_propagate_system - .label(HierarchySystem::TransformPropagate) - .after(HierarchySystem::ParentUpdate), ); } } diff --git a/crates/bevy_hierarchy/src/hierarchy/hierarchy_maintenance_system.rs b/crates/bevy_hierarchy/src/systems.rs similarity index 52% rename from crates/bevy_hierarchy/src/hierarchy/hierarchy_maintenance_system.rs rename to crates/bevy_hierarchy/src/systems.rs index 1e8c2f84e9ed0..194f0da0c2af4 100644 --- a/crates/bevy_hierarchy/src/hierarchy/hierarchy_maintenance_system.rs +++ b/crates/bevy_hierarchy/src/systems.rs @@ -70,103 +70,3 @@ pub fn parent_update_system( commands.entity(*e).insert(Children::with(v)); }); } -#[cfg(test)] -mod test { - use bevy_ecs::{ - schedule::{Schedule, Stage, SystemStage}, - system::CommandQueue, - world::World, - }; - - use bevy_transform::components::Transform; - - use super::*; - use crate::{hierarchy::BuildChildren, transform_propagate_system::transform_propagate_system}; - - #[test] - fn correct_children() { - let mut world = World::default(); - - let mut update_stage = SystemStage::parallel(); - update_stage.add_system(parent_update_system); - update_stage.add_system(transform_propagate_system); - - let mut schedule = Schedule::default(); - schedule.add_stage("update", update_stage); - - // Add parent entities - let mut command_queue = CommandQueue::default(); - let mut commands = Commands::new(&mut command_queue, &world); - 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( - 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(), - ); - }); - command_queue.apply(&mut world); - schedule.run(&mut world); - - assert_eq!( - world - .get::(parent) - .unwrap() - .0 - .iter() - .cloned() - .collect::>(), - children, - ); - - // Parent `e1` to `e2`. - (*world.get_mut::(children[0]).unwrap()).0 = children[1]; - - schedule.run(&mut world); - - assert_eq!( - world - .get::(parent) - .unwrap() - .iter() - .cloned() - .collect::>(), - vec![children[1]] - ); - - assert_eq!( - world - .get::(children[1]) - .unwrap() - .iter() - .cloned() - .collect::>(), - vec![children[0]] - ); - - assert!(world.despawn(children[0])); - - schedule.run(&mut world); - - assert_eq!( - world - .get::(parent) - .unwrap() - .iter() - .cloned() - .collect::>(), - vec![children[1]] - ); - } -} diff --git a/crates/bevy_pbr/Cargo.toml b/crates/bevy_pbr/Cargo.toml index 25f8dfc32a710..4790bb75ab7c8 100644 --- a/crates/bevy_pbr/Cargo.toml +++ b/crates/bevy_pbr/Cargo.toml @@ -18,7 +18,6 @@ bevy_asset = { path = "../bevy_asset", version = "0.6.0" } bevy_core = { path = "../bevy_core", version = "0.6.0" } bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.6.0" } bevy_ecs = { path = "../bevy_ecs", version = "0.6.0" } -bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.6.0" } bevy_math = { path = "../bevy_math", version = "0.6.0" } bevy_reflect = { path = "../bevy_reflect", version = "0.6.0", features = ["bevy"] } bevy_render = { path = "../bevy_render", version = "0.6.0" } diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index 15e71a1383de4..94234fc73388e 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -35,7 +35,6 @@ pub mod draw_3d_graph { use bevy_app::prelude::*; use bevy_asset::{load_internal_asset, Assets, Handle, HandleUntyped}; use bevy_ecs::prelude::*; -use bevy_hierarchy::HierarchySystem; use bevy_reflect::TypeUuid; use bevy_render::{ prelude::Color, @@ -45,6 +44,7 @@ use bevy_render::{ view::VisibilitySystems, RenderApp, RenderStage, }; +use bevy_transform::TransformSystem; pub const PBR_SHADER_HANDLE: HandleUntyped = HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 4805239651767701046); @@ -86,26 +86,26 @@ impl Plugin for PbrPlugin { CoreStage::PostUpdate, assign_lights_to_clusters .label(SimulationLightSystems::AssignLightsToClusters) - .after(HierarchySystem::TransformPropagate), + .after(TransformSystem::TransformPropagate), ) .add_system_to_stage( CoreStage::PostUpdate, update_directional_light_frusta .label(SimulationLightSystems::UpdateDirectionalLightFrusta) - .after(HierarchySystem::TransformPropagate), + .after(TransformSystem::TransformPropagate), ) .add_system_to_stage( CoreStage::PostUpdate, update_point_light_frusta .label(SimulationLightSystems::UpdatePointLightFrusta) - .after(HierarchySystem::TransformPropagate) + .after(TransformSystem::TransformPropagate) .after(SimulationLightSystems::AssignLightsToClusters), ) .add_system_to_stage( CoreStage::PostUpdate, check_light_mesh_visibility .label(SimulationLightSystems::CheckLightVisibility) - .after(HierarchySystem::TransformPropagate) + .after(TransformSystem::TransformPropagate) .after(VisibilitySystems::CalculateBounds) .after(SimulationLightSystems::UpdateDirectionalLightFrusta) .after(SimulationLightSystems::UpdatePointLightFrusta) diff --git a/crates/bevy_render/Cargo.toml b/crates/bevy_render/Cargo.toml index 7d10f08965184..49b3db948ad20 100644 --- a/crates/bevy_render/Cargo.toml +++ b/crates/bevy_render/Cargo.toml @@ -28,7 +28,6 @@ bevy_core = { path = "../bevy_core", version = "0.6.0" } bevy_crevice = { path = "../bevy_crevice", version = "0.6.0", features = ["glam"] } bevy_derive = { path = "../bevy_derive", version = "0.6.0" } bevy_ecs = { path = "../bevy_ecs", version = "0.6.0" } -bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.6.0" } bevy_math = { path = "../bevy_math", version = "0.6.0" } bevy_reflect = { path = "../bevy_reflect", version = "0.6.0", features = ["bevy"] } bevy_transform = { path = "../bevy_transform", version = "0.6.0" } diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index bb8d8dbde37bf..860ebb2142dae 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -5,9 +5,9 @@ pub use render_layers::*; use bevy_app::{CoreStage, Plugin}; use bevy_asset::{Assets, Handle}; use bevy_ecs::prelude::*; -use bevy_hierarchy::HierarchySystem; use bevy_reflect::Reflect; use bevy_transform::components::GlobalTransform; +use bevy_transform::TransformSystem; use crate::{ camera::{Camera, CameraProjection, OrthographicProjection, PerspectiveProjection}, @@ -88,13 +88,13 @@ impl Plugin for VisibilityPlugin { CoreStage::PostUpdate, update_frusta:: .label(UpdateOrthographicFrusta) - .after(HierarchySystem::TransformPropagate), + .after(TransformSystem::TransformPropagate), ) .add_system_to_stage( CoreStage::PostUpdate, update_frusta:: .label(UpdatePerspectiveFrusta) - .after(HierarchySystem::TransformPropagate), + .after(TransformSystem::TransformPropagate), ) .add_system_to_stage( CoreStage::PostUpdate, @@ -103,7 +103,7 @@ impl Plugin for VisibilityPlugin { .after(CalculateBounds) .after(UpdateOrthographicFrusta) .after(UpdatePerspectiveFrusta) - .after(HierarchySystem::TransformPropagate), + .after(TransformSystem::TransformPropagate), ); } } diff --git a/crates/bevy_scene/src/command.rs b/crates/bevy_scene/src/command.rs index a8d9d474eba5e..55b8c4ec85db8 100644 --- a/crates/bevy_scene/src/command.rs +++ b/crates/bevy_scene/src/command.rs @@ -4,7 +4,7 @@ use bevy_ecs::{ system::{Command, Commands}, world::World, }; -use bevy_hierarchy::hierarchy::ChildBuilder; +use bevy_hierarchy::ChildBuilder; use crate::{Scene, SceneSpawner}; diff --git a/crates/bevy_scene/src/scene_spawner.rs b/crates/bevy_scene/src/scene_spawner.rs index df2d87154ad60..142d299743efd 100644 --- a/crates/bevy_scene/src/scene_spawner.rs +++ b/crates/bevy_scene/src/scene_spawner.rs @@ -7,7 +7,7 @@ use bevy_ecs::{ system::Command, world::{Mut, World}, }; -use bevy_hierarchy::{hierarchy::AddChild, prelude::Parent}; +use bevy_hierarchy::{AddChild, Parent}; use bevy_reflect::TypeRegistryArc; use bevy_utils::{tracing::error, HashMap}; use thiserror::Error; diff --git a/crates/bevy_transform/Cargo.toml b/crates/bevy_transform/Cargo.toml index 63e5641331b71..ca2fc6d6edfd8 100644 --- a/crates/bevy_transform/Cargo.toml +++ b/crates/bevy_transform/Cargo.toml @@ -12,6 +12,7 @@ keywords = ["bevy"] # bevy bevy_app = { path = "../bevy_app", version = "0.6.0" } bevy_ecs = { path = "../bevy_ecs", version = "0.6.0", features = ["bevy_reflect"] } +bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.6.0"} bevy_math = { path = "../bevy_math", version = "0.6.0" } bevy_reflect = { path = "../bevy_reflect", version = "0.6.0", features = ["bevy"] } bevy_utils = { path = "../bevy_utils", version = "0.6.0" } diff --git a/crates/bevy_transform/src/lib.rs b/crates/bevy_transform/src/lib.rs index bcfe6519d179f..233678e6089af 100644 --- a/crates/bevy_transform/src/lib.rs +++ b/crates/bevy_transform/src/lib.rs @@ -3,6 +3,8 @@ /// The basic components of the transform crate pub mod components; +mod systems; +pub use crate::systems::transform_propagate_system; #[doc(hidden)] pub mod prelude { @@ -11,7 +13,8 @@ pub mod prelude { } use bevy_app::prelude::*; -use bevy_ecs::bundle::Bundle; +use bevy_ecs::prelude::*; +use bevy_hierarchy::HierarchySystem; use prelude::{GlobalTransform, Transform}; /// A [`Bundle`] of the [`Transform`] and [`GlobalTransform`] @@ -74,6 +77,13 @@ impl From for TransformBundle { Self::from_transform(transform) } } +/// Label enum for the systems relating to transform propagaion +#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)] +pub enum TransformSystem { + /// Propagates changes in transform to childrens' [`GlobalTransform`](bevy_transform::components::GlobalTransform) + TransformPropagate, +} + /// The base plugin for handling [`Transform`] components #[derive(Default)] pub struct TransformPlugin; @@ -81,6 +91,19 @@ pub struct TransformPlugin; impl Plugin for TransformPlugin { fn build(&self, app: &mut App) { app.register_type::() - .register_type::(); + .register_type::() + // Adding these to startup ensures the first update is "correct" + .add_startup_system_to_stage( + StartupStage::PostStartup, + systems::transform_propagate_system + .label(TransformSystem::TransformPropagate) + .after(HierarchySystem::ParentUpdate), + ) + .add_system_to_stage( + CoreStage::PostUpdate, + systems::transform_propagate_system + .label(TransformSystem::TransformPropagate) + .after(HierarchySystem::ParentUpdate), + ); } } diff --git a/crates/bevy_hierarchy/src/transform_propagate_system.rs b/crates/bevy_transform/src/systems.rs similarity index 66% rename from crates/bevy_hierarchy/src/transform_propagate_system.rs rename to crates/bevy_transform/src/systems.rs index 40e0cf0bea8a0..9fb2e9a2d0ef9 100644 --- a/crates/bevy_hierarchy/src/transform_propagate_system.rs +++ b/crates/bevy_transform/src/systems.rs @@ -1,10 +1,10 @@ -use crate::components::{Children, Parent}; +use crate::components::{GlobalTransform, Transform}; use bevy_ecs::{ entity::Entity, query::{Changed, With, Without}, system::Query, }; -use bevy_transform::components::{GlobalTransform, Transform}; +use bevy_hierarchy::{Children, Parent}; /// Update [`GlobalTransform`] component of entities based on entity hierarchy and /// [`Transform`] component. @@ -25,7 +25,7 @@ pub fn transform_propagate_system( } if let Some(children) = children { - for child in children.0.iter() { + for child in children.iter() { propagate_recursive( &global_transform, &changed_transform_query, @@ -61,7 +61,7 @@ fn propagate_recursive( }; if let Ok(Some(children)) = children_query.get(entity) { - for child in children.0.iter() { + for child in children.iter() { propagate_recursive( &global_matrix, changed_transform_query, @@ -82,9 +82,12 @@ mod test { world::World, }; - use super::*; - use crate::hierarchy::{parent_update_system, BuildChildren, BuildWorldChildren}; - use bevy_transform::TransformBundle; + use crate::components::{GlobalTransform, Transform}; + use crate::systems::transform_propagate_system; + use crate::TransformBundle; + use bevy_hierarchy::{ + parent_update_system, BuildChildren, BuildWorldChildren, Children, Parent, + }; #[test] fn did_propagate() { @@ -173,4 +176,90 @@ mod test { GlobalTransform::from_xyz(1.0, 0.0, 0.0) * Transform::from_xyz(0.0, 0.0, 3.0) ); } + + #[test] + fn correct_children() { + let mut world = World::default(); + + let mut update_stage = SystemStage::parallel(); + update_stage.add_system(parent_update_system); + update_stage.add_system(transform_propagate_system); + + let mut schedule = Schedule::default(); + schedule.add_stage("update", update_stage); + + // Add parent entities + let mut command_queue = CommandQueue::default(); + let mut commands = Commands::new(&mut command_queue, &world); + 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( + 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(), + ); + }); + command_queue.apply(&mut world); + schedule.run(&mut world); + + assert_eq!( + world + .get::(parent) + .unwrap() + .iter() + .cloned() + .collect::>(), + children, + ); + + // Parent `e1` to `e2`. + (*world.get_mut::(children[0]).unwrap()).0 = children[1]; + + schedule.run(&mut world); + + assert_eq!( + world + .get::(parent) + .unwrap() + .iter() + .cloned() + .collect::>(), + vec![children[1]] + ); + + assert_eq!( + world + .get::(children[1]) + .unwrap() + .iter() + .cloned() + .collect::>(), + vec![children[0]] + ); + + assert!(world.despawn(children[0])); + + schedule.run(&mut world); + + assert_eq!( + world + .get::(parent) + .unwrap() + .iter() + .cloned() + .collect::>(), + vec![children[1]] + ); + } } diff --git a/crates/bevy_ui/src/flex/mod.rs b/crates/bevy_ui/src/flex/mod.rs index 3222427f7a8f2..63ccf94a2ca13 100644 --- a/crates/bevy_ui/src/flex/mod.rs +++ b/crates/bevy_ui/src/flex/mod.rs @@ -7,7 +7,7 @@ use bevy_ecs::{ query::{Changed, FilterFetch, With, Without, WorldQuery}, system::{Query, Res, ResMut}, }; -use bevy_hierarchy::components::{Children, Parent}; +use bevy_hierarchy::{Children, Parent}; use bevy_log::warn; use bevy_math::Vec2; use bevy_transform::components::Transform; diff --git a/crates/bevy_ui/src/lib.rs b/crates/bevy_ui/src/lib.rs index 8e2a28f933e92..2a44323966a3d 100644 --- a/crates/bevy_ui/src/lib.rs +++ b/crates/bevy_ui/src/lib.rs @@ -27,9 +27,9 @@ pub mod prelude { use bevy_app::prelude::*; use bevy_ecs::schedule::{ParallelSystemDescriptorCoercion, SystemLabel}; -use bevy_hierarchy::HierarchySystem; use bevy_input::InputSystem; use bevy_math::{Rect, Size}; +use bevy_transform::TransformSystem; use update::{ui_z_system, update_clipping_system}; use crate::prelude::CameraUi; @@ -93,17 +93,17 @@ impl Plugin for UiPlugin { CoreStage::PostUpdate, flex_node_system .label(UiSystem::Flex) - .before(HierarchySystem::TransformPropagate), + .before(TransformSystem::TransformPropagate), ) .add_system_to_stage( CoreStage::PostUpdate, ui_z_system .after(UiSystem::Flex) - .before(HierarchySystem::TransformPropagate), + .before(TransformSystem::TransformPropagate), ) .add_system_to_stage( CoreStage::PostUpdate, - update_clipping_system.after(HierarchySystem::TransformPropagate), + update_clipping_system.after(TransformSystem::TransformPropagate), ); crate::render::build_ui_render(app); diff --git a/crates/bevy_ui/src/update.rs b/crates/bevy_ui/src/update.rs index 7a3bb91d663fb..8af7d72caca62 100644 --- a/crates/bevy_ui/src/update.rs +++ b/crates/bevy_ui/src/update.rs @@ -8,7 +8,7 @@ use bevy_ecs::{ query::{With, Without}, system::{Commands, Query}, }; -use bevy_hierarchy::components::{Children, Parent}; +use bevy_hierarchy::{Children, Parent}; use bevy_math::Vec2; use bevy_sprite::Rect; use bevy_transform::components::{GlobalTransform, Transform}; @@ -139,7 +139,7 @@ mod tests { system::{CommandQueue, Commands}, world::World, }; - use bevy_hierarchy::hierarchy::BuildChildren; + use bevy_hierarchy::BuildChildren; use bevy_transform::components::Transform; use crate::Node; From 78e2327b3fb926700f76196a55e41cc065d8be29 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Fri, 11 Mar 2022 14:02:36 -0500 Subject: [PATCH 15/22] Expose Transform and GlobalTransform at root of bevy_transform Reduces pointless importing boilerplate --- assets/scenes/load_scene_example.scn.ron | 2 +- crates/bevy_gltf/src/loader.rs | 2 +- crates/bevy_hierarchy/src/lib.rs | 2 +- crates/bevy_pbr/src/bundle.rs | 2 +- crates/bevy_pbr/src/light.rs | 2 +- crates/bevy_pbr/src/render/light.rs | 2 +- crates/bevy_pbr/src/render/mesh.rs | 2 +- crates/bevy_render/src/camera/bundle.rs | 2 +- crates/bevy_render/src/camera/camera.rs | 2 +- crates/bevy_render/src/view/mod.rs | 2 +- crates/bevy_render/src/view/visibility/mod.rs | 2 +- crates/bevy_sprite/src/bundle.rs | 2 +- crates/bevy_sprite/src/mesh2d/material.rs | 2 +- crates/bevy_sprite/src/mesh2d/mesh.rs | 2 +- crates/bevy_sprite/src/render/mod.rs | 2 +- crates/bevy_transform/src/lib.rs | 7 +++---- crates/bevy_ui/src/flex/mod.rs | 2 +- crates/bevy_ui/src/focus.rs | 2 +- crates/bevy_ui/src/render/mod.rs | 2 +- crates/bevy_ui/src/update.rs | 4 ++-- 20 files changed, 23 insertions(+), 24 deletions(-) diff --git a/assets/scenes/load_scene_example.scn.ron b/assets/scenes/load_scene_example.scn.ron index 1f9de9dae7da8..069a9e2627e93 100644 --- a/assets/scenes/load_scene_example.scn.ron +++ b/assets/scenes/load_scene_example.scn.ron @@ -3,7 +3,7 @@ entity: 0, components: [ { - "type": "bevy_transform::components::transform::Transform", + "type": "bevy_transform::transform::Transform", "struct": { "translation": { "type": "glam::vec3::Vec3", diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index 464f89c4a9be6..b4085c3db0133 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -25,7 +25,7 @@ use bevy_render::{ view::VisibleEntities, }; use bevy_scene::Scene; -use bevy_transform::{components::Transform, TransformBundle}; +use bevy_transform::{Transform, TransformBundle}; use bevy_utils::{HashMap, HashSet}; use gltf::{ diff --git a/crates/bevy_hierarchy/src/lib.rs b/crates/bevy_hierarchy/src/lib.rs index e61ec3acea98e..44a21ba9fd26c 100644 --- a/crates/bevy_hierarchy/src/lib.rs +++ b/crates/bevy_hierarchy/src/lib.rs @@ -1,7 +1,7 @@ #![warn(missing_docs)] //! `bevy_hierarchy` can be used to define hierarchies of entities. //! -//! Most commonly, these hierarchies are used for inheriting [`Transform`](bevy_transform::components::Transform) values +//! Most commonly, these hierarchies are used for inheriting [`Transform`](bevy_transform::Transform) values //! from the [`Parent`] to its [`Children`]. /// The basic components of the hierarchy diff --git a/crates/bevy_pbr/src/bundle.rs b/crates/bevy_pbr/src/bundle.rs index c42ce981b95bd..d0a65b1ec373b 100644 --- a/crates/bevy_pbr/src/bundle.rs +++ b/crates/bevy_pbr/src/bundle.rs @@ -7,7 +7,7 @@ use bevy_render::{ primitives::{CubemapFrusta, Frustum}, view::{ComputedVisibility, Visibility, VisibleEntities}, }; -use bevy_transform::components::{GlobalTransform, Transform}; +use bevy_transform::{GlobalTransform, Transform}; /// A component bundle for PBR entities with a [`Mesh`] and a [`StandardMaterial`]. pub type PbrBundle = MaterialMeshBundle; diff --git a/crates/bevy_pbr/src/light.rs b/crates/bevy_pbr/src/light.rs index ec0988f8d6ef6..e4b0b0ed9ef54 100644 --- a/crates/bevy_pbr/src/light.rs +++ b/crates/bevy_pbr/src/light.rs @@ -11,7 +11,7 @@ use bevy_render::{ primitives::{Aabb, CubemapFrusta, Frustum, Sphere}, view::{ComputedVisibility, RenderLayers, Visibility, VisibleEntities}, }; -use bevy_transform::components::GlobalTransform; +use bevy_transform::GlobalTransform; use bevy_utils::tracing::warn; use bevy_window::Windows; diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index c0605748262ae..0ef409ed2e87e 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -29,7 +29,7 @@ use bevy_render::{ ExtractedView, ViewUniform, ViewUniformOffset, ViewUniforms, Visibility, VisibleEntities, }, }; -use bevy_transform::components::GlobalTransform; +use bevy_transform::GlobalTransform; use bevy_utils::{ tracing::{error, warn}, HashMap, diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index ac0ec3acd4360..290f18bf27aff 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -21,7 +21,7 @@ use bevy_render::{ view::{ComputedVisibility, ViewUniform, ViewUniformOffset, ViewUniforms}, RenderApp, RenderStage, }; -use bevy_transform::components::GlobalTransform; +use bevy_transform::GlobalTransform; #[derive(Default)] pub struct MeshRenderPlugin; diff --git a/crates/bevy_render/src/camera/bundle.rs b/crates/bevy_render/src/camera/bundle.rs index f32aad826c5b6..406aca7939d48 100644 --- a/crates/bevy_render/src/camera/bundle.rs +++ b/crates/bevy_render/src/camera/bundle.rs @@ -5,7 +5,7 @@ use crate::{ }; use bevy_ecs::{bundle::Bundle, prelude::Component}; use bevy_math::Vec3; -use bevy_transform::components::{GlobalTransform, Transform}; +use bevy_transform::{GlobalTransform, Transform}; use super::{CameraProjection, ScalingMode}; diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 6da11ccb66473..7e591878c10ec 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -21,7 +21,7 @@ use bevy_ecs::{ }; use bevy_math::{Mat4, UVec2, Vec2, Vec3}; use bevy_reflect::{Reflect, ReflectDeserialize}; -use bevy_transform::components::GlobalTransform; +use bevy_transform::GlobalTransform; use bevy_utils::HashSet; use bevy_window::{WindowCreated, WindowId, WindowResized, Windows}; use serde::{Deserialize, Serialize}; diff --git a/crates/bevy_render/src/view/mod.rs b/crates/bevy_render/src/view/mod.rs index ba712a31943cd..ca688172be7cb 100644 --- a/crates/bevy_render/src/view/mod.rs +++ b/crates/bevy_render/src/view/mod.rs @@ -20,7 +20,7 @@ use crate::{ use bevy_app::{App, Plugin}; use bevy_ecs::prelude::*; use bevy_math::{Mat4, Vec3}; -use bevy_transform::components::GlobalTransform; +use bevy_transform::GlobalTransform; pub struct ViewPlugin; diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index 860ebb2142dae..bce83c27f4eaa 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -6,7 +6,7 @@ use bevy_app::{CoreStage, Plugin}; use bevy_asset::{Assets, Handle}; use bevy_ecs::prelude::*; use bevy_reflect::Reflect; -use bevy_transform::components::GlobalTransform; +use bevy_transform::GlobalTransform; use bevy_transform::TransformSystem; use crate::{ diff --git a/crates/bevy_sprite/src/bundle.rs b/crates/bevy_sprite/src/bundle.rs index 82fdcd9db6292..d66bac98cc215 100644 --- a/crates/bevy_sprite/src/bundle.rs +++ b/crates/bevy_sprite/src/bundle.rs @@ -8,7 +8,7 @@ use bevy_render::{ texture::{Image, DEFAULT_IMAGE_HANDLE}, view::Visibility, }; -use bevy_transform::components::{GlobalTransform, Transform}; +use bevy_transform::{GlobalTransform, Transform}; #[derive(Bundle, Clone)] pub struct SpriteBundle { diff --git a/crates/bevy_sprite/src/mesh2d/material.rs b/crates/bevy_sprite/src/mesh2d/material.rs index b815f7662bddd..aef7824b08d2d 100644 --- a/crates/bevy_sprite/src/mesh2d/material.rs +++ b/crates/bevy_sprite/src/mesh2d/material.rs @@ -28,7 +28,7 @@ use bevy_render::{ view::{ComputedVisibility, Msaa, Visibility, VisibleEntities}, RenderApp, RenderStage, }; -use bevy_transform::components::{GlobalTransform, Transform}; +use bevy_transform::{GlobalTransform, Transform}; use std::hash::Hash; use std::marker::PhantomData; diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index d9bd79aab90e8..f4a54e839d3ed 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -17,7 +17,7 @@ use bevy_render::{ view::{ComputedVisibility, ExtractedView, ViewUniform, ViewUniformOffset, ViewUniforms}, RenderApp, RenderStage, }; -use bevy_transform::components::GlobalTransform; +use bevy_transform::GlobalTransform; /// Component for rendering with meshes in the 2d pipeline, usually with a [2d material](crate::Material2d) such as [`ColorMaterial`](crate::ColorMaterial). /// diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 7e3ffe4c97038..de5748a141fdb 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -26,7 +26,7 @@ use bevy_render::{ view::{Msaa, ViewUniform, ViewUniformOffset, ViewUniforms, Visibility}, RenderWorld, }; -use bevy_transform::components::GlobalTransform; +use bevy_transform::GlobalTransform; use bevy_utils::HashMap; use bytemuck::{Pod, Zeroable}; use copyless::VecHelper; diff --git a/crates/bevy_transform/src/lib.rs b/crates/bevy_transform/src/lib.rs index 233678e6089af..27f57a3439515 100644 --- a/crates/bevy_transform/src/lib.rs +++ b/crates/bevy_transform/src/lib.rs @@ -1,8 +1,8 @@ #![warn(missing_docs)] #![doc = include_str!("../README.md")] -/// The basic components of the transform crate -pub mod components; +mod components; +pub use components::*; mod systems; pub use crate::systems::transform_propagate_system; @@ -15,7 +15,6 @@ pub mod prelude { use bevy_app::prelude::*; use bevy_ecs::prelude::*; use bevy_hierarchy::HierarchySystem; -use prelude::{GlobalTransform, Transform}; /// A [`Bundle`] of the [`Transform`] and [`GlobalTransform`] /// [`Component`](bevy_ecs::component::Component)s, which describe the position of an entity. @@ -80,7 +79,7 @@ impl From for TransformBundle { /// Label enum for the systems relating to transform propagaion #[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)] pub enum TransformSystem { - /// Propagates changes in transform to childrens' [`GlobalTransform`](bevy_transform::components::GlobalTransform) + /// Propagates changes in transform to childrens' [`GlobalTransform`](bevy_transform::GlobalTransform) TransformPropagate, } diff --git a/crates/bevy_ui/src/flex/mod.rs b/crates/bevy_ui/src/flex/mod.rs index 63ccf94a2ca13..cc2bcbcf181c2 100644 --- a/crates/bevy_ui/src/flex/mod.rs +++ b/crates/bevy_ui/src/flex/mod.rs @@ -10,7 +10,7 @@ use bevy_ecs::{ use bevy_hierarchy::{Children, Parent}; use bevy_log::warn; use bevy_math::Vec2; -use bevy_transform::components::Transform; +use bevy_transform::Transform; use bevy_utils::HashMap; use bevy_window::{Window, WindowId, WindowScaleFactorChanged, Windows}; use std::fmt; diff --git a/crates/bevy_ui/src/focus.rs b/crates/bevy_ui/src/focus.rs index bf01512d57b80..339978a64096e 100644 --- a/crates/bevy_ui/src/focus.rs +++ b/crates/bevy_ui/src/focus.rs @@ -9,7 +9,7 @@ use bevy_ecs::{ use bevy_input::{mouse::MouseButton, touch::Touches, Input}; use bevy_math::Vec2; use bevy_reflect::{Reflect, ReflectDeserialize}; -use bevy_transform::components::GlobalTransform; +use bevy_transform::GlobalTransform; use bevy_window::Windows; use serde::{Deserialize, Serialize}; use smallvec::SmallVec; diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index dff085aa39993..000c87d9a4fce 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -26,7 +26,7 @@ use bevy_render::{ }; use bevy_sprite::{Rect, SpriteAssetEvents, TextureAtlas}; use bevy_text::{DefaultTextPipeline, Text}; -use bevy_transform::components::GlobalTransform; +use bevy_transform::GlobalTransform; use bevy_utils::HashMap; use bevy_window::{WindowId, Windows}; use bytemuck::{Pod, Zeroable}; diff --git a/crates/bevy_ui/src/update.rs b/crates/bevy_ui/src/update.rs index 8af7d72caca62..46cb357d7bc2a 100644 --- a/crates/bevy_ui/src/update.rs +++ b/crates/bevy_ui/src/update.rs @@ -11,7 +11,7 @@ use bevy_ecs::{ use bevy_hierarchy::{Children, Parent}; use bevy_math::Vec2; use bevy_sprite::Rect; -use bevy_transform::components::{GlobalTransform, Transform}; +use bevy_transform::{GlobalTransform, Transform}; /// The resolution of Z values for UI pub const UI_Z_STEP: f32 = 0.001; @@ -140,7 +140,7 @@ mod tests { world::World, }; use bevy_hierarchy::BuildChildren; - use bevy_transform::components::Transform; + use bevy_transform::Transform; use crate::Node; From a4fd724bf62fa36a9e0bf4a311240655393e8b36 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Fri, 11 Mar 2022 14:18:25 -0500 Subject: [PATCH 16/22] Re-add doc links --- crates/bevy_transform/src/components/global_transform.rs | 4 ++-- crates/bevy_transform/src/components/transform.rs | 4 ++-- crates/bevy_transform/src/lib.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/bevy_transform/src/components/global_transform.rs b/crates/bevy_transform/src/components/global_transform.rs index efa01262da85d..f1bce51993914 100644 --- a/crates/bevy_transform/src/components/global_transform.rs +++ b/crates/bevy_transform/src/components/global_transform.rs @@ -14,12 +14,12 @@ use std::ops::Mul; /// ## [`Transform`] and [`GlobalTransform`] /// /// [`Transform`] is the position of an entity relative to its parent position, or the reference -/// frame if it doesn't have a `Parent`. +/// frame if it doesn't have a [`Parent`](bevy_hierarchy::Parent). /// /// [`GlobalTransform`] is the position of an entity relative to the reference frame. /// /// [`GlobalTransform`] is updated from [`Transform`] in the system -/// `transform_propagate_system`. +/// [`transform_propagate_system`](crate::transform_propagate_system). /// /// This system runs in stage [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate). If you /// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag diff --git a/crates/bevy_transform/src/components/transform.rs b/crates/bevy_transform/src/components/transform.rs index 9aabbde081f97..80c80c7f54fbe 100644 --- a/crates/bevy_transform/src/components/transform.rs +++ b/crates/bevy_transform/src/components/transform.rs @@ -15,12 +15,12 @@ use std::ops::Mul; /// ## [`Transform`] and [`GlobalTransform`] /// /// [`Transform`] is the position of an entity relative to its parent position, or the reference -/// frame if it doesn't have a `Parent`. +/// frame if it doesn't have a [`Parent`](bevy_hierarchy::Parent). /// /// [`GlobalTransform`] is the position of an entity relative to the reference frame. /// /// [`GlobalTransform`] is updated from [`Transform`] in the system -/// `transform_propagate_system`. +/// [`transform_propagate_system`](crate::transform_propagate_system). /// /// This system runs in stage [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate). If you /// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag diff --git a/crates/bevy_transform/src/lib.rs b/crates/bevy_transform/src/lib.rs index 27f57a3439515..919d6bada6985 100644 --- a/crates/bevy_transform/src/lib.rs +++ b/crates/bevy_transform/src/lib.rs @@ -32,7 +32,7 @@ use bevy_hierarchy::HierarchySystem; /// [`GlobalTransform`] is the position of an entity relative to the reference frame. /// /// [`GlobalTransform`] is updated from [`Transform`] in the system -/// `transform_propagate_system`. +/// [`transform_propagate_system`]. /// /// This system runs in stage [`CoreStage::PostUpdate`](crate::CoreStage::PostUpdate). If you /// update the[`Transform`] of an entity in this stage or after, you will notice a 1 frame lag From 41bcf614ed63c6688cc791f8704f35df7e4be1e6 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Fri, 11 Mar 2022 14:20:47 -0500 Subject: [PATCH 17/22] Expose ChildBuilder traits in prelude --- crates/bevy_hierarchy/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/bevy_hierarchy/src/lib.rs b/crates/bevy_hierarchy/src/lib.rs index 44a21ba9fd26c..fdd02004d1eb0 100644 --- a/crates/bevy_hierarchy/src/lib.rs +++ b/crates/bevy_hierarchy/src/lib.rs @@ -4,11 +4,9 @@ //! Most commonly, these hierarchies are used for inheriting [`Transform`](bevy_transform::Transform) values //! from the [`Parent`] to its [`Children`]. -/// The basic components of the hierarchy mod components; pub use components::*; -/// Establishing and updating the transform hierarchy mod hierarchy; pub use hierarchy::*; @@ -21,7 +19,7 @@ pub use systems::*; #[doc(hidden)] pub mod prelude { #[doc(hidden)] - pub use crate::{components::*, hierarchy::*, HierarchyPlugin}; + pub use crate::{child_builder::*, components::*, hierarchy::*, HierarchyPlugin}; } use bevy_app::prelude::*; From 5fb826c945a0da6edc12fd6cf381a9193bc24761 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Fri, 11 Mar 2022 14:02:36 -0500 Subject: [PATCH 18/22] Revert "Expose Transform and GlobalTransform at root of bevy_transform" This reverts commit 013836a816292f5b23f729197d14ead05d8882b0. --- assets/scenes/load_scene_example.scn.ron | 2 +- crates/bevy_gltf/src/loader.rs | 2 +- crates/bevy_hierarchy/src/lib.rs | 2 +- crates/bevy_pbr/src/bundle.rs | 2 +- crates/bevy_pbr/src/light.rs | 2 +- crates/bevy_pbr/src/render/light.rs | 2 +- crates/bevy_pbr/src/render/mesh.rs | 2 +- crates/bevy_render/src/camera/bundle.rs | 2 +- crates/bevy_render/src/camera/camera.rs | 2 +- crates/bevy_render/src/view/mod.rs | 2 +- crates/bevy_render/src/view/visibility/mod.rs | 2 +- crates/bevy_sprite/src/bundle.rs | 2 +- crates/bevy_sprite/src/mesh2d/material.rs | 2 +- crates/bevy_sprite/src/mesh2d/mesh.rs | 2 +- crates/bevy_sprite/src/render/mod.rs | 2 +- crates/bevy_transform/src/lib.rs | 7 ++++--- crates/bevy_ui/src/flex/mod.rs | 2 +- crates/bevy_ui/src/focus.rs | 2 +- crates/bevy_ui/src/render/mod.rs | 2 +- crates/bevy_ui/src/update.rs | 4 ++-- 20 files changed, 24 insertions(+), 23 deletions(-) diff --git a/assets/scenes/load_scene_example.scn.ron b/assets/scenes/load_scene_example.scn.ron index 069a9e2627e93..1f9de9dae7da8 100644 --- a/assets/scenes/load_scene_example.scn.ron +++ b/assets/scenes/load_scene_example.scn.ron @@ -3,7 +3,7 @@ entity: 0, components: [ { - "type": "bevy_transform::transform::Transform", + "type": "bevy_transform::components::transform::Transform", "struct": { "translation": { "type": "glam::vec3::Vec3", diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index b4085c3db0133..464f89c4a9be6 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -25,7 +25,7 @@ use bevy_render::{ view::VisibleEntities, }; use bevy_scene::Scene; -use bevy_transform::{Transform, TransformBundle}; +use bevy_transform::{components::Transform, TransformBundle}; use bevy_utils::{HashMap, HashSet}; use gltf::{ diff --git a/crates/bevy_hierarchy/src/lib.rs b/crates/bevy_hierarchy/src/lib.rs index fdd02004d1eb0..1e274c979da12 100644 --- a/crates/bevy_hierarchy/src/lib.rs +++ b/crates/bevy_hierarchy/src/lib.rs @@ -1,7 +1,7 @@ #![warn(missing_docs)] //! `bevy_hierarchy` can be used to define hierarchies of entities. //! -//! Most commonly, these hierarchies are used for inheriting [`Transform`](bevy_transform::Transform) values +//! Most commonly, these hierarchies are used for inheriting [`Transform`](bevy_transform::components::Transform) values //! from the [`Parent`] to its [`Children`]. mod components; diff --git a/crates/bevy_pbr/src/bundle.rs b/crates/bevy_pbr/src/bundle.rs index d0a65b1ec373b..c42ce981b95bd 100644 --- a/crates/bevy_pbr/src/bundle.rs +++ b/crates/bevy_pbr/src/bundle.rs @@ -7,7 +7,7 @@ use bevy_render::{ primitives::{CubemapFrusta, Frustum}, view::{ComputedVisibility, Visibility, VisibleEntities}, }; -use bevy_transform::{GlobalTransform, Transform}; +use bevy_transform::components::{GlobalTransform, Transform}; /// A component bundle for PBR entities with a [`Mesh`] and a [`StandardMaterial`]. pub type PbrBundle = MaterialMeshBundle; diff --git a/crates/bevy_pbr/src/light.rs b/crates/bevy_pbr/src/light.rs index e4b0b0ed9ef54..ec0988f8d6ef6 100644 --- a/crates/bevy_pbr/src/light.rs +++ b/crates/bevy_pbr/src/light.rs @@ -11,7 +11,7 @@ use bevy_render::{ primitives::{Aabb, CubemapFrusta, Frustum, Sphere}, view::{ComputedVisibility, RenderLayers, Visibility, VisibleEntities}, }; -use bevy_transform::GlobalTransform; +use bevy_transform::components::GlobalTransform; use bevy_utils::tracing::warn; use bevy_window::Windows; diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 0ef409ed2e87e..c0605748262ae 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -29,7 +29,7 @@ use bevy_render::{ ExtractedView, ViewUniform, ViewUniformOffset, ViewUniforms, Visibility, VisibleEntities, }, }; -use bevy_transform::GlobalTransform; +use bevy_transform::components::GlobalTransform; use bevy_utils::{ tracing::{error, warn}, HashMap, diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 290f18bf27aff..ac0ec3acd4360 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -21,7 +21,7 @@ use bevy_render::{ view::{ComputedVisibility, ViewUniform, ViewUniformOffset, ViewUniforms}, RenderApp, RenderStage, }; -use bevy_transform::GlobalTransform; +use bevy_transform::components::GlobalTransform; #[derive(Default)] pub struct MeshRenderPlugin; diff --git a/crates/bevy_render/src/camera/bundle.rs b/crates/bevy_render/src/camera/bundle.rs index 406aca7939d48..f32aad826c5b6 100644 --- a/crates/bevy_render/src/camera/bundle.rs +++ b/crates/bevy_render/src/camera/bundle.rs @@ -5,7 +5,7 @@ use crate::{ }; use bevy_ecs::{bundle::Bundle, prelude::Component}; use bevy_math::Vec3; -use bevy_transform::{GlobalTransform, Transform}; +use bevy_transform::components::{GlobalTransform, Transform}; use super::{CameraProjection, ScalingMode}; diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 7e591878c10ec..6da11ccb66473 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -21,7 +21,7 @@ use bevy_ecs::{ }; use bevy_math::{Mat4, UVec2, Vec2, Vec3}; use bevy_reflect::{Reflect, ReflectDeserialize}; -use bevy_transform::GlobalTransform; +use bevy_transform::components::GlobalTransform; use bevy_utils::HashSet; use bevy_window::{WindowCreated, WindowId, WindowResized, Windows}; use serde::{Deserialize, Serialize}; diff --git a/crates/bevy_render/src/view/mod.rs b/crates/bevy_render/src/view/mod.rs index ca688172be7cb..ba712a31943cd 100644 --- a/crates/bevy_render/src/view/mod.rs +++ b/crates/bevy_render/src/view/mod.rs @@ -20,7 +20,7 @@ use crate::{ use bevy_app::{App, Plugin}; use bevy_ecs::prelude::*; use bevy_math::{Mat4, Vec3}; -use bevy_transform::GlobalTransform; +use bevy_transform::components::GlobalTransform; pub struct ViewPlugin; diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index bce83c27f4eaa..860ebb2142dae 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -6,7 +6,7 @@ use bevy_app::{CoreStage, Plugin}; use bevy_asset::{Assets, Handle}; use bevy_ecs::prelude::*; use bevy_reflect::Reflect; -use bevy_transform::GlobalTransform; +use bevy_transform::components::GlobalTransform; use bevy_transform::TransformSystem; use crate::{ diff --git a/crates/bevy_sprite/src/bundle.rs b/crates/bevy_sprite/src/bundle.rs index d66bac98cc215..82fdcd9db6292 100644 --- a/crates/bevy_sprite/src/bundle.rs +++ b/crates/bevy_sprite/src/bundle.rs @@ -8,7 +8,7 @@ use bevy_render::{ texture::{Image, DEFAULT_IMAGE_HANDLE}, view::Visibility, }; -use bevy_transform::{GlobalTransform, Transform}; +use bevy_transform::components::{GlobalTransform, Transform}; #[derive(Bundle, Clone)] pub struct SpriteBundle { diff --git a/crates/bevy_sprite/src/mesh2d/material.rs b/crates/bevy_sprite/src/mesh2d/material.rs index aef7824b08d2d..b815f7662bddd 100644 --- a/crates/bevy_sprite/src/mesh2d/material.rs +++ b/crates/bevy_sprite/src/mesh2d/material.rs @@ -28,7 +28,7 @@ use bevy_render::{ view::{ComputedVisibility, Msaa, Visibility, VisibleEntities}, RenderApp, RenderStage, }; -use bevy_transform::{GlobalTransform, Transform}; +use bevy_transform::components::{GlobalTransform, Transform}; use std::hash::Hash; use std::marker::PhantomData; diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index f4a54e839d3ed..d9bd79aab90e8 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -17,7 +17,7 @@ use bevy_render::{ view::{ComputedVisibility, ExtractedView, ViewUniform, ViewUniformOffset, ViewUniforms}, RenderApp, RenderStage, }; -use bevy_transform::GlobalTransform; +use bevy_transform::components::GlobalTransform; /// Component for rendering with meshes in the 2d pipeline, usually with a [2d material](crate::Material2d) such as [`ColorMaterial`](crate::ColorMaterial). /// diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index de5748a141fdb..7e3ffe4c97038 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -26,7 +26,7 @@ use bevy_render::{ view::{Msaa, ViewUniform, ViewUniformOffset, ViewUniforms, Visibility}, RenderWorld, }; -use bevy_transform::GlobalTransform; +use bevy_transform::components::GlobalTransform; use bevy_utils::HashMap; use bytemuck::{Pod, Zeroable}; use copyless::VecHelper; diff --git a/crates/bevy_transform/src/lib.rs b/crates/bevy_transform/src/lib.rs index 919d6bada6985..4a008c4c811f0 100644 --- a/crates/bevy_transform/src/lib.rs +++ b/crates/bevy_transform/src/lib.rs @@ -1,8 +1,8 @@ #![warn(missing_docs)] #![doc = include_str!("../README.md")] -mod components; -pub use components::*; +/// The basic components of the transform crate +pub mod components; mod systems; pub use crate::systems::transform_propagate_system; @@ -15,6 +15,7 @@ pub mod prelude { use bevy_app::prelude::*; use bevy_ecs::prelude::*; use bevy_hierarchy::HierarchySystem; +use prelude::{GlobalTransform, Transform}; /// A [`Bundle`] of the [`Transform`] and [`GlobalTransform`] /// [`Component`](bevy_ecs::component::Component)s, which describe the position of an entity. @@ -79,7 +80,7 @@ impl From for TransformBundle { /// Label enum for the systems relating to transform propagaion #[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)] pub enum TransformSystem { - /// Propagates changes in transform to childrens' [`GlobalTransform`](bevy_transform::GlobalTransform) + /// Propagates changes in transform to childrens' [`GlobalTransform`](bevy_transform::components::GlobalTransform) TransformPropagate, } diff --git a/crates/bevy_ui/src/flex/mod.rs b/crates/bevy_ui/src/flex/mod.rs index cc2bcbcf181c2..63ccf94a2ca13 100644 --- a/crates/bevy_ui/src/flex/mod.rs +++ b/crates/bevy_ui/src/flex/mod.rs @@ -10,7 +10,7 @@ use bevy_ecs::{ use bevy_hierarchy::{Children, Parent}; use bevy_log::warn; use bevy_math::Vec2; -use bevy_transform::Transform; +use bevy_transform::components::Transform; use bevy_utils::HashMap; use bevy_window::{Window, WindowId, WindowScaleFactorChanged, Windows}; use std::fmt; diff --git a/crates/bevy_ui/src/focus.rs b/crates/bevy_ui/src/focus.rs index 339978a64096e..bf01512d57b80 100644 --- a/crates/bevy_ui/src/focus.rs +++ b/crates/bevy_ui/src/focus.rs @@ -9,7 +9,7 @@ use bevy_ecs::{ use bevy_input::{mouse::MouseButton, touch::Touches, Input}; use bevy_math::Vec2; use bevy_reflect::{Reflect, ReflectDeserialize}; -use bevy_transform::GlobalTransform; +use bevy_transform::components::GlobalTransform; use bevy_window::Windows; use serde::{Deserialize, Serialize}; use smallvec::SmallVec; diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 000c87d9a4fce..dff085aa39993 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -26,7 +26,7 @@ use bevy_render::{ }; use bevy_sprite::{Rect, SpriteAssetEvents, TextureAtlas}; use bevy_text::{DefaultTextPipeline, Text}; -use bevy_transform::GlobalTransform; +use bevy_transform::components::GlobalTransform; use bevy_utils::HashMap; use bevy_window::{WindowId, Windows}; use bytemuck::{Pod, Zeroable}; diff --git a/crates/bevy_ui/src/update.rs b/crates/bevy_ui/src/update.rs index 46cb357d7bc2a..8af7d72caca62 100644 --- a/crates/bevy_ui/src/update.rs +++ b/crates/bevy_ui/src/update.rs @@ -11,7 +11,7 @@ use bevy_ecs::{ use bevy_hierarchy::{Children, Parent}; use bevy_math::Vec2; use bevy_sprite::Rect; -use bevy_transform::{GlobalTransform, Transform}; +use bevy_transform::components::{GlobalTransform, Transform}; /// The resolution of Z values for UI pub const UI_Z_STEP: f32 = 0.001; @@ -140,7 +140,7 @@ mod tests { world::World, }; use bevy_hierarchy::BuildChildren; - use bevy_transform::Transform; + use bevy_transform::components::Transform; use crate::Node; From 21849e13a8dbab2259fc6308ffd2fba921de62b3 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Sat, 12 Mar 2022 10:57:41 -0500 Subject: [PATCH 19/22] Remove dead doc link --- crates/bevy_hierarchy/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_hierarchy/src/lib.rs b/crates/bevy_hierarchy/src/lib.rs index 1e274c979da12..60fa42f525e97 100644 --- a/crates/bevy_hierarchy/src/lib.rs +++ b/crates/bevy_hierarchy/src/lib.rs @@ -1,7 +1,7 @@ #![warn(missing_docs)] //! `bevy_hierarchy` can be used to define hierarchies of entities. //! -//! Most commonly, these hierarchies are used for inheriting [`Transform`](bevy_transform::components::Transform) values +//! Most commonly, these hierarchies are used for inheriting `Transform` values //! from the [`Parent`] to its [`Children`]. mod components; From ffcea8450a59d75cd2c516c31afe7581bb78b362 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Sat, 12 Mar 2022 11:38:50 -0500 Subject: [PATCH 20/22] Fix doc link --- crates/bevy_transform/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_transform/src/lib.rs b/crates/bevy_transform/src/lib.rs index 4a008c4c811f0..57e6e160000f8 100644 --- a/crates/bevy_transform/src/lib.rs +++ b/crates/bevy_transform/src/lib.rs @@ -80,7 +80,7 @@ impl From for TransformBundle { /// Label enum for the systems relating to transform propagaion #[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)] pub enum TransformSystem { - /// Propagates changes in transform to childrens' [`GlobalTransform`](bevy_transform::components::GlobalTransform) + /// Propagates changes in transform to childrens' [`GlobalTransform`](crate::components::GlobalTransform) TransformPropagate, } From 0deeede9bea8a0a49370983f1fc51a39ae52118f Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Sat, 12 Mar 2022 12:04:46 -0500 Subject: [PATCH 21/22] Remove unused dependencies --- crates/bevy_hierarchy/Cargo.toml | 1 - crates/bevy_transform/Cargo.toml | 4 ---- 2 files changed, 5 deletions(-) diff --git a/crates/bevy_hierarchy/Cargo.toml b/crates/bevy_hierarchy/Cargo.toml index 87f4892a64fcf..69290ddd68fb4 100644 --- a/crates/bevy_hierarchy/Cargo.toml +++ b/crates/bevy_hierarchy/Cargo.toml @@ -12,7 +12,6 @@ keywords = ["bevy"] # bevy bevy_app = { path = "../bevy_app", version = "0.6.0" } bevy_ecs = { path = "../bevy_ecs", version = "0.6.0", features = ["bevy_reflect"] } -bevy_math = { path = "../bevy_math", version = "0.6.0" } bevy_reflect = { path = "../bevy_reflect", version = "0.6.0", features = ["bevy"] } bevy_utils = { path = "../bevy_utils", version = "0.6.0" } diff --git a/crates/bevy_transform/Cargo.toml b/crates/bevy_transform/Cargo.toml index ca2fc6d6edfd8..207a429187680 100644 --- a/crates/bevy_transform/Cargo.toml +++ b/crates/bevy_transform/Cargo.toml @@ -15,7 +15,3 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.6.0", features = ["bevy_reflect" bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.6.0"} bevy_math = { path = "../bevy_math", version = "0.6.0" } bevy_reflect = { path = "../bevy_reflect", version = "0.6.0", features = ["bevy"] } -bevy_utils = { path = "../bevy_utils", version = "0.6.0" } - -# other -smallvec = { version = "1.6", features = ["serde", "union", "const_generics"] } From c0db93c2c29858f105e4d789da0dcfa6cc00fb91 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Mon, 14 Mar 2022 18:53:34 -0700 Subject: [PATCH 22/22] Update crates/bevy_transform/src/lib.rs --- crates/bevy_transform/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_transform/src/lib.rs b/crates/bevy_transform/src/lib.rs index 57e6e160000f8..a88017c7d7d60 100644 --- a/crates/bevy_transform/src/lib.rs +++ b/crates/bevy_transform/src/lib.rs @@ -77,7 +77,7 @@ impl From for TransformBundle { Self::from_transform(transform) } } -/// Label enum for the systems relating to transform propagaion +/// Label enum for the systems relating to transform propagation #[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)] pub enum TransformSystem { /// Propagates changes in transform to childrens' [`GlobalTransform`](crate::components::GlobalTransform)