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
@ -14,6 +14,7 @@ bevy_app = { path = "../bevy_app", version = "0.6.0" }
|
|||||||
bevy_asset = { path = "../bevy_asset", version = "0.6.0" }
|
bevy_asset = { path = "../bevy_asset", version = "0.6.0" }
|
||||||
bevy_core = { path = "../bevy_core", version = "0.6.0" }
|
bevy_core = { path = "../bevy_core", version = "0.6.0" }
|
||||||
bevy_ecs = { path = "../bevy_ecs", 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_pbr = { path = "../bevy_pbr", version = "0.6.0" }
|
||||||
bevy_reflect = { path = "../bevy_reflect", version = "0.6.0", features = ["bevy"] }
|
bevy_reflect = { path = "../bevy_reflect", version = "0.6.0", features = ["bevy"] }
|
||||||
bevy_render = { path = "../bevy_render", version = "0.6.0" }
|
bevy_render = { path = "../bevy_render", version = "0.6.0" }
|
||||||
|
@ -4,6 +4,7 @@ use bevy_asset::{
|
|||||||
};
|
};
|
||||||
use bevy_core::Name;
|
use bevy_core::Name;
|
||||||
use bevy_ecs::world::World;
|
use bevy_ecs::world::World;
|
||||||
|
use bevy_hierarchy::{BuildWorldChildren, WorldChildBuilder};
|
||||||
use bevy_log::warn;
|
use bevy_log::warn;
|
||||||
use bevy_math::{Mat4, Vec3};
|
use bevy_math::{Mat4, Vec3};
|
||||||
use bevy_pbr::{
|
use bevy_pbr::{
|
||||||
@ -24,11 +25,8 @@ use bevy_render::{
|
|||||||
view::VisibleEntities,
|
view::VisibleEntities,
|
||||||
};
|
};
|
||||||
use bevy_scene::Scene;
|
use bevy_scene::Scene;
|
||||||
use bevy_transform::{
|
use bevy_transform::{components::Transform, TransformBundle};
|
||||||
hierarchy::{BuildWorldChildren, WorldChildBuilder},
|
|
||||||
prelude::Transform,
|
|
||||||
TransformBundle,
|
|
||||||
};
|
|
||||||
use bevy_utils::{HashMap, HashSet};
|
use bevy_utils::{HashMap, HashSet};
|
||||||
use gltf::{
|
use gltf::{
|
||||||
mesh::Mode,
|
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 super::DespawnRecursiveExt;
|
||||||
use crate::{components::Children, hierarchy::BuildChildren};
|
use crate::{child_builder::BuildChildren, components::Children};
|
||||||
|
|
||||||
#[derive(Component, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Debug)]
|
#[derive(Component, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Debug)]
|
||||||
struct Idx(u32);
|
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));
|
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_derive = { path = "../bevy_derive", version = "0.6.0" }
|
||||||
bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.6.0" }
|
bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.6.0" }
|
||||||
bevy_ecs = { path = "../bevy_ecs", 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_input = { path = "../bevy_input", version = "0.6.0" }
|
||||||
bevy_log = { path = "../bevy_log", version = "0.6.0" }
|
bevy_log = { path = "../bevy_log", version = "0.6.0" }
|
||||||
bevy_math = { path = "../bevy_math", 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)
|
/// * [`LogPlugin`](bevy_log::LogPlugin)
|
||||||
/// * [`CorePlugin`](bevy_core::CorePlugin)
|
/// * [`CorePlugin`](bevy_core::CorePlugin)
|
||||||
/// * [`TransformPlugin`](bevy_transform::TransformPlugin)
|
/// * [`TransformPlugin`](bevy_transform::TransformPlugin)
|
||||||
|
/// * [`HierarchyPlugin`](bevy_hierarchy::HierarchyPlugin)
|
||||||
/// * [`DiagnosticsPlugin`](bevy_diagnostic::DiagnosticsPlugin)
|
/// * [`DiagnosticsPlugin`](bevy_diagnostic::DiagnosticsPlugin)
|
||||||
/// * [`InputPlugin`](bevy_input::InputPlugin)
|
/// * [`InputPlugin`](bevy_input::InputPlugin)
|
||||||
/// * [`WindowPlugin`](bevy_window::WindowPlugin)
|
/// * [`WindowPlugin`](bevy_window::WindowPlugin)
|
||||||
@ -27,6 +28,7 @@ impl PluginGroup for DefaultPlugins {
|
|||||||
group.add(bevy_log::LogPlugin::default());
|
group.add(bevy_log::LogPlugin::default());
|
||||||
group.add(bevy_core::CorePlugin::default());
|
group.add(bevy_core::CorePlugin::default());
|
||||||
group.add(bevy_transform::TransformPlugin::default());
|
group.add(bevy_transform::TransformPlugin::default());
|
||||||
|
group.add(bevy_hierarchy::HierarchyPlugin::default());
|
||||||
group.add(bevy_diagnostic::DiagnosticsPlugin::default());
|
group.add(bevy_diagnostic::DiagnosticsPlugin::default());
|
||||||
group.add(bevy_input::InputPlugin::default());
|
group.add(bevy_input::InputPlugin::default());
|
||||||
group.add(bevy_window::WindowPlugin::default());
|
group.add(bevy_window::WindowPlugin::default());
|
||||||
|
@ -65,6 +65,11 @@ pub mod tasks {
|
|||||||
pub use bevy_tasks::*;
|
pub use bevy_tasks::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod hierarchy {
|
||||||
|
//! Entity hierarchies and property inheritance
|
||||||
|
pub use bevy_hierarchy::*;
|
||||||
|
}
|
||||||
|
|
||||||
pub mod transform {
|
pub mod transform {
|
||||||
//! Local and global transforms (e.g. translation, scale, rotation).
|
//! Local and global transforms (e.g. translation, scale, rotation).
|
||||||
pub use bevy_transform::*;
|
pub use bevy_transform::*;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
app::prelude::*, asset::prelude::*, core::prelude::*, ecs::prelude::*, input::prelude::*,
|
app::prelude::*, asset::prelude::*, core::prelude::*, ecs::prelude::*, hierarchy::prelude::*,
|
||||||
log::prelude::*, math::prelude::*, reflect::prelude::*, scene::prelude::*,
|
input::prelude::*, log::prelude::*, math::prelude::*, reflect::prelude::*, scene::prelude::*,
|
||||||
transform::prelude::*, utils::prelude::*, window::prelude::*, DefaultPlugins, MinimalPlugins,
|
transform::prelude::*, utils::prelude::*, window::prelude::*, DefaultPlugins, MinimalPlugins,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6,7 +6,8 @@ use bevy_app::{CoreStage, Plugin};
|
|||||||
use bevy_asset::{Assets, Handle};
|
use bevy_asset::{Assets, Handle};
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_reflect::Reflect;
|
use bevy_reflect::Reflect;
|
||||||
use bevy_transform::{components::GlobalTransform, TransformSystem};
|
use bevy_transform::components::GlobalTransform;
|
||||||
|
use bevy_transform::TransformSystem;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
camera::{Camera, CameraProjection, OrthographicProjection, PerspectiveProjection},
|
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_asset = { path = "../bevy_asset", version = "0.6.0" }
|
||||||
bevy_ecs = { path = "../bevy_ecs", 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_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" }
|
bevy_utils = { path = "../bevy_utils", version = "0.6.0" }
|
||||||
|
|
||||||
# other
|
# other
|
||||||
|
@ -4,7 +4,7 @@ use bevy_ecs::{
|
|||||||
system::{Command, Commands},
|
system::{Command, Commands},
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
use bevy_transform::hierarchy::ChildBuilder;
|
use bevy_hierarchy::ChildBuilder;
|
||||||
|
|
||||||
use crate::{Scene, SceneSpawner};
|
use crate::{Scene, SceneSpawner};
|
||||||
|
|
||||||
|
@ -7,8 +7,8 @@ use bevy_ecs::{
|
|||||||
system::Command,
|
system::Command,
|
||||||
world::{Mut, World},
|
world::{Mut, World},
|
||||||
};
|
};
|
||||||
|
use bevy_hierarchy::{AddChild, Parent};
|
||||||
use bevy_reflect::TypeRegistryArc;
|
use bevy_reflect::TypeRegistryArc;
|
||||||
use bevy_transform::{hierarchy::AddChild, prelude::Parent};
|
|
||||||
use bevy_utils::{tracing::error, HashMap};
|
use bevy_utils::{tracing::error, HashMap};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use uuid::Uuid;
|
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"
|
name = "bevy_transform"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Provides hierarchy and transform functionality for Bevy Engine"
|
description = "Provides transform functionality for Bevy Engine"
|
||||||
homepage = "https://bevyengine.org"
|
homepage = "https://bevyengine.org"
|
||||||
repository = "https://github.com/bevyengine/bevy"
|
repository = "https://github.com/bevyengine/bevy"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
@ -12,9 +12,6 @@ keywords = ["bevy"]
|
|||||||
# bevy
|
# bevy
|
||||||
bevy_app = { path = "../bevy_app", version = "0.6.0" }
|
bevy_app = { path = "../bevy_app", version = "0.6.0" }
|
||||||
bevy_ecs = { path = "../bevy_ecs", version = "0.6.0", features = ["bevy_reflect"] }
|
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_math = { path = "../bevy_math", version = "0.6.0" }
|
||||||
bevy_reflect = { path = "../bevy_reflect", version = "0.6.0", features = ["bevy"] }
|
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`] and [`GlobalTransform`]
|
||||||
///
|
///
|
||||||
/// [`Transform`] is the position of an entity relative to its parent position, or the reference
|
/// [`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 the position of an entity relative to the reference frame.
|
||||||
///
|
///
|
||||||
/// [`GlobalTransform`] is updated from [`Transform`] in the system
|
/// [`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
|
/// 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
|
/// 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 global_transform;
|
||||||
mod parent;
|
|
||||||
mod transform;
|
mod transform;
|
||||||
|
|
||||||
pub use children::Children;
|
|
||||||
pub use global_transform::*;
|
pub use global_transform::*;
|
||||||
pub use parent::{Parent, PreviousParent};
|
|
||||||
pub use transform::*;
|
pub use transform::*;
|
||||||
|
@ -15,12 +15,12 @@ use std::ops::Mul;
|
|||||||
/// ## [`Transform`] and [`GlobalTransform`]
|
/// ## [`Transform`] and [`GlobalTransform`]
|
||||||
///
|
///
|
||||||
/// [`Transform`] is the position of an entity relative to its parent position, or the reference
|
/// [`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 the position of an entity relative to the reference frame.
|
||||||
///
|
///
|
||||||
/// [`GlobalTransform`] is updated from [`Transform`] in the system
|
/// [`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
|
/// 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
|
/// 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
|
/// The basic components of the transform crate
|
||||||
pub mod components;
|
pub mod components;
|
||||||
/// Establishing and updating the transform hierarchy
|
mod systems;
|
||||||
pub mod hierarchy;
|
pub use crate::systems::transform_propagate_system;
|
||||||
/// Propagating transform changes down the transform hierarchy
|
|
||||||
pub mod transform_propagate_system;
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub use crate::{components::*, hierarchy::*, TransformBundle, TransformPlugin};
|
pub use crate::{components::*, TransformBundle, TransformPlugin};
|
||||||
}
|
}
|
||||||
|
|
||||||
use bevy_app::prelude::*;
|
use bevy_app::prelude::*;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::prelude::*;
|
||||||
bundle::Bundle,
|
use bevy_hierarchy::HierarchySystem;
|
||||||
schedule::{ParallelSystemDescriptorCoercion, SystemLabel},
|
use prelude::{GlobalTransform, Transform};
|
||||||
};
|
|
||||||
use prelude::{parent_update_system, Children, GlobalTransform, Parent, PreviousParent, Transform};
|
|
||||||
|
|
||||||
/// A [`Bundle`] of the [`Transform`] and [`GlobalTransform`]
|
/// A [`Bundle`] of the [`Transform`] and [`GlobalTransform`]
|
||||||
/// [`Component`](bevy_ecs::component::Component)s, which describe the position of an entity.
|
/// [`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`] and [`GlobalTransform`]
|
||||||
///
|
///
|
||||||
/// [`Transform`] is the position of an entity relative to its parent position, or the reference
|
/// [`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 the position of an entity relative to the reference frame.
|
||||||
///
|
///
|
||||||
/// [`GlobalTransform`] is updated from [`Transform`] in the system
|
/// [`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
|
/// 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
|
/// 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)
|
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
|
/// The base plugin for handling [`Transform`] components
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct TransformPlugin;
|
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 {
|
impl Plugin for TransformPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.register_type::<Children>()
|
app.register_type::<Transform>()
|
||||||
.register_type::<Parent>()
|
|
||||||
.register_type::<PreviousParent>()
|
|
||||||
.register_type::<Transform>()
|
|
||||||
.register_type::<GlobalTransform>()
|
.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(
|
.add_startup_system_to_stage(
|
||||||
StartupStage::PostStartup,
|
StartupStage::PostStartup,
|
||||||
parent_update_system.label(TransformSystem::ParentUpdate),
|
systems::transform_propagate_system
|
||||||
)
|
|
||||||
.add_startup_system_to_stage(
|
|
||||||
StartupStage::PostStartup,
|
|
||||||
transform_propagate_system::transform_propagate_system
|
|
||||||
.label(TransformSystem::TransformPropagate)
|
.label(TransformSystem::TransformPropagate)
|
||||||
.after(TransformSystem::ParentUpdate),
|
.after(HierarchySystem::ParentUpdate),
|
||||||
)
|
)
|
||||||
.add_system_to_stage(
|
.add_system_to_stage(
|
||||||
CoreStage::PostUpdate,
|
CoreStage::PostUpdate,
|
||||||
parent_update_system.label(TransformSystem::ParentUpdate),
|
systems::transform_propagate_system
|
||||||
)
|
|
||||||
.add_system_to_stage(
|
|
||||||
CoreStage::PostUpdate,
|
|
||||||
transform_propagate_system::transform_propagate_system
|
|
||||||
.label(TransformSystem::TransformPropagate)
|
.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::{
|
use bevy_ecs::{
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
query::{Changed, With, Without},
|
query::{Changed, With, Without},
|
||||||
system::Query,
|
system::Query,
|
||||||
};
|
};
|
||||||
|
use bevy_hierarchy::{Children, Parent};
|
||||||
|
|
||||||
/// Update [`GlobalTransform`] component of entities based on entity hierarchy and
|
/// Update [`GlobalTransform`] component of entities based on entity hierarchy and
|
||||||
/// [`Transform`] component.
|
/// [`Transform`] component.
|
||||||
@ -24,7 +25,7 @@ pub fn transform_propagate_system(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(children) = children {
|
if let Some(children) = children {
|
||||||
for child in children.0.iter() {
|
for child in children.iter() {
|
||||||
propagate_recursive(
|
propagate_recursive(
|
||||||
&global_transform,
|
&global_transform,
|
||||||
&changed_transform_query,
|
&changed_transform_query,
|
||||||
@ -60,7 +61,7 @@ fn propagate_recursive(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Ok(Some(children)) = children_query.get(entity) {
|
if let Ok(Some(children)) = children_query.get(entity) {
|
||||||
for child in children.0.iter() {
|
for child in children.iter() {
|
||||||
propagate_recursive(
|
propagate_recursive(
|
||||||
&global_matrix,
|
&global_matrix,
|
||||||
changed_transform_query,
|
changed_transform_query,
|
||||||
@ -81,10 +82,11 @@ mod test {
|
|||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::*;
|
use crate::components::{GlobalTransform, Transform};
|
||||||
use crate::{
|
use crate::systems::transform_propagate_system;
|
||||||
hierarchy::{parent_update_system, BuildChildren, BuildWorldChildren},
|
use crate::TransformBundle;
|
||||||
TransformBundle,
|
use bevy_hierarchy::{
|
||||||
|
parent_update_system, BuildChildren, BuildWorldChildren, Children, Parent,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[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)
|
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_core_pipeline = { path = "../bevy_core_pipeline", version = "0.6.0" }
|
||||||
bevy_derive = { path = "../bevy_derive", version = "0.6.0" }
|
bevy_derive = { path = "../bevy_derive", version = "0.6.0" }
|
||||||
bevy_ecs = { path = "../bevy_ecs", 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_input = { path = "../bevy_input", version = "0.6.0" }
|
||||||
bevy_log = { path = "../bevy_log", version = "0.6.0" }
|
bevy_log = { path = "../bevy_log", version = "0.6.0" }
|
||||||
bevy_math = { path = "../bevy_math", 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},
|
query::{Changed, FilterFetch, With, Without, WorldQuery},
|
||||||
system::{Query, Res, ResMut},
|
system::{Query, Res, ResMut},
|
||||||
};
|
};
|
||||||
|
use bevy_hierarchy::{Children, Parent};
|
||||||
use bevy_log::warn;
|
use bevy_log::warn;
|
||||||
use bevy_math::Vec2;
|
use bevy_math::Vec2;
|
||||||
use bevy_transform::prelude::{Children, Parent, Transform};
|
use bevy_transform::components::Transform;
|
||||||
use bevy_utils::HashMap;
|
use bevy_utils::HashMap;
|
||||||
use bevy_window::{Window, WindowId, WindowScaleFactorChanged, Windows};
|
use bevy_window::{Window, WindowId, WindowScaleFactorChanged, Windows};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -8,12 +8,10 @@ use bevy_ecs::{
|
|||||||
query::{With, Without},
|
query::{With, Without},
|
||||||
system::{Commands, Query},
|
system::{Commands, Query},
|
||||||
};
|
};
|
||||||
|
use bevy_hierarchy::{Children, Parent};
|
||||||
use bevy_math::Vec2;
|
use bevy_math::Vec2;
|
||||||
use bevy_sprite::Rect;
|
use bevy_sprite::Rect;
|
||||||
use bevy_transform::{
|
use bevy_transform::components::{GlobalTransform, Transform};
|
||||||
components::GlobalTransform,
|
|
||||||
prelude::{Children, Parent, Transform},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// The resolution of Z values for UI
|
/// The resolution of Z values for UI
|
||||||
pub const UI_Z_STEP: f32 = 0.001;
|
pub const UI_Z_STEP: f32 = 0.001;
|
||||||
@ -141,7 +139,8 @@ mod tests {
|
|||||||
system::{CommandQueue, Commands},
|
system::{CommandQueue, Commands},
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
use bevy_transform::{components::Transform, hierarchy::BuildChildren};
|
use bevy_hierarchy::BuildChildren;
|
||||||
|
use bevy_transform::components::Transform;
|
||||||
|
|
||||||
use crate::Node;
|
use crate::Node;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user