mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
Split bevy_hierarchy out from bevy_transform (#4168)
# Objective - Hierarchy tools are not just used for `Transform`: they are also used for scenes. - In the future there's interest in using them for other features, such as visiibility inheritance. - The fact that these tools are found in `bevy_transform` causes a great deal of user and developer confusion - Fixes #2758. ## Solution - Split `bevy_transform` into two! - Make everything work again. Note that this is a very tightly scoped PR: I *know* there are code quality and docs issues that existed in bevy_transform that I've just moved around. We should fix those in a seperate PR and try to merge this ASAP to reduce the bitrot involved in splitting an entire crate. ## Frustrations The API around `GlobalTransform` is a mess: we have massive code and docs duplication, no link between the two types and no clear way to extend this to other forms of inheritance. In the medium-term, I feel pretty strongly that `GlobalTransform` should be replaced by something like `Inherited<Transform>`, which lives in `bevy_hierarchy`: - avoids code duplication - makes the inheritance pattern extensible - links the types at the type-level - allows us to remove all references to inheritance from `bevy_transform`, making it more useful as a standalone crate and cleaning up its docs ## Additional context - double-blessed by @cart in https://github.com/bevyengine/bevy/issues/4141#issuecomment-1063592414 and https://github.com/bevyengine/bevy/issues/2758#issuecomment-913810963 - preparation for more advanced / cleaner hierarchy tools: go read https://github.com/bevyengine/rfcs/pull/53 ! - originally attempted by @finegeometer in #2789. It was a great idea, just needed more discussion! Co-authored-by: Carter Anderson <mcanders1@gmail.com>
This commit is contained in:
parent
a291b5aaed
commit
a304fd9a99
29 changed files with 226 additions and 206 deletions
|
@ -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" }
|
||||
|
|
|
@ -4,6 +4,7 @@ use bevy_asset::{
|
|||
};
|
||||
use bevy_core::Name;
|
||||
use bevy_ecs::world::World;
|
||||
use bevy_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,
|
||||
|
|
19
crates/bevy_hierarchy/Cargo.toml
Normal file
19
crates/bevy_hierarchy/Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
|||
[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_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"] }
|
5
crates/bevy_hierarchy/src/components/mod.rs
Normal file
5
crates/bevy_hierarchy/src/components/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
mod children;
|
||||
mod parent;
|
||||
|
||||
pub use children::Children;
|
||||
pub use parent::{Parent, PreviousParent};
|
|
@ -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);
|
53
crates/bevy_hierarchy/src/lib.rs
Normal file
53
crates/bevy_hierarchy/src/lib.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
#![warn(missing_docs)]
|
||||
//! `bevy_hierarchy` can be used to define hierarchies of entities.
|
||||
//!
|
||||
//! Most commonly, these hierarchies are used for inheriting `Transform` values
|
||||
//! from the [`Parent`] to its [`Children`].
|
||||
|
||||
mod components;
|
||||
pub use components::*;
|
||||
|
||||
mod hierarchy;
|
||||
pub use hierarchy::*;
|
||||
|
||||
mod child_builder;
|
||||
pub use child_builder::*;
|
||||
|
||||
mod systems;
|
||||
pub use systems::*;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod prelude {
|
||||
#[doc(hidden)]
|
||||
pub use crate::{child_builder::*, components::*, hierarchy::*, HierarchyPlugin};
|
||||
}
|
||||
|
||||
use bevy_app::prelude::*;
|
||||
use bevy_ecs::prelude::*;
|
||||
|
||||
/// The base plugin for handling [`Parent`] and [`Children`] components
|
||||
#[derive(Default)]
|
||||
pub struct HierarchyPlugin;
|
||||
|
||||
/// Label enum for the systems relating to hierarchy upkeep
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)]
|
||||
pub enum HierarchySystem {
|
||||
/// Updates [`Parent`] when changes in the hierarchy occur
|
||||
ParentUpdate,
|
||||
}
|
||||
|
||||
impl Plugin for HierarchyPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.register_type::<Children>()
|
||||
.register_type::<Parent>()
|
||||
.register_type::<PreviousParent>()
|
||||
.add_startup_system_to_stage(
|
||||
StartupStage::PostStartup,
|
||||
parent_update_system.label(HierarchySystem::ParentUpdate),
|
||||
)
|
||||
.add_system_to_stage(
|
||||
CoreStage::PostUpdate,
|
||||
parent_update_system.label(HierarchySystem::ParentUpdate),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -70,101 +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 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::<Children>(parent)
|
||||
.unwrap()
|
||||
.0
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect::<Vec<_>>(),
|
||||
children,
|
||||
);
|
||||
|
||||
// Parent `e1` to `e2`.
|
||||
(*world.get_mut::<Parent>(children[0]).unwrap()).0 = children[1];
|
||||
|
||||
schedule.run(&mut world);
|
||||
|
||||
assert_eq!(
|
||||
world
|
||||
.get::<Children>(parent)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![children[1]]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
world
|
||||
.get::<Children>(children[1])
|
||||
.unwrap()
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![children[0]]
|
||||
);
|
||||
|
||||
assert!(world.despawn(children[0]));
|
||||
|
||||
schedule.run(&mut world);
|
||||
|
||||
assert_eq!(
|
||||
world
|
||||
.get::<Children>(parent)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![children[1]]
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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" }
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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::*;
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -6,7 +6,8 @@ use bevy_app::{CoreStage, Plugin};
|
|||
use bevy_asset::{Assets, Handle};
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_reflect::Reflect;
|
||||
use bevy_transform::{components::GlobalTransform, TransformSystem};
|
||||
use bevy_transform::components::GlobalTransform;
|
||||
use bevy_transform::TransformSystem;
|
||||
|
||||
use crate::{
|
||||
camera::{Camera, CameraProjection, OrthographicProjection, PerspectiveProjection},
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -4,7 +4,7 @@ use bevy_ecs::{
|
|||
system::{Command, Commands},
|
||||
world::World,
|
||||
};
|
||||
use bevy_transform::hierarchy::ChildBuilder;
|
||||
use bevy_hierarchy::ChildBuilder;
|
||||
|
||||
use crate::{Scene, SceneSpawner};
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ use bevy_ecs::{
|
|||
system::Command,
|
||||
world::{Mut, World},
|
||||
};
|
||||
use bevy_hierarchy::{AddChild, Parent};
|
||||
use bevy_reflect::TypeRegistryArc;
|
||||
use bevy_transform::{hierarchy::AddChild, prelude::Parent};
|
||||
use bevy_utils::{tracing::error, HashMap};
|
||||
use thiserror::Error;
|
||||
use uuid::Uuid;
|
||||
|
|
24
crates/bevy_transform/.gitignore
vendored
24
crates/bevy_transform/.gitignore
vendored
|
@ -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
|
|
@ -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"
|
||||
|
@ -12,9 +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_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"] }
|
||||
|
|
|
@ -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`](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`](crate::transform_propagate_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
|
||||
|
|
|
@ -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::*;
|
||||
|
|
|
@ -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`](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`](crate::transform_propagate_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
|
||||
|
|
|
@ -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::*;
|
|
@ -3,23 +3,19 @@
|
|||
|
||||
/// 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;
|
||||
mod systems;
|
||||
pub use crate::systems::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::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.
|
||||
|
@ -32,12 +28,12 @@ use prelude::{parent_update_system, Children, GlobalTransform, Parent, PreviousP
|
|||
/// ## [`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
|
||||
|
@ -81,46 +77,33 @@ impl From<Transform> for TransformBundle {
|
|||
Self::from_transform(transform)
|
||||
}
|
||||
}
|
||||
/// 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)
|
||||
TransformPropagate,
|
||||
}
|
||||
|
||||
/// 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::<Children>()
|
||||
.register_type::<Parent>()
|
||||
.register_type::<PreviousParent>()
|
||||
.register_type::<Transform>()
|
||||
app.register_type::<Transform>()
|
||||
.register_type::<GlobalTransform>()
|
||||
// add transform systems to startup so the first update is "correct"
|
||||
// Adding these to startup ensures 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
|
||||
systems::transform_propagate_system
|
||||
.label(TransformSystem::TransformPropagate)
|
||||
.after(TransformSystem::ParentUpdate),
|
||||
.after(HierarchySystem::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
|
||||
systems::transform_propagate_system
|
||||
.label(TransformSystem::TransformPropagate)
|
||||
.after(TransformSystem::ParentUpdate),
|
||||
.after(HierarchySystem::ParentUpdate),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
use crate::components::{Children, GlobalTransform, Parent, Transform};
|
||||
use crate::components::{GlobalTransform, Transform};
|
||||
use bevy_ecs::{
|
||||
entity::Entity,
|
||||
query::{Changed, With, Without},
|
||||
system::Query,
|
||||
};
|
||||
use bevy_hierarchy::{Children, Parent};
|
||||
|
||||
/// Update [`GlobalTransform`] component of entities based on entity hierarchy and
|
||||
/// [`Transform`] component.
|
||||
|
@ -24,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,
|
||||
|
@ -60,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,
|
||||
|
@ -81,10 +82,11 @@ mod test {
|
|||
world::World,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
use crate::{
|
||||
hierarchy::{parent_update_system, BuildChildren, BuildWorldChildren},
|
||||
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]
|
||||
|
@ -174,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::<Children>(parent)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect::<Vec<_>>(),
|
||||
children,
|
||||
);
|
||||
|
||||
// Parent `e1` to `e2`.
|
||||
(*world.get_mut::<Parent>(children[0]).unwrap()).0 = children[1];
|
||||
|
||||
schedule.run(&mut world);
|
||||
|
||||
assert_eq!(
|
||||
world
|
||||
.get::<Children>(parent)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![children[1]]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
world
|
||||
.get::<Children>(children[1])
|
||||
.unwrap()
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![children[0]]
|
||||
);
|
||||
|
||||
assert!(world.despawn(children[0]));
|
||||
|
||||
schedule.run(&mut world);
|
||||
|
||||
assert_eq!(
|
||||
world
|
||||
.get::<Children>(parent)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect::<Vec<_>>(),
|
||||
vec![children[1]]
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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" }
|
||||
|
|
|
@ -7,9 +7,10 @@ use bevy_ecs::{
|
|||
query::{Changed, FilterFetch, With, Without, WorldQuery},
|
||||
system::{Query, Res, ResMut},
|
||||
};
|
||||
use bevy_hierarchy::{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;
|
||||
|
|
|
@ -8,12 +8,10 @@ use bevy_ecs::{
|
|||
query::{With, Without},
|
||||
system::{Commands, Query},
|
||||
};
|
||||
use bevy_hierarchy::{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::BuildChildren;
|
||||
use bevy_transform::components::Transform;
|
||||
|
||||
use crate::Node;
|
||||
|
||||
|
|
Loading…
Reference in a new issue