Parent -> ChildOf (#17427)
Fixes #17412 ## Objective `Parent` uses the "has a X" naming convention. There is increasing sentiment that we should use the "is a X" naming convention for relationships (following #17398). This leaves `Children` as-is because there is prevailing sentiment that `Children` is clearer than `ParentOf` in many cases (especially when treating it like a collection). This renames `Parent` to `ChildOf`. This is just the implementation PR. To discuss the path forward, do so in #17412. ## Migration Guide - The `Parent` component has been renamed to `ChildOf`.
This commit is contained in:
parent
000c362de0
commit
ba5e71f53d
@ -3,7 +3,7 @@ use core::hint::black_box;
|
|||||||
use benches::bench;
|
use benches::bench;
|
||||||
use bevy_ecs::bundle::Bundle;
|
use bevy_ecs::bundle::Bundle;
|
||||||
use bevy_ecs::component::ComponentCloneHandler;
|
use bevy_ecs::component::ComponentCloneHandler;
|
||||||
use bevy_ecs::hierarchy::Parent;
|
use bevy_ecs::hierarchy::ChildOf;
|
||||||
use bevy_ecs::reflect::AppTypeRegistry;
|
use bevy_ecs::reflect::AppTypeRegistry;
|
||||||
use bevy_ecs::{component::Component, world::World};
|
use bevy_ecs::{component::Component, world::World};
|
||||||
use bevy_math::Mat4;
|
use bevy_math::Mat4;
|
||||||
@ -142,7 +142,7 @@ fn bench_clone_hierarchy<B: Bundle + Default + GetTypeRegistration>(
|
|||||||
|
|
||||||
for parent_id in current_hierarchy_level {
|
for parent_id in current_hierarchy_level {
|
||||||
for _ in 0..children {
|
for _ in 0..children {
|
||||||
let child_id = world.spawn((B::default(), Parent(parent_id))).id();
|
let child_id = world.spawn((B::default(), ChildOf(parent_id))).id();
|
||||||
hierarchy_level.push(child_id);
|
hierarchy_level.push(child_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ pub fn event_propagation(criterion: &mut Criterion) {
|
|||||||
struct TestEvent<const N: usize> {}
|
struct TestEvent<const N: usize> {}
|
||||||
|
|
||||||
impl<const N: usize> Event for TestEvent<N> {
|
impl<const N: usize> Event for TestEvent<N> {
|
||||||
type Traversal = &'static Parent;
|
type Traversal = &'static ChildOf;
|
||||||
const AUTO_PROPAGATE: bool = true;
|
const AUTO_PROPAGATE: bool = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ impl Default for App {
|
|||||||
{
|
{
|
||||||
app.init_resource::<AppTypeRegistry>();
|
app.init_resource::<AppTypeRegistry>();
|
||||||
app.register_type::<Name>();
|
app.register_type::<Name>();
|
||||||
app.register_type::<Parent>();
|
app.register_type::<ChildOf>();
|
||||||
app.register_type::<Children>();
|
app.register_type::<Children>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ use crate::{
|
|||||||
bundle::Bundle,
|
bundle::Bundle,
|
||||||
component::{Component, ComponentCloneHandler, ComponentId, ComponentInfo, Components},
|
component::{Component, ComponentCloneHandler, ComponentId, ComponentInfo, Components},
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
hierarchy::{Children, Parent},
|
hierarchy::{ChildOf, Children},
|
||||||
query::DebugCheckedUnwrap,
|
query::DebugCheckedUnwrap,
|
||||||
world::{DeferredWorld, World},
|
world::{DeferredWorld, World},
|
||||||
};
|
};
|
||||||
@ -631,11 +631,11 @@ impl<'w> EntityCloneBuilder<'w> {
|
|||||||
/// Sets the option to add cloned entity as a child to the parent entity.
|
/// Sets the option to add cloned entity as a child to the parent entity.
|
||||||
pub fn as_child(&mut self, as_child: bool) -> &mut Self {
|
pub fn as_child(&mut self, as_child: bool) -> &mut Self {
|
||||||
if as_child {
|
if as_child {
|
||||||
self.override_component_clone_handler::<Parent>(ComponentCloneHandler::custom_handler(
|
self.override_component_clone_handler::<ChildOf>(ComponentCloneHandler::custom_handler(
|
||||||
component_clone_parent,
|
component_clone_parent,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
self.remove_component_clone_handler_override::<Parent>()
|
self.remove_component_clone_handler_override::<ChildOf>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -694,18 +694,21 @@ fn component_clone_children(world: &mut DeferredWorld, ctx: &mut ComponentCloneC
|
|||||||
.with_source_and_target(*child, child_clone);
|
.with_source_and_target(*child, child_clone);
|
||||||
world.commands().queue(move |world: &mut World| {
|
world.commands().queue(move |world: &mut World| {
|
||||||
clone_entity.clone_entity(world);
|
clone_entity.clone_entity(world);
|
||||||
world.entity_mut(child_clone).insert(Parent(parent));
|
world.entity_mut(child_clone).insert(ChildOf(parent));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clone handler for the [`Parent`] component. Allows to add clone as a child to the parent entity.
|
/// Clone handler for the [`ChildOf`] component. Allows to add clone as a child to the parent entity.
|
||||||
fn component_clone_parent(world: &mut DeferredWorld, ctx: &mut ComponentCloneCtx) {
|
fn component_clone_parent(world: &mut DeferredWorld, ctx: &mut ComponentCloneCtx) {
|
||||||
let parent = ctx
|
let parent = ctx
|
||||||
.read_source_component::<Parent>()
|
.read_source_component::<ChildOf>()
|
||||||
.map(|p| p.0)
|
.map(|p| p.0)
|
||||||
.expect("Source entity must have Parent component");
|
.expect("Source entity must have a ChildOf component");
|
||||||
world.commands().entity(ctx.target()).insert(Parent(parent));
|
world
|
||||||
|
.commands()
|
||||||
|
.entity(ctx.target())
|
||||||
|
.insert(ChildOf(parent));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! The canonical "parent-child" [`Relationship`] for entities, driven by
|
//! The canonical "parent-child" [`Relationship`] for entities, driven by
|
||||||
//! the [`Parent`] [`Relationship`] and the [`Children`] [`RelationshipTarget`].
|
//! the [`ChildOf`] [`Relationship`] and the [`Children`] [`RelationshipTarget`].
|
||||||
//!
|
//!
|
||||||
//! See [`Parent`] for a full description of the relationship and how to use it.
|
//! See [`ChildOf`] for a full description of the relationship and how to use it.
|
||||||
//!
|
//!
|
||||||
//! [`Relationship`]: crate::relationship::Relationship
|
//! [`Relationship`]: crate::relationship::Relationship
|
||||||
//! [`RelationshipTarget`]: crate::relationship::RelationshipTarget
|
//! [`RelationshipTarget`]: crate::relationship::RelationshipTarget
|
||||||
@ -38,32 +38,32 @@ use log::warn;
|
|||||||
/// 3. Ensuring a hierarchy is despawned when an entity is despawned.
|
/// 3. Ensuring a hierarchy is despawned when an entity is despawned.
|
||||||
/// 4.
|
/// 4.
|
||||||
///
|
///
|
||||||
/// [`Parent`] contains a single "target" [`Entity`]. When [`Parent`] is inserted on a "source" entity,
|
/// [`ChildOf`] contains a single "target" [`Entity`]. When [`ChildOf`] is inserted on a "source" entity,
|
||||||
/// the "target" entity will automatically (and immediately, via a component hook) have a [`Children`]
|
/// the "target" entity will automatically (and immediately, via a component hook) have a [`Children`]
|
||||||
/// component inserted, and the "source" entity will be added to that [`Children`] instance.
|
/// component inserted, and the "source" entity will be added to that [`Children`] instance.
|
||||||
///
|
///
|
||||||
/// If the [`Parent`] component is replaced with a different "target" entity, the old target's [`Children`]
|
/// If the [`ChildOf`] component is replaced with a different "target" entity, the old target's [`Children`]
|
||||||
/// will be automatically (and immediately, via a component hook) be updated to reflect that change.
|
/// will be automatically (and immediately, via a component hook) be updated to reflect that change.
|
||||||
///
|
///
|
||||||
/// Likewise, when the [`Parent`] component is removed, the "source" entity will be removed from the old
|
/// Likewise, when the [`ChildOf`] component is removed, the "source" entity will be removed from the old
|
||||||
/// target's [`Children`]. If this results in [`Children`] being empty, [`Children`] will be automatically removed.
|
/// target's [`Children`]. If this results in [`Children`] being empty, [`Children`] will be automatically removed.
|
||||||
///
|
///
|
||||||
/// When a parent is despawned, all children (and their descendants) will _also_ be despawned.
|
/// When a parent is despawned, all children (and their descendants) will _also_ be despawned.
|
||||||
///
|
///
|
||||||
/// You can create parent-child relationships in a variety of ways. The most direct way is to insert a [`Parent`] component:
|
/// You can create parent-child relationships in a variety of ways. The most direct way is to insert a [`ChildOf`] component:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use bevy_ecs::prelude::*;
|
/// # use bevy_ecs::prelude::*;
|
||||||
/// # let mut world = World::new();
|
/// # let mut world = World::new();
|
||||||
/// let root = world.spawn_empty().id();
|
/// let root = world.spawn_empty().id();
|
||||||
/// let child1 = world.spawn(Parent(root)).id();
|
/// let child1 = world.spawn(ChildOf(root)).id();
|
||||||
/// let child2 = world.spawn(Parent(root)).id();
|
/// let child2 = world.spawn(ChildOf(root)).id();
|
||||||
/// let grandchild = world.spawn(Parent(child1)).id();
|
/// let grandchild = world.spawn(ChildOf(child1)).id();
|
||||||
///
|
///
|
||||||
/// assert_eq!(&**world.entity(root).get::<Children>().unwrap(), &[child1, child2]);
|
/// assert_eq!(&**world.entity(root).get::<Children>().unwrap(), &[child1, child2]);
|
||||||
/// assert_eq!(&**world.entity(child1).get::<Children>().unwrap(), &[grandchild]);
|
/// assert_eq!(&**world.entity(child1).get::<Children>().unwrap(), &[grandchild]);
|
||||||
///
|
///
|
||||||
/// world.entity_mut(child2).remove::<Parent>();
|
/// world.entity_mut(child2).remove::<ChildOf>();
|
||||||
/// assert_eq!(&**world.entity(root).get::<Children>().unwrap(), &[child1]);
|
/// assert_eq!(&**world.entity(root).get::<Children>().unwrap(), &[child1]);
|
||||||
///
|
///
|
||||||
/// world.entity_mut(root).despawn();
|
/// world.entity_mut(root).despawn();
|
||||||
@ -105,16 +105,16 @@ use log::warn;
|
|||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
#[relationship(relationship_target = Children)]
|
#[relationship(relationship_target = Children)]
|
||||||
pub struct Parent(pub Entity);
|
pub struct ChildOf(pub Entity);
|
||||||
|
|
||||||
impl Parent {
|
impl ChildOf {
|
||||||
/// Returns the "target" entity.
|
/// Returns the "target" entity.
|
||||||
pub fn get(&self) -> Entity {
|
pub fn get(&self) -> Entity {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for Parent {
|
impl Deref for ChildOf {
|
||||||
type Target = Entity;
|
type Target = Entity;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -123,24 +123,24 @@ impl Deref for Parent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: We need to impl either FromWorld or Default so Parent can be registered as Reflect.
|
// TODO: We need to impl either FromWorld or Default so ChildOf can be registered as Reflect.
|
||||||
// This is because Reflect deserialize by creating an instance and apply a patch on top.
|
// This is because Reflect 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
|
// However ChildOf should only ever be set with a real user-defined entity. Its worth looking into
|
||||||
// better ways to handle cases like this.
|
// better ways to handle cases like this.
|
||||||
impl FromWorld for Parent {
|
impl FromWorld for ChildOf {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from_world(_world: &mut World) -> Self {
|
fn from_world(_world: &mut World) -> Self {
|
||||||
Parent(Entity::PLACEHOLDER)
|
ChildOf(Entity::PLACEHOLDER)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`RelationshipTarget`](crate::relationship::RelationshipTarget) collection component that is populated
|
/// A [`RelationshipTarget`](crate::relationship::RelationshipTarget) collection component that is populated
|
||||||
/// with entities that "target" this entity with the [`Parent`] [`Relationship`](crate::relationship::Relationship) component.
|
/// with entities that "target" this entity with the [`ChildOf`] [`Relationship`](crate::relationship::Relationship) component.
|
||||||
///
|
///
|
||||||
/// Together, these components form the "canonical parent-child hierarchy". See the [`Parent`] component for all full
|
/// Together, these components form the "canonical parent-child hierarchy". See the [`ChildOf`] component for all full
|
||||||
/// description of this relationship and instructions on how to use it.
|
/// description of this relationship and instructions on how to use it.
|
||||||
#[derive(Component, Default, VisitEntitiesMut, Debug, PartialEq, Eq)]
|
#[derive(Component, Default, VisitEntitiesMut, Debug, PartialEq, Eq)]
|
||||||
#[relationship_target(relationship = Parent, despawn_descendants)]
|
#[relationship_target(relationship = ChildOf, despawn_descendants)]
|
||||||
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
|
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "bevy_reflect",
|
feature = "bevy_reflect",
|
||||||
@ -167,14 +167,14 @@ impl Deref for Children {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type alias over [`RelatedSpawner`] used to spawn child entities containing a [`Parent`] relationship.
|
/// A type alias over [`RelatedSpawner`] used to spawn child entities containing a [`ChildOf`] relationship.
|
||||||
pub type ChildSpawner<'w> = RelatedSpawner<'w, Parent>;
|
pub type ChildSpawner<'w> = RelatedSpawner<'w, ChildOf>;
|
||||||
|
|
||||||
/// A type alias over [`RelatedSpawnerCommands`] used to spawn child entities containing a [`Parent`] relationship.
|
/// A type alias over [`RelatedSpawnerCommands`] used to spawn child entities containing a [`ChildOf`] relationship.
|
||||||
pub type ChildSpawnerCommands<'w> = RelatedSpawnerCommands<'w, Parent>;
|
pub type ChildSpawnerCommands<'w> = RelatedSpawnerCommands<'w, ChildOf>;
|
||||||
|
|
||||||
impl<'w> EntityWorldMut<'w> {
|
impl<'w> EntityWorldMut<'w> {
|
||||||
/// Spawns children of this entity (with a [`Parent`] relationship) by taking a function that operates on a [`ChildSpawner`].
|
/// Spawns children of this entity (with a [`ChildOf`] relationship) by taking a function that operates on a [`ChildSpawner`].
|
||||||
pub fn with_children(&mut self, func: impl FnOnce(&mut ChildSpawner)) -> &mut Self {
|
pub fn with_children(&mut self, func: impl FnOnce(&mut ChildSpawner)) -> &mut Self {
|
||||||
self.with_related(func);
|
self.with_related(func);
|
||||||
self
|
self
|
||||||
@ -182,12 +182,12 @@ impl<'w> EntityWorldMut<'w> {
|
|||||||
|
|
||||||
/// Adds the given children to this entity
|
/// Adds the given children to this entity
|
||||||
pub fn add_children(&mut self, children: &[Entity]) -> &mut Self {
|
pub fn add_children(&mut self, children: &[Entity]) -> &mut Self {
|
||||||
self.add_related::<Parent>(children)
|
self.add_related::<ChildOf>(children)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds the given child to this entity
|
/// Adds the given child to this entity
|
||||||
pub fn add_child(&mut self, child: Entity) -> &mut Self {
|
pub fn add_child(&mut self, child: Entity) -> &mut Self {
|
||||||
self.add_related::<Parent>(&[child])
|
self.add_related::<ChildOf>(&[child])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spawns the passed bundle and adds it to this entity as a child.
|
/// Spawns the passed bundle and adds it to this entity as a child.
|
||||||
@ -198,31 +198,31 @@ impl<'w> EntityWorldMut<'w> {
|
|||||||
pub fn with_child(&mut self, bundle: impl Bundle) -> &mut Self {
|
pub fn with_child(&mut self, bundle: impl Bundle) -> &mut Self {
|
||||||
let id = self.id();
|
let id = self.id();
|
||||||
self.world_scope(|world| {
|
self.world_scope(|world| {
|
||||||
world.spawn((bundle, Parent(id)));
|
world.spawn((bundle, ChildOf(id)));
|
||||||
});
|
});
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes the [`Parent`] component, if it exists.
|
/// Removes the [`ChildOf`] component, if it exists.
|
||||||
#[deprecated(since = "0.16.0", note = "Use entity_mut.remove::<Parent>()")]
|
#[deprecated(since = "0.16.0", note = "Use entity_mut.remove::<ChildOf>()")]
|
||||||
pub fn remove_parent(&mut self) -> &mut Self {
|
pub fn remove_parent(&mut self) -> &mut Self {
|
||||||
self.remove::<Parent>();
|
self.remove::<ChildOf>();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts the [`Parent`] component with the given `parent` entity, if it exists.
|
/// Inserts the [`ChildOf`] component with the given `parent` entity, if it exists.
|
||||||
#[deprecated(since = "0.16.0", note = "Use entity_mut.insert(Parent(entity))")]
|
#[deprecated(since = "0.16.0", note = "Use entity_mut.insert(ChildOf(entity))")]
|
||||||
pub fn set_parent(&mut self, parent: Entity) -> &mut Self {
|
pub fn set_parent(&mut self, parent: Entity) -> &mut Self {
|
||||||
self.insert(Parent(parent));
|
self.insert(ChildOf(parent));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> EntityCommands<'a> {
|
impl<'a> EntityCommands<'a> {
|
||||||
/// Spawns children of this entity (with a [`Parent`] relationship) by taking a function that operates on a [`ChildSpawner`].
|
/// Spawns children of this entity (with a [`ChildOf`] relationship) by taking a function that operates on a [`ChildSpawner`].
|
||||||
pub fn with_children(
|
pub fn with_children(
|
||||||
&mut self,
|
&mut self,
|
||||||
func: impl FnOnce(&mut RelatedSpawnerCommands<Parent>),
|
func: impl FnOnce(&mut RelatedSpawnerCommands<ChildOf>),
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.with_related(func);
|
self.with_related(func);
|
||||||
self
|
self
|
||||||
@ -230,12 +230,12 @@ impl<'a> EntityCommands<'a> {
|
|||||||
|
|
||||||
/// Adds the given children to this entity
|
/// Adds the given children to this entity
|
||||||
pub fn add_children(&mut self, children: &[Entity]) -> &mut Self {
|
pub fn add_children(&mut self, children: &[Entity]) -> &mut Self {
|
||||||
self.add_related::<Parent>(children)
|
self.add_related::<ChildOf>(children)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds the given child to this entity
|
/// Adds the given child to this entity
|
||||||
pub fn add_child(&mut self, child: Entity) -> &mut Self {
|
pub fn add_child(&mut self, child: Entity) -> &mut Self {
|
||||||
self.add_related::<Parent>(&[child])
|
self.add_related::<ChildOf>(&[child])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Spawns the passed bundle and adds it to this entity as a child.
|
/// Spawns the passed bundle and adds it to this entity as a child.
|
||||||
@ -245,21 +245,21 @@ impl<'a> EntityCommands<'a> {
|
|||||||
/// [`with_children`]: EntityCommands::with_children
|
/// [`with_children`]: EntityCommands::with_children
|
||||||
pub fn with_child(&mut self, bundle: impl Bundle) -> &mut Self {
|
pub fn with_child(&mut self, bundle: impl Bundle) -> &mut Self {
|
||||||
let id = self.id();
|
let id = self.id();
|
||||||
self.commands.spawn((bundle, Parent(id)));
|
self.commands.spawn((bundle, ChildOf(id)));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes the [`Parent`] component, if it exists.
|
/// Removes the [`ChildOf`] component, if it exists.
|
||||||
#[deprecated(since = "0.16.0", note = "Use entity_commands.remove::<Parent>()")]
|
#[deprecated(since = "0.16.0", note = "Use entity_commands.remove::<ChildOf>()")]
|
||||||
pub fn remove_parent(&mut self) -> &mut Self {
|
pub fn remove_parent(&mut self) -> &mut Self {
|
||||||
self.remove::<Parent>();
|
self.remove::<ChildOf>();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts the [`Parent`] component with the given `parent` entity, if it exists.
|
/// Inserts the [`ChildOf`] component with the given `parent` entity, if it exists.
|
||||||
#[deprecated(since = "0.16.0", note = "Use entity_commands.insert(Parent(entity))")]
|
#[deprecated(since = "0.16.0", note = "Use entity_commands.insert(ChildOf(entity))")]
|
||||||
pub fn set_parent(&mut self, parent: Entity) -> &mut Self {
|
pub fn set_parent(&mut self, parent: Entity) -> &mut Self {
|
||||||
self.insert(Parent(parent));
|
self.insert(ChildOf(parent));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -272,7 +272,7 @@ pub fn validate_parent_has_component<C: Component>(
|
|||||||
_: ComponentId,
|
_: ComponentId,
|
||||||
) {
|
) {
|
||||||
let entity_ref = world.entity(entity);
|
let entity_ref = world.entity(entity);
|
||||||
let Some(child_of) = entity_ref.get::<Parent>() else {
|
let Some(child_of) = entity_ref.get::<ChildOf>() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if !world
|
if !world
|
||||||
@ -297,7 +297,7 @@ pub fn validate_parent_has_component<C: Component>(
|
|||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
hierarchy::{Children, Parent},
|
hierarchy::{ChildOf, Children},
|
||||||
relationship::RelationshipTarget,
|
relationship::RelationshipTarget,
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
@ -338,9 +338,9 @@ mod tests {
|
|||||||
fn hierarchy() {
|
fn hierarchy() {
|
||||||
let mut world = World::new();
|
let mut world = World::new();
|
||||||
let root = world.spawn_empty().id();
|
let root = world.spawn_empty().id();
|
||||||
let child1 = world.spawn(Parent(root)).id();
|
let child1 = world.spawn(ChildOf(root)).id();
|
||||||
let grandchild = world.spawn(Parent(child1)).id();
|
let grandchild = world.spawn(ChildOf(child1)).id();
|
||||||
let child2 = world.spawn(Parent(root)).id();
|
let child2 = world.spawn(ChildOf(root)).id();
|
||||||
|
|
||||||
// Spawn
|
// Spawn
|
||||||
let hierarchy = get_hierarchy(&world, root);
|
let hierarchy = get_hierarchy(&world, root);
|
||||||
@ -356,12 +356,12 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Removal
|
// Removal
|
||||||
world.entity_mut(child1).remove::<Parent>();
|
world.entity_mut(child1).remove::<ChildOf>();
|
||||||
let hierarchy = get_hierarchy(&world, root);
|
let hierarchy = get_hierarchy(&world, root);
|
||||||
assert_eq!(hierarchy, Node::new_with(root, vec![Node::new(child2)]));
|
assert_eq!(hierarchy, Node::new_with(root, vec![Node::new(child2)]));
|
||||||
|
|
||||||
// Insert
|
// Insert
|
||||||
world.entity_mut(child1).insert(Parent(root));
|
world.entity_mut(child1).insert(ChildOf(root));
|
||||||
let hierarchy = get_hierarchy(&world, root);
|
let hierarchy = get_hierarchy(&world, root);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
hierarchy,
|
hierarchy,
|
||||||
@ -420,10 +420,10 @@ mod tests {
|
|||||||
fn self_parenting_invalid() {
|
fn self_parenting_invalid() {
|
||||||
let mut world = World::new();
|
let mut world = World::new();
|
||||||
let id = world.spawn_empty().id();
|
let id = world.spawn_empty().id();
|
||||||
world.entity_mut(id).insert(Parent(id));
|
world.entity_mut(id).insert(ChildOf(id));
|
||||||
assert!(
|
assert!(
|
||||||
world.entity(id).get::<Parent>().is_none(),
|
world.entity(id).get::<ChildOf>().is_none(),
|
||||||
"invalid Parent relationships should self-remove"
|
"invalid ChildOf relationships should self-remove"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,10 +432,10 @@ mod tests {
|
|||||||
let mut world = World::new();
|
let mut world = World::new();
|
||||||
let parent = world.spawn_empty().id();
|
let parent = world.spawn_empty().id();
|
||||||
world.entity_mut(parent).despawn();
|
world.entity_mut(parent).despawn();
|
||||||
let id = world.spawn(Parent(parent)).id();
|
let id = world.spawn(ChildOf(parent)).id();
|
||||||
assert!(
|
assert!(
|
||||||
world.entity(id).get::<Parent>().is_none(),
|
world.entity(id).get::<ChildOf>().is_none(),
|
||||||
"invalid Parent relationships should self-remove"
|
"invalid ChildOf relationships should self-remove"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -443,12 +443,12 @@ mod tests {
|
|||||||
fn reinsert_same_parent() {
|
fn reinsert_same_parent() {
|
||||||
let mut world = World::new();
|
let mut world = World::new();
|
||||||
let parent = world.spawn_empty().id();
|
let parent = world.spawn_empty().id();
|
||||||
let id = world.spawn(Parent(parent)).id();
|
let id = world.spawn(ChildOf(parent)).id();
|
||||||
world.entity_mut(id).insert(Parent(parent));
|
world.entity_mut(id).insert(ChildOf(parent));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(&Parent(parent)),
|
Some(&ChildOf(parent)),
|
||||||
world.entity(id).get::<Parent>(),
|
world.entity(id).get::<ChildOf>(),
|
||||||
"Parent should still be there"
|
"ChildOf should still be there"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ pub mod prelude {
|
|||||||
component::{require, Component},
|
component::{require, Component},
|
||||||
entity::{Entity, EntityBorrow, EntityMapper},
|
entity::{Entity, EntityBorrow, EntityMapper},
|
||||||
event::{Event, EventMutator, EventReader, EventWriter, Events},
|
event::{Event, EventMutator, EventReader, EventWriter, Events},
|
||||||
hierarchy::{ChildSpawner, ChildSpawnerCommands, Children, Parent},
|
hierarchy::{ChildOf, ChildSpawner, ChildSpawnerCommands, Children},
|
||||||
name::{Name, NameOrEntity},
|
name::{Name, NameOrEntity},
|
||||||
observer::{CloneEntityWithObserversExt, Observer, Trigger},
|
observer::{CloneEntityWithObserversExt, Observer, Trigger},
|
||||||
query::{Added, AnyOf, Changed, Has, Or, QueryBuilder, QueryState, With, Without},
|
query::{Added, AnyOf, Changed, Has, Or, QueryBuilder, QueryState, With, Without},
|
||||||
|
@ -800,9 +800,9 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
struct Parent(Entity);
|
struct ChildOf(Entity);
|
||||||
|
|
||||||
impl<D> Traversal<D> for &'_ Parent {
|
impl<D> Traversal<D> for &'_ ChildOf {
|
||||||
fn traverse(item: Self::Item<'_>, _: &D) -> Option<Entity> {
|
fn traverse(item: Self::Item<'_>, _: &D) -> Option<Entity> {
|
||||||
Some(item.0)
|
Some(item.0)
|
||||||
}
|
}
|
||||||
@ -812,7 +812,7 @@ mod tests {
|
|||||||
struct EventPropagating;
|
struct EventPropagating;
|
||||||
|
|
||||||
impl Event for EventPropagating {
|
impl Event for EventPropagating {
|
||||||
type Traversal = &'static Parent;
|
type Traversal = &'static ChildOf;
|
||||||
|
|
||||||
const AUTO_PROPAGATE: bool = true;
|
const AUTO_PROPAGATE: bool = true;
|
||||||
}
|
}
|
||||||
@ -1198,7 +1198,7 @@ mod tests {
|
|||||||
.id();
|
.id();
|
||||||
|
|
||||||
let child = world
|
let child = world
|
||||||
.spawn(Parent(parent))
|
.spawn(ChildOf(parent))
|
||||||
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
|
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
|
||||||
res.observed("child");
|
res.observed("child");
|
||||||
})
|
})
|
||||||
@ -1225,7 +1225,7 @@ mod tests {
|
|||||||
.id();
|
.id();
|
||||||
|
|
||||||
let child = world
|
let child = world
|
||||||
.spawn(Parent(parent))
|
.spawn(ChildOf(parent))
|
||||||
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
|
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
|
||||||
res.observed("child");
|
res.observed("child");
|
||||||
})
|
})
|
||||||
@ -1255,7 +1255,7 @@ mod tests {
|
|||||||
.id();
|
.id();
|
||||||
|
|
||||||
let child = world
|
let child = world
|
||||||
.spawn(Parent(parent))
|
.spawn(ChildOf(parent))
|
||||||
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
|
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
|
||||||
res.observed("child");
|
res.observed("child");
|
||||||
})
|
})
|
||||||
@ -1285,7 +1285,7 @@ mod tests {
|
|||||||
.id();
|
.id();
|
||||||
|
|
||||||
let child = world
|
let child = world
|
||||||
.spawn(Parent(parent))
|
.spawn(ChildOf(parent))
|
||||||
.observe(
|
.observe(
|
||||||
|mut trigger: Trigger<EventPropagating>, mut res: ResMut<Order>| {
|
|mut trigger: Trigger<EventPropagating>, mut res: ResMut<Order>| {
|
||||||
res.observed("child");
|
res.observed("child");
|
||||||
@ -1315,14 +1315,14 @@ mod tests {
|
|||||||
.id();
|
.id();
|
||||||
|
|
||||||
let child_a = world
|
let child_a = world
|
||||||
.spawn(Parent(parent))
|
.spawn(ChildOf(parent))
|
||||||
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
|
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
|
||||||
res.observed("child_a");
|
res.observed("child_a");
|
||||||
})
|
})
|
||||||
.id();
|
.id();
|
||||||
|
|
||||||
let child_b = world
|
let child_b = world
|
||||||
.spawn(Parent(parent))
|
.spawn(ChildOf(parent))
|
||||||
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
|
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
|
||||||
res.observed("child_b");
|
res.observed("child_b");
|
||||||
})
|
})
|
||||||
@ -1372,7 +1372,7 @@ mod tests {
|
|||||||
.id();
|
.id();
|
||||||
|
|
||||||
let child_a = world
|
let child_a = world
|
||||||
.spawn(Parent(parent_a))
|
.spawn(ChildOf(parent_a))
|
||||||
.observe(
|
.observe(
|
||||||
|mut trigger: Trigger<EventPropagating>, mut res: ResMut<Order>| {
|
|mut trigger: Trigger<EventPropagating>, mut res: ResMut<Order>| {
|
||||||
res.observed("child_a");
|
res.observed("child_a");
|
||||||
@ -1389,7 +1389,7 @@ mod tests {
|
|||||||
.id();
|
.id();
|
||||||
|
|
||||||
let child_b = world
|
let child_b = world
|
||||||
.spawn(Parent(parent_b))
|
.spawn(ChildOf(parent_b))
|
||||||
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
|
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
|
||||||
res.observed("child_b");
|
res.observed("child_b");
|
||||||
})
|
})
|
||||||
@ -1416,8 +1416,8 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let grandparent = world.spawn_empty().id();
|
let grandparent = world.spawn_empty().id();
|
||||||
let parent = world.spawn(Parent(grandparent)).id();
|
let parent = world.spawn(ChildOf(grandparent)).id();
|
||||||
let child = world.spawn(Parent(parent)).id();
|
let child = world.spawn(ChildOf(parent)).id();
|
||||||
|
|
||||||
// TODO: ideally this flush is not necessary, but right now observe() returns WorldEntityMut
|
// TODO: ideally this flush is not necessary, but right now observe() returns WorldEntityMut
|
||||||
// and therefore does not automatically flush.
|
// and therefore does not automatically flush.
|
||||||
@ -1441,8 +1441,8 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let grandparent = world.spawn(A).id();
|
let grandparent = world.spawn(A).id();
|
||||||
let parent = world.spawn(Parent(grandparent)).id();
|
let parent = world.spawn(ChildOf(grandparent)).id();
|
||||||
let child = world.spawn((A, Parent(parent))).id();
|
let child = world.spawn((A, ChildOf(parent))).id();
|
||||||
|
|
||||||
// TODO: ideally this flush is not necessary, but right now observe() returns WorldEntityMut
|
// TODO: ideally this flush is not necessary, but right now observe() returns WorldEntityMut
|
||||||
// and therefore does not automatically flush.
|
// and therefore does not automatically flush.
|
||||||
|
@ -28,7 +28,7 @@ use log::warn;
|
|||||||
/// component is inserted on an [`Entity`], the corresponding [`RelationshipTarget`] component is immediately inserted on the target component if it does
|
/// component is inserted on an [`Entity`], the corresponding [`RelationshipTarget`] component is immediately inserted on the target component if it does
|
||||||
/// not already exist, and the "source" entity is automatically added to the [`RelationshipTarget`] collection (this is done via "component hooks").
|
/// not already exist, and the "source" entity is automatically added to the [`RelationshipTarget`] collection (this is done via "component hooks").
|
||||||
///
|
///
|
||||||
/// A common example of a [`Relationship`] is the parent / child relationship. Bevy ECS includes a canonical form of this via the [`Parent`](crate::hierarchy::Parent)
|
/// A common example of a [`Relationship`] is the parent / child relationship. Bevy ECS includes a canonical form of this via the [`ChildOf`](crate::hierarchy::ChildOf)
|
||||||
/// [`Relationship`] and the [`Children`](crate::hierarchy::Children) [`RelationshipTarget`].
|
/// [`Relationship`] and the [`Children`](crate::hierarchy::Children) [`RelationshipTarget`].
|
||||||
///
|
///
|
||||||
/// [`Relationship`] and [`RelationshipTarget`] should always be derived via the [`Component`] trait to ensure the hooks are set up properly.
|
/// [`Relationship`] and [`RelationshipTarget`] should always be derived via the [`Component`] trait to ensure the hooks are set up properly.
|
||||||
@ -38,10 +38,10 @@ use log::warn;
|
|||||||
/// # use bevy_ecs::entity::Entity;
|
/// # use bevy_ecs::entity::Entity;
|
||||||
/// #[derive(Component)]
|
/// #[derive(Component)]
|
||||||
/// #[relationship(relationship_target = Children)]
|
/// #[relationship(relationship_target = Children)]
|
||||||
/// pub struct Parent(pub Entity);
|
/// pub struct ChildOf(pub Entity);
|
||||||
///
|
///
|
||||||
/// #[derive(Component)]
|
/// #[derive(Component)]
|
||||||
/// #[relationship_target(relationship = Parent)]
|
/// #[relationship_target(relationship = ChildOf)]
|
||||||
/// pub struct Children(Vec<Entity>);
|
/// pub struct Children(Vec<Entity>);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
@ -53,10 +53,10 @@ use log::warn;
|
|||||||
/// # use bevy_ecs::entity::Entity;
|
/// # use bevy_ecs::entity::Entity;
|
||||||
/// #[derive(Component)]
|
/// #[derive(Component)]
|
||||||
/// #[relationship(relationship_target = Children)]
|
/// #[relationship(relationship_target = Children)]
|
||||||
/// pub struct Parent(pub Entity);
|
/// pub struct ChildOf(pub Entity);
|
||||||
///
|
///
|
||||||
/// #[derive(Component)]
|
/// #[derive(Component)]
|
||||||
/// #[relationship_target(relationship = Parent, despawn_descendants)]
|
/// #[relationship_target(relationship = ChildOf, despawn_descendants)]
|
||||||
/// pub struct Children(Vec<Entity>);
|
/// pub struct Children(Vec<Entity>);
|
||||||
/// ```
|
/// ```
|
||||||
pub trait Relationship: Component + Sized {
|
pub trait Relationship: Component + Sized {
|
||||||
|
@ -144,7 +144,7 @@ impl<E: Event + Clone> Event for FocusedInput<E> {
|
|||||||
#[derive(QueryData)]
|
#[derive(QueryData)]
|
||||||
/// These are for accessing components defined on the targeted entity
|
/// These are for accessing components defined on the targeted entity
|
||||||
pub struct WindowTraversal {
|
pub struct WindowTraversal {
|
||||||
parent: Option<&'static Parent>,
|
parent: Option<&'static ChildOf>,
|
||||||
window: Option<&'static Window>,
|
window: Option<&'static Window>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,7 +279,7 @@ pub trait IsFocused {
|
|||||||
/// When working with the entire [`World`], consider using the [`IsFocused`] instead.
|
/// When working with the entire [`World`], consider using the [`IsFocused`] instead.
|
||||||
#[derive(SystemParam)]
|
#[derive(SystemParam)]
|
||||||
pub struct IsFocusedHelper<'w, 's> {
|
pub struct IsFocusedHelper<'w, 's> {
|
||||||
parent_query: Query<'w, 's, &'static Parent>,
|
parent_query: Query<'w, 's, &'static ChildOf>,
|
||||||
input_focus: Option<Res<'w, InputFocus>>,
|
input_focus: Option<Res<'w, InputFocus>>,
|
||||||
input_focus_visible: Option<Res<'w, InputFocusVisible>>,
|
input_focus_visible: Option<Res<'w, InputFocusVisible>>,
|
||||||
}
|
}
|
||||||
@ -327,7 +327,7 @@ impl IsFocused for World {
|
|||||||
if e == entity {
|
if e == entity {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if let Some(parent) = self.entity(e).get::<Parent>().map(Parent::get) {
|
if let Some(parent) = self.entity(e).get::<ChildOf>().map(ChildOf::get) {
|
||||||
e = parent;
|
e = parent;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -29,7 +29,7 @@ use bevy_ecs::prelude::ReflectComponent;
|
|||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
component::Component,
|
component::Component,
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
hierarchy::{Children, Parent},
|
hierarchy::{ChildOf, Children},
|
||||||
observer::Trigger,
|
observer::Trigger,
|
||||||
query::{With, Without},
|
query::{With, Without},
|
||||||
system::{Commands, Query, Res, ResMut, SystemParam},
|
system::{Commands, Query, Res, ResMut, SystemParam},
|
||||||
@ -157,7 +157,7 @@ pub struct TabNavigation<'w, 's> {
|
|||||||
Without<TabGroup>,
|
Without<TabGroup>,
|
||||||
>,
|
>,
|
||||||
// Query for parents.
|
// Query for parents.
|
||||||
parent_query: Query<'w, 's, &'static Parent>,
|
parent_query: Query<'w, 's, &'static ChildOf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TabNavigation<'_, '_> {
|
impl TabNavigation<'_, '_> {
|
||||||
@ -371,8 +371,8 @@ mod tests {
|
|||||||
let world = app.world_mut();
|
let world = app.world_mut();
|
||||||
|
|
||||||
let tab_group_entity = world.spawn(TabGroup::new(0)).id();
|
let tab_group_entity = world.spawn(TabGroup::new(0)).id();
|
||||||
let tab_entity_1 = world.spawn((TabIndex(0), Parent(tab_group_entity))).id();
|
let tab_entity_1 = world.spawn((TabIndex(0), ChildOf(tab_group_entity))).id();
|
||||||
let tab_entity_2 = world.spawn((TabIndex(1), Parent(tab_group_entity))).id();
|
let tab_entity_2 = world.spawn((TabIndex(1), ChildOf(tab_group_entity))).id();
|
||||||
|
|
||||||
let mut system_state: SystemState<TabNavigation> = SystemState::new(world);
|
let mut system_state: SystemState<TabNavigation> = SystemState::new(world);
|
||||||
let tab_navigation = system_state.get(world);
|
let tab_navigation = system_state.get(world);
|
||||||
|
@ -78,7 +78,7 @@ pub struct Pointer<E: Debug + Clone + Reflect> {
|
|||||||
/// propagates to the pointer's window and stops there.
|
/// propagates to the pointer's window and stops there.
|
||||||
#[derive(QueryData)]
|
#[derive(QueryData)]
|
||||||
pub struct PointerTraversal {
|
pub struct PointerTraversal {
|
||||||
parent: Option<&'static Parent>,
|
parent: Option<&'static ChildOf>,
|
||||||
window: Option<&'static Window>,
|
window: Option<&'static Window>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ use bevy_ecs::{
|
|||||||
component::ComponentId,
|
component::ComponentId,
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
event::EventCursor,
|
event::EventCursor,
|
||||||
hierarchy::Parent,
|
hierarchy::ChildOf,
|
||||||
query::QueryBuilder,
|
query::QueryBuilder,
|
||||||
reflect::{AppTypeRegistry, ReflectComponent, ReflectResource},
|
reflect::{AppTypeRegistry, ReflectComponent, ReflectResource},
|
||||||
removal_detection::RemovedComponentEntity,
|
removal_detection::RemovedComponentEntity,
|
||||||
@ -841,7 +841,7 @@ pub fn process_remote_reparent_request(
|
|||||||
// If `None`, remove the entities' parents.
|
// If `None`, remove the entities' parents.
|
||||||
else {
|
else {
|
||||||
for entity in entities {
|
for entity in entities {
|
||||||
get_entity_mut(world, entity)?.remove::<Parent>();
|
get_entity_mut(world, entity)?.remove::<ChildOf>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ use crate::{
|
|||||||
#[reflect(Component, Default, Debug, PartialEq)]
|
#[reflect(Component, Default, Debug, PartialEq)]
|
||||||
#[require(InheritedVisibility, ViewVisibility)]
|
#[require(InheritedVisibility, ViewVisibility)]
|
||||||
pub enum Visibility {
|
pub enum Visibility {
|
||||||
/// An entity with `Visibility::Inherited` will inherit the Visibility of its [`Parent`].
|
/// An entity with `Visibility::Inherited` will inherit the Visibility of its [`ChildOf`] target.
|
||||||
///
|
///
|
||||||
/// A root-level entity that is set to `Inherited` will be visible.
|
/// A root-level entity that is set to `Inherited` will be visible.
|
||||||
#[default]
|
#[default]
|
||||||
@ -47,7 +47,7 @@ pub enum Visibility {
|
|||||||
/// An entity with `Visibility::Visible` will be unconditionally visible.
|
/// An entity with `Visibility::Visible` will be unconditionally visible.
|
||||||
///
|
///
|
||||||
/// Note that an entity with `Visibility::Visible` will be visible regardless of whether the
|
/// Note that an entity with `Visibility::Visible` will be visible regardless of whether the
|
||||||
/// [`Parent`] entity is hidden.
|
/// [`ChildOf`] target entity is hidden.
|
||||||
Visible,
|
Visible,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,7 +316,7 @@ pub enum VisibilitySystems {
|
|||||||
/// Label for [`update_frusta`] in [`CameraProjectionPlugin`](crate::camera::CameraProjectionPlugin).
|
/// Label for [`update_frusta`] in [`CameraProjectionPlugin`](crate::camera::CameraProjectionPlugin).
|
||||||
UpdateFrusta,
|
UpdateFrusta,
|
||||||
/// Label for the system propagating the [`InheritedVisibility`] in a
|
/// Label for the system propagating the [`InheritedVisibility`] in a
|
||||||
/// [`Parent`] / [`Children`] hierarchy.
|
/// [`ChildOf`] / [`Children`] hierarchy.
|
||||||
VisibilityPropagate,
|
VisibilityPropagate,
|
||||||
/// Label for the [`check_visibility`] system updating [`ViewVisibility`]
|
/// Label for the [`check_visibility`] system updating [`ViewVisibility`]
|
||||||
/// of each entity and the [`VisibleEntities`] of each view.\
|
/// of each entity and the [`VisibleEntities`] of each view.\
|
||||||
@ -387,10 +387,10 @@ pub fn update_frusta(
|
|||||||
|
|
||||||
fn visibility_propagate_system(
|
fn visibility_propagate_system(
|
||||||
changed: Query<
|
changed: Query<
|
||||||
(Entity, &Visibility, Option<&Parent>, Option<&Children>),
|
(Entity, &Visibility, Option<&ChildOf>, Option<&Children>),
|
||||||
(
|
(
|
||||||
With<InheritedVisibility>,
|
With<InheritedVisibility>,
|
||||||
Or<(Changed<Visibility>, Changed<Parent>)>,
|
Or<(Changed<Visibility>, Changed<ChildOf>)>,
|
||||||
),
|
),
|
||||||
>,
|
>,
|
||||||
mut visibility_query: Query<(&Visibility, &mut InheritedVisibility)>,
|
mut visibility_query: Query<(&Visibility, &mut InheritedVisibility)>,
|
||||||
@ -761,7 +761,7 @@ mod test {
|
|||||||
.entity_mut(parent2)
|
.entity_mut(parent2)
|
||||||
.insert(Visibility::Visible);
|
.insert(Visibility::Visible);
|
||||||
// Simulate a change in the parent component
|
// Simulate a change in the parent component
|
||||||
app.world_mut().entity_mut(child2).insert(Parent(parent2)); // example of changing parent
|
app.world_mut().entity_mut(child2).insert(ChildOf(parent2)); // example of changing parent
|
||||||
|
|
||||||
// Run the system again to propagate changes
|
// Run the system again to propagate changes
|
||||||
app.update();
|
app.update();
|
||||||
|
@ -203,7 +203,7 @@ mod tests {
|
|||||||
hash_map::EntityHashMap, Entity, EntityMapper, MapEntities, VisitEntities,
|
hash_map::EntityHashMap, Entity, EntityMapper, MapEntities, VisitEntities,
|
||||||
VisitEntitiesMut,
|
VisitEntitiesMut,
|
||||||
},
|
},
|
||||||
hierarchy::Parent,
|
hierarchy::ChildOf,
|
||||||
reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities, ReflectResource},
|
reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities, ReflectResource},
|
||||||
system::Resource,
|
system::Resource,
|
||||||
world::World,
|
world::World,
|
||||||
@ -269,7 +269,7 @@ mod tests {
|
|||||||
world
|
world
|
||||||
.resource_mut::<AppTypeRegistry>()
|
.resource_mut::<AppTypeRegistry>()
|
||||||
.write()
|
.write()
|
||||||
.register::<Parent>();
|
.register::<ChildOf>();
|
||||||
let original_parent_entity = world.spawn_empty().id();
|
let original_parent_entity = world.spawn_empty().id();
|
||||||
let original_child_entity = world.spawn_empty().id();
|
let original_child_entity = world.spawn_empty().id();
|
||||||
world
|
world
|
||||||
@ -305,7 +305,7 @@ mod tests {
|
|||||||
world
|
world
|
||||||
.get_entity(original_child_entity)
|
.get_entity(original_child_entity)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get::<Parent>()
|
.get::<ChildOf>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get(),
|
.get(),
|
||||||
"something about reloading the scene is touching entities with the same scene Ids"
|
"something about reloading the scene is touching entities with the same scene Ids"
|
||||||
@ -315,7 +315,7 @@ mod tests {
|
|||||||
world
|
world
|
||||||
.get_entity(from_scene_parent_entity)
|
.get_entity(from_scene_parent_entity)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get::<Parent>()
|
.get::<ChildOf>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get(),
|
.get(),
|
||||||
"something about reloading the scene is touching components not defined in the scene but on entities defined in the scene"
|
"something about reloading the scene is touching components not defined in the scene but on entities defined in the scene"
|
||||||
@ -325,7 +325,7 @@ mod tests {
|
|||||||
world
|
world
|
||||||
.get_entity(from_scene_child_entity)
|
.get_entity(from_scene_child_entity)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get::<Parent>()
|
.get::<ChildOf>()
|
||||||
.expect("something is wrong with this test, and the scene components don't have a parent/child relationship")
|
.expect("something is wrong with this test, and the scene components don't have a parent/child relationship")
|
||||||
.get(),
|
.get(),
|
||||||
"something is wrong with this test or the code reloading scenes since the relationship between scene entities is broken"
|
"something is wrong with this test or the code reloading scenes since the relationship between scene entities is broken"
|
||||||
|
@ -3,7 +3,7 @@ use bevy_asset::{AssetEvent, AssetId, Assets, Handle};
|
|||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
entity::{hash_map::EntityHashMap, Entity},
|
entity::{hash_map::EntityHashMap, Entity},
|
||||||
event::{Event, EventCursor, Events},
|
event::{Event, EventCursor, Events},
|
||||||
hierarchy::Parent,
|
hierarchy::ChildOf,
|
||||||
reflect::AppTypeRegistry,
|
reflect::AppTypeRegistry,
|
||||||
system::Resource,
|
system::Resource,
|
||||||
world::{Mut, World},
|
world::{Mut, World},
|
||||||
@ -377,7 +377,7 @@ impl SceneSpawner {
|
|||||||
for (instance_id, parent) in scenes_with_parent {
|
for (instance_id, parent) in scenes_with_parent {
|
||||||
if let Some(instance) = self.spawned_instances.get(&instance_id) {
|
if let Some(instance) = self.spawned_instances.get(&instance_id) {
|
||||||
for &entity in instance.entity_map.values() {
|
for &entity in instance.entity_map.values() {
|
||||||
// Add the `Parent` component to the scene root, and update the `Children` component of
|
// Add the `ChildOf` component to the scene root, and update the `Children` component of
|
||||||
// the scene parent
|
// the scene parent
|
||||||
if !world
|
if !world
|
||||||
.get_entity(entity)
|
.get_entity(entity)
|
||||||
@ -386,7 +386,7 @@ impl SceneSpawner {
|
|||||||
// scene have a parent
|
// scene have a parent
|
||||||
// Entities that wouldn't exist anymore are also skipped
|
// Entities that wouldn't exist anymore are also skipped
|
||||||
// this case shouldn't happen anyway
|
// this case shouldn't happen anyway
|
||||||
.is_none_or(|entity| entity.contains::<Parent>())
|
.is_none_or(|entity| entity.contains::<ChildOf>())
|
||||||
{
|
{
|
||||||
world.entity_mut(parent).add_child(entity);
|
world.entity_mut(parent).add_child(entity);
|
||||||
}
|
}
|
||||||
|
@ -455,13 +455,13 @@ pub fn detect_text_needs_rerender<Root: Component>(
|
|||||||
),
|
),
|
||||||
>,
|
>,
|
||||||
changed_spans: Query<
|
changed_spans: Query<
|
||||||
(Entity, Option<&Parent>, Has<TextLayout>),
|
(Entity, Option<&ChildOf>, Has<TextLayout>),
|
||||||
(
|
(
|
||||||
Or<(
|
Or<(
|
||||||
Changed<TextSpan>,
|
Changed<TextSpan>,
|
||||||
Changed<TextFont>,
|
Changed<TextFont>,
|
||||||
Changed<Children>,
|
Changed<Children>,
|
||||||
Changed<Parent>, // Included to detect broken text block hierarchies.
|
Changed<ChildOf>, // Included to detect broken text block hierarchies.
|
||||||
Added<TextLayout>,
|
Added<TextLayout>,
|
||||||
)>,
|
)>,
|
||||||
With<TextSpan>,
|
With<TextSpan>,
|
||||||
@ -469,7 +469,7 @@ pub fn detect_text_needs_rerender<Root: Component>(
|
|||||||
),
|
),
|
||||||
>,
|
>,
|
||||||
mut computed: Query<(
|
mut computed: Query<(
|
||||||
Option<&Parent>,
|
Option<&ChildOf>,
|
||||||
Option<&mut ComputedTextBlock>,
|
Option<&mut ComputedTextBlock>,
|
||||||
Has<TextSpan>,
|
Has<TextSpan>,
|
||||||
)>,
|
)>,
|
||||||
@ -515,7 +515,7 @@ pub fn detect_text_needs_rerender<Root: Component>(
|
|||||||
// is outweighed by the expense of tracking visited spans.
|
// is outweighed by the expense of tracking visited spans.
|
||||||
loop {
|
loop {
|
||||||
let Ok((maybe_parent, maybe_computed, has_span)) = computed.get_mut(parent) else {
|
let Ok((maybe_parent, maybe_computed, has_span)) = computed.get_mut(parent) else {
|
||||||
once!(warn!("found entity {} with a TextSpan that is part of a broken hierarchy with a Parent \
|
once!(warn!("found entity {} with a TextSpan that is part of a broken hierarchy with a ChildOf \
|
||||||
component that points at non-existent entity {}; this warning only prints once",
|
component that points at non-existent entity {}; this warning only prints once",
|
||||||
entity, parent));
|
entity, parent));
|
||||||
break;
|
break;
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
//! while preserving [`GlobalTransform`].
|
//! while preserving [`GlobalTransform`].
|
||||||
|
|
||||||
use crate::prelude::{GlobalTransform, Transform};
|
use crate::prelude::{GlobalTransform, Transform};
|
||||||
use bevy_ecs::{entity::Entity, hierarchy::Parent, system::EntityCommands, world::EntityWorldMut};
|
use bevy_ecs::{entity::Entity, hierarchy::ChildOf, system::EntityCommands, world::EntityWorldMut};
|
||||||
|
|
||||||
/// Collection of methods similar to the built-in parenting methods on [`EntityWorldMut`] and [`EntityCommands`], but preserving each
|
/// Collection of methods similar to the built-in parenting methods on [`EntityWorldMut`] and [`EntityCommands`], but preserving each
|
||||||
/// entity's [`GlobalTransform`].
|
/// entity's [`GlobalTransform`].
|
||||||
@ -10,7 +10,7 @@ pub trait BuildChildrenTransformExt {
|
|||||||
/// Change this entity's parent while preserving this entity's [`GlobalTransform`]
|
/// Change this entity's parent while preserving this entity's [`GlobalTransform`]
|
||||||
/// by updating its [`Transform`].
|
/// by updating its [`Transform`].
|
||||||
///
|
///
|
||||||
/// Insert the [`Parent`] component directly if you don't want to also update the [`Transform`].
|
/// Insert the [`ChildOf`] component directly if you don't want to also update the [`Transform`].
|
||||||
///
|
///
|
||||||
/// Note that both the hierarchy and transform updates will only execute
|
/// Note that both the hierarchy and transform updates will only execute
|
||||||
/// the next time commands are applied
|
/// the next time commands are applied
|
||||||
@ -64,7 +64,7 @@ impl BuildChildrenTransformExt for EntityWorldMut<'_> {
|
|||||||
fn remove_parent_in_place(&mut self) -> &mut Self {
|
fn remove_parent_in_place(&mut self) -> &mut Self {
|
||||||
let child = self.id();
|
let child = self.id();
|
||||||
self.world_scope(|world| {
|
self.world_scope(|world| {
|
||||||
world.entity_mut(child).remove::<Parent>();
|
world.entity_mut(child).remove::<ChildOf>();
|
||||||
// FIXME: Replace this closure with a `try` block. See: https://github.com/rust-lang/rust/issues/31436.
|
// FIXME: Replace this closure with a `try` block. See: https://github.com/rust-lang/rust/issues/31436.
|
||||||
let mut update_transform = || {
|
let mut update_transform = || {
|
||||||
let child_global = *world.get_entity(child).ok()?.get::<GlobalTransform>()?;
|
let child_global = *world.get_entity(child).ok()?.get::<GlobalTransform>()?;
|
||||||
|
@ -28,7 +28,7 @@ use {
|
|||||||
/// ## [`Transform`] and [`GlobalTransform`]
|
/// ## [`Transform`] and [`GlobalTransform`]
|
||||||
///
|
///
|
||||||
/// [`Transform`] transforms an entity relative to its parent's reference frame, or relative to world space coordinates,
|
/// [`Transform`] transforms an entity relative to its parent's reference frame, or relative to world space coordinates,
|
||||||
/// if it doesn't have a [`Parent`](bevy_ecs::hierarchy::Parent).
|
/// if it doesn't have a [`ChildOf`](bevy_ecs::hierarchy::ChildOf) component.
|
||||||
///
|
///
|
||||||
/// [`GlobalTransform`] is managed by Bevy; it is computed by successively applying the [`Transform`] of each ancestor
|
/// [`GlobalTransform`] is managed by Bevy; it is computed by successively applying the [`Transform`] of each ancestor
|
||||||
/// entity which has a Transform. This is done automatically by Bevy-internal systems in the system set
|
/// entity which has a Transform. This is done automatically by Bevy-internal systems in the system set
|
||||||
|
@ -19,7 +19,7 @@ use {bevy_ecs::reflect::ReflectComponent, bevy_reflect::prelude::*};
|
|||||||
/// ## [`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`](bevy_ecs::hierarchy::Parent).
|
/// frame if it doesn't have a [`ChildOf`](bevy_ecs::hierarchy::ChildOf) component.
|
||||||
///
|
///
|
||||||
/// [`GlobalTransform`] is the position of an entity relative to the reference frame.
|
/// [`GlobalTransform`] is the position of an entity relative to the reference frame.
|
||||||
///
|
///
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! System parameter for computing up-to-date [`GlobalTransform`]s.
|
//! System parameter for computing up-to-date [`GlobalTransform`]s.
|
||||||
|
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
hierarchy::Parent,
|
hierarchy::ChildOf,
|
||||||
prelude::Entity,
|
prelude::Entity,
|
||||||
query::QueryEntityError,
|
query::QueryEntityError,
|
||||||
system::{Query, SystemParam},
|
system::{Query, SystemParam},
|
||||||
@ -18,7 +18,7 @@ use crate::components::{GlobalTransform, Transform};
|
|||||||
/// the last time the transform propagation systems ran.
|
/// the last time the transform propagation systems ran.
|
||||||
#[derive(SystemParam)]
|
#[derive(SystemParam)]
|
||||||
pub struct TransformHelper<'w, 's> {
|
pub struct TransformHelper<'w, 's> {
|
||||||
parent_query: Query<'w, 's, &'static Parent>,
|
parent_query: Query<'w, 's, &'static ChildOf>,
|
||||||
transform_query: Query<'w, 's, &'static Transform>,
|
transform_query: Query<'w, 's, &'static Transform>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ mod tests {
|
|||||||
use core::f32::consts::TAU;
|
use core::f32::consts::TAU;
|
||||||
|
|
||||||
use bevy_app::App;
|
use bevy_app::App;
|
||||||
use bevy_ecs::{hierarchy::Parent, system::SystemState};
|
use bevy_ecs::{hierarchy::ChildOf, system::SystemState};
|
||||||
use bevy_math::{Quat, Vec3};
|
use bevy_math::{Quat, Vec3};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -124,7 +124,7 @@ mod tests {
|
|||||||
let mut e = app.world_mut().spawn(transform);
|
let mut e = app.world_mut().spawn(transform);
|
||||||
|
|
||||||
if let Some(entity) = entity {
|
if let Some(entity) = entity {
|
||||||
e.insert(Parent(entity));
|
e.insert(ChildOf(entity));
|
||||||
}
|
}
|
||||||
|
|
||||||
entity = Some(e.id());
|
entity = Some(e.id());
|
||||||
|
@ -11,13 +11,13 @@ pub fn sync_simple_transforms(
|
|||||||
(&Transform, &mut GlobalTransform),
|
(&Transform, &mut GlobalTransform),
|
||||||
(
|
(
|
||||||
Or<(Changed<Transform>, Added<GlobalTransform>)>,
|
Or<(Changed<Transform>, Added<GlobalTransform>)>,
|
||||||
Without<Parent>,
|
Without<ChildOf>,
|
||||||
Without<Children>,
|
Without<Children>,
|
||||||
),
|
),
|
||||||
>,
|
>,
|
||||||
Query<(Ref<Transform>, &mut GlobalTransform), (Without<Parent>, Without<Children>)>,
|
Query<(Ref<Transform>, &mut GlobalTransform), (Without<ChildOf>, Without<Children>)>,
|
||||||
)>,
|
)>,
|
||||||
mut orphaned: RemovedComponents<Parent>,
|
mut orphaned: RemovedComponents<ChildOf>,
|
||||||
) {
|
) {
|
||||||
// Update changed entities.
|
// Update changed entities.
|
||||||
query
|
query
|
||||||
@ -43,11 +43,14 @@ pub fn sync_simple_transforms(
|
|||||||
pub fn propagate_transforms(
|
pub fn propagate_transforms(
|
||||||
mut root_query: Query<
|
mut root_query: Query<
|
||||||
(Entity, &Children, Ref<Transform>, &mut GlobalTransform),
|
(Entity, &Children, Ref<Transform>, &mut GlobalTransform),
|
||||||
Without<Parent>,
|
Without<ChildOf>,
|
||||||
>,
|
>,
|
||||||
mut orphaned: RemovedComponents<Parent>,
|
mut orphaned: RemovedComponents<ChildOf>,
|
||||||
transform_query: Query<(Ref<Transform>, &mut GlobalTransform, Option<&Children>), With<Parent>>,
|
transform_query: Query<
|
||||||
parent_query: Query<(Entity, Ref<Parent>), With<GlobalTransform>>,
|
(Ref<Transform>, &mut GlobalTransform, Option<&Children>),
|
||||||
|
With<ChildOf>,
|
||||||
|
>,
|
||||||
|
parent_query: Query<(Entity, Ref<ChildOf>), With<GlobalTransform>>,
|
||||||
mut orphaned_entities: Local<Vec<Entity>>,
|
mut orphaned_entities: Local<Vec<Entity>>,
|
||||||
) {
|
) {
|
||||||
orphaned_entities.clear();
|
orphaned_entities.clear();
|
||||||
@ -109,9 +112,9 @@ unsafe fn propagate_recursive(
|
|||||||
parent: &GlobalTransform,
|
parent: &GlobalTransform,
|
||||||
transform_query: &Query<
|
transform_query: &Query<
|
||||||
(Ref<Transform>, &mut GlobalTransform, Option<&Children>),
|
(Ref<Transform>, &mut GlobalTransform, Option<&Children>),
|
||||||
With<Parent>,
|
With<ChildOf>,
|
||||||
>,
|
>,
|
||||||
parent_query: &Query<(Entity, Ref<Parent>), With<GlobalTransform>>,
|
parent_query: &Query<(Entity, Ref<ChildOf>), With<GlobalTransform>>,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
mut changed: bool,
|
mut changed: bool,
|
||||||
) {
|
) {
|
||||||
@ -130,7 +133,7 @@ unsafe fn propagate_recursive(
|
|||||||
// \ /
|
// \ /
|
||||||
// D
|
// D
|
||||||
//
|
//
|
||||||
// D has two parents, B and C. If the propagation passes through C, but the Parent component on D points to B,
|
// D has two parents, B and C. If the propagation passes through C, but the ChildOf component on D points to B,
|
||||||
// the above check will panic as the origin parent does match the recorded parent.
|
// the above check will panic as the origin parent does match the recorded parent.
|
||||||
//
|
//
|
||||||
// Also consider the following case, where A and B are roots:
|
// Also consider the following case, where A and B are roots:
|
||||||
@ -203,8 +206,8 @@ mod test {
|
|||||||
let root = commands.spawn(offset_transform(3.3)).id();
|
let root = commands.spawn(offset_transform(3.3)).id();
|
||||||
let parent = commands.spawn(offset_transform(4.4)).id();
|
let parent = commands.spawn(offset_transform(4.4)).id();
|
||||||
let child = commands.spawn(offset_transform(5.5)).id();
|
let child = commands.spawn(offset_transform(5.5)).id();
|
||||||
commands.entity(parent).insert(Parent(root));
|
commands.entity(parent).insert(ChildOf(root));
|
||||||
commands.entity(child).insert(Parent(parent));
|
commands.entity(child).insert(ChildOf(parent));
|
||||||
command_queue.apply(&mut world);
|
command_queue.apply(&mut world);
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
|
|
||||||
@ -217,7 +220,7 @@ mod test {
|
|||||||
// Remove parent of `parent`
|
// Remove parent of `parent`
|
||||||
let mut command_queue = CommandQueue::default();
|
let mut command_queue = CommandQueue::default();
|
||||||
let mut commands = Commands::new(&mut command_queue, &world);
|
let mut commands = Commands::new(&mut command_queue, &world);
|
||||||
commands.entity(parent).remove::<Parent>();
|
commands.entity(parent).remove::<ChildOf>();
|
||||||
command_queue.apply(&mut world);
|
command_queue.apply(&mut world);
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
|
|
||||||
@ -230,7 +233,7 @@ mod test {
|
|||||||
// Remove parent of `child`
|
// Remove parent of `child`
|
||||||
let mut command_queue = CommandQueue::default();
|
let mut command_queue = CommandQueue::default();
|
||||||
let mut commands = Commands::new(&mut command_queue, &world);
|
let mut commands = Commands::new(&mut command_queue, &world);
|
||||||
commands.entity(child).remove::<Parent>();
|
commands.entity(child).remove::<ChildOf>();
|
||||||
command_queue.apply(&mut world);
|
command_queue.apply(&mut world);
|
||||||
schedule.run(&mut world);
|
schedule.run(&mut world);
|
||||||
|
|
||||||
@ -426,7 +429,7 @@ mod test {
|
|||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn panic_when_hierarchy_cycle() {
|
fn panic_when_hierarchy_cycle() {
|
||||||
ComputeTaskPool::get_or_init(TaskPool::default);
|
ComputeTaskPool::get_or_init(TaskPool::default);
|
||||||
// We cannot directly edit Parent and Children, so we use a temp world to break
|
// We cannot directly edit ChildOf and Children, so we use a temp world to break
|
||||||
// the hierarchy's invariants.
|
// the hierarchy's invariants.
|
||||||
let mut temp = World::new();
|
let mut temp = World::new();
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
@ -456,25 +459,25 @@ mod test {
|
|||||||
core::mem::swap(
|
core::mem::swap(
|
||||||
#[expect(
|
#[expect(
|
||||||
unsafe_code,
|
unsafe_code,
|
||||||
reason = "Parent is not mutable but this is for a test to produce a scenario that cannot happen"
|
reason = "ChildOf is not mutable but this is for a test to produce a scenario that cannot happen"
|
||||||
)]
|
)]
|
||||||
// SAFETY: Parent is not mutable but this is for a test to produce a scenario that cannot happen
|
// SAFETY: ChildOf is not mutable but this is for a test to produce a scenario that cannot happen
|
||||||
unsafe {
|
unsafe {
|
||||||
&mut *app
|
&mut *app
|
||||||
.world_mut()
|
.world_mut()
|
||||||
.entity_mut(child)
|
.entity_mut(child)
|
||||||
.get_mut_assume_mutable::<Parent>()
|
.get_mut_assume_mutable::<ChildOf>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
},
|
},
|
||||||
// SAFETY: Parent is not mutable but this is for a test to produce a scenario that cannot happen
|
// SAFETY: ChildOf is not mutable but this is for a test to produce a scenario that cannot happen
|
||||||
#[expect(
|
#[expect(
|
||||||
unsafe_code,
|
unsafe_code,
|
||||||
reason = "Parent is not mutable but this is for a test to produce a scenario that cannot happen"
|
reason = "ChildOf is not mutable but this is for a test to produce a scenario that cannot happen"
|
||||||
)]
|
)]
|
||||||
unsafe {
|
unsafe {
|
||||||
&mut *temp
|
&mut *temp
|
||||||
.entity_mut(grandchild)
|
.entity_mut(grandchild)
|
||||||
.get_mut_assume_mutable::<Parent>()
|
.get_mut_assume_mutable::<ChildOf>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -514,7 +517,7 @@ mod test {
|
|||||||
.abs_diff_eq(2. * translation, 0.1));
|
.abs_diff_eq(2. * translation, 0.1));
|
||||||
|
|
||||||
// Reparent child
|
// Reparent child
|
||||||
world.entity_mut(child).remove::<Parent>();
|
world.entity_mut(child).remove::<ChildOf>();
|
||||||
world.entity_mut(parent).add_child(child);
|
world.entity_mut(parent).add_child(child);
|
||||||
|
|
||||||
// Run schedule to propagate transforms
|
// Run schedule to propagate transforms
|
||||||
|
@ -43,17 +43,17 @@ impl GhostNode {
|
|||||||
#[cfg(feature = "ghost_nodes")]
|
#[cfg(feature = "ghost_nodes")]
|
||||||
/// System param that allows iteration of all UI root nodes.
|
/// System param that allows iteration of all UI root nodes.
|
||||||
///
|
///
|
||||||
/// A UI root node is either a [`Node`] without a [`Parent`], or with only [`GhostNode`] ancestors.
|
/// A UI root node is either a [`Node`] without a [`ChildOf`], or with only [`GhostNode`] ancestors.
|
||||||
#[derive(SystemParam)]
|
#[derive(SystemParam)]
|
||||||
pub struct UiRootNodes<'w, 's> {
|
pub struct UiRootNodes<'w, 's> {
|
||||||
root_node_query: Query<'w, 's, Entity, (With<Node>, Without<Parent>)>,
|
root_node_query: Query<'w, 's, Entity, (With<Node>, Without<ChildOf>)>,
|
||||||
root_ghost_node_query: Query<'w, 's, Entity, (With<GhostNode>, Without<Parent>)>,
|
root_ghost_node_query: Query<'w, 's, Entity, (With<GhostNode>, Without<ChildOf>)>,
|
||||||
all_nodes_query: Query<'w, 's, Entity, With<Node>>,
|
all_nodes_query: Query<'w, 's, Entity, With<Node>>,
|
||||||
ui_children: UiChildren<'w, 's>,
|
ui_children: UiChildren<'w, 's>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "ghost_nodes"))]
|
#[cfg(not(feature = "ghost_nodes"))]
|
||||||
pub type UiRootNodes<'w, 's> = Query<'w, 's, Entity, (With<Node>, Without<Parent>)>;
|
pub type UiRootNodes<'w, 's> = Query<'w, 's, Entity, (With<Node>, Without<ChildOf>)>;
|
||||||
|
|
||||||
#[cfg(feature = "ghost_nodes")]
|
#[cfg(feature = "ghost_nodes")]
|
||||||
impl<'w, 's> UiRootNodes<'w, 's> {
|
impl<'w, 's> UiRootNodes<'w, 's> {
|
||||||
@ -80,7 +80,7 @@ pub struct UiChildren<'w, 's> {
|
|||||||
changed_children_query: Query<'w, 's, Entity, Changed<Children>>,
|
changed_children_query: Query<'w, 's, Entity, Changed<Children>>,
|
||||||
children_query: Query<'w, 's, &'static Children>,
|
children_query: Query<'w, 's, &'static Children>,
|
||||||
ghost_nodes_query: Query<'w, 's, Entity, With<GhostNode>>,
|
ghost_nodes_query: Query<'w, 's, Entity, With<GhostNode>>,
|
||||||
parents_query: Query<'w, 's, &'static Parent>,
|
parents_query: Query<'w, 's, &'static ChildOf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "ghost_nodes"))]
|
#[cfg(not(feature = "ghost_nodes"))]
|
||||||
@ -89,7 +89,7 @@ pub struct UiChildren<'w, 's> {
|
|||||||
pub struct UiChildren<'w, 's> {
|
pub struct UiChildren<'w, 's> {
|
||||||
ui_children_query: Query<'w, 's, Option<&'static Children>, With<Node>>,
|
ui_children_query: Query<'w, 's, Option<&'static Children>, With<Node>>,
|
||||||
changed_children_query: Query<'w, 's, Entity, Changed<Children>>,
|
changed_children_query: Query<'w, 's, Entity, Changed<Children>>,
|
||||||
parents_query: Query<'w, 's, &'static Parent>,
|
parents_query: Query<'w, 's, &'static ChildOf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "ghost_nodes")]
|
#[cfg(feature = "ghost_nodes")]
|
||||||
|
@ -107,7 +107,7 @@ pub fn ui_layout_system(
|
|||||||
Option<&mut ContentSize>,
|
Option<&mut ContentSize>,
|
||||||
Option<&UiTargetCamera>,
|
Option<&UiTargetCamera>,
|
||||||
)>,
|
)>,
|
||||||
computed_node_query: Query<(Entity, Option<Ref<Parent>>), With<ComputedNode>>,
|
computed_node_query: Query<(Entity, Option<Ref<ChildOf>>), With<ComputedNode>>,
|
||||||
ui_children: UiChildren,
|
ui_children: UiChildren,
|
||||||
mut removed_components: UiLayoutSystemRemovedComponentParam,
|
mut removed_components: UiLayoutSystemRemovedComponentParam,
|
||||||
mut node_transform_query: Query<(
|
mut node_transform_query: Query<(
|
||||||
@ -844,7 +844,7 @@ mod tests {
|
|||||||
ui_schedule.run(&mut world);
|
ui_schedule.run(&mut world);
|
||||||
|
|
||||||
let overlap_check = world
|
let overlap_check = world
|
||||||
.query_filtered::<(Entity, &ComputedNode, &GlobalTransform), Without<Parent>>()
|
.query_filtered::<(Entity, &ComputedNode, &GlobalTransform), Without<ChildOf>>()
|
||||||
.iter(&world)
|
.iter(&world)
|
||||||
.fold(
|
.fold(
|
||||||
Option::<(Rect, bool)>::None,
|
Option::<(Rect, bool)>::None,
|
||||||
|
@ -179,7 +179,7 @@ fn update_accessibility_nodes(
|
|||||||
Entity,
|
Entity,
|
||||||
&AccessibilityNode,
|
&AccessibilityNode,
|
||||||
Option<&Children>,
|
Option<&Children>,
|
||||||
Option<&Parent>,
|
Option<&ChildOf>,
|
||||||
)>,
|
)>,
|
||||||
node_entities: Query<Entity, With<AccessibilityNode>>,
|
node_entities: Query<Entity, With<AccessibilityNode>>,
|
||||||
) {
|
) {
|
||||||
@ -218,7 +218,7 @@ fn update_adapter(
|
|||||||
Entity,
|
Entity,
|
||||||
&AccessibilityNode,
|
&AccessibilityNode,
|
||||||
Option<&Children>,
|
Option<&Children>,
|
||||||
Option<&Parent>,
|
Option<&ChildOf>,
|
||||||
)>,
|
)>,
|
||||||
node_entities: Query<Entity, With<AccessibilityNode>>,
|
node_entities: Query<Entity, With<AccessibilityNode>>,
|
||||||
primary_window: &Window,
|
primary_window: &Window,
|
||||||
@ -253,12 +253,12 @@ fn update_adapter(
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn queue_node_for_update(
|
fn queue_node_for_update(
|
||||||
node_entity: Entity,
|
node_entity: Entity,
|
||||||
parent: Option<&Parent>,
|
child_of: Option<&ChildOf>,
|
||||||
node_entities: &Query<Entity, With<AccessibilityNode>>,
|
node_entities: &Query<Entity, With<AccessibilityNode>>,
|
||||||
window_children: &mut Vec<NodeId>,
|
window_children: &mut Vec<NodeId>,
|
||||||
) {
|
) {
|
||||||
let should_push = if let Some(parent) = parent {
|
let should_push = if let Some(child_of) = child_of {
|
||||||
!node_entities.contains(parent.get())
|
!node_entities.contains(child_of.get())
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
A runtime warning.
|
A runtime warning.
|
||||||
|
|
||||||
An [`Entity`] with a hierarchy-inherited component has a [`Parent`]
|
An [`Entity`] with a hierarchy-inherited component has a [`ChildOf`]
|
||||||
without the hierarchy-inherited component in question.
|
without the hierarchy-inherited component in question.
|
||||||
|
|
||||||
The hierarchy-inherited components defined in bevy include:
|
The hierarchy-inherited components defined in bevy include:
|
||||||
@ -108,5 +108,5 @@ as a child of a pre-existing [`Entity`] that does not have the proper components
|
|||||||
[`ViewVisibility`]: https://docs.rs/bevy/*/bevy/render/view/struct.ViewVisibility.html
|
[`ViewVisibility`]: https://docs.rs/bevy/*/bevy/render/view/struct.ViewVisibility.html
|
||||||
[`Visibility`]: https://docs.rs/bevy/*/bevy/render/view/struct.Visibility.html
|
[`Visibility`]: https://docs.rs/bevy/*/bevy/render/view/struct.Visibility.html
|
||||||
[`GlobalTransform`]: https://docs.rs/bevy/*/bevy/transform/components/struct.GlobalTransform.html
|
[`GlobalTransform`]: https://docs.rs/bevy/*/bevy/transform/components/struct.GlobalTransform.html
|
||||||
[`Parent`]: https://docs.rs/bevy/*/bevy/hierarchy/struct.Parent.html
|
[`ChildOf`]: https://docs.rs/bevy/*/bevy/ecs/hierarchy/struct.ChildOf.html
|
||||||
[`Entity`]: https://docs.rs/bevy/*/bevy/ecs/entity/struct.Entity.html
|
[`Entity`]: https://docs.rs/bevy/*/bevy/ecs/entity/struct.Entity.html
|
||||||
|
@ -432,7 +432,7 @@ fn reset_sphere_position(
|
|||||||
fn move_sphere(
|
fn move_sphere(
|
||||||
mouse_button_input: Res<ButtonInput<MouseButton>>,
|
mouse_button_input: Res<ButtonInput<MouseButton>>,
|
||||||
pointers: Query<&PointerInteraction>,
|
pointers: Query<&PointerInteraction>,
|
||||||
mut meshes: Query<(&Name, &Parent), With<Mesh3d>>,
|
mut meshes: Query<(&Name, &ChildOf), With<Mesh3d>>,
|
||||||
mut transforms: Query<&mut Transform>,
|
mut transforms: Query<&mut Transform>,
|
||||||
app_status: Res<AppStatus>,
|
app_status: Res<AppStatus>,
|
||||||
) {
|
) {
|
||||||
@ -445,11 +445,11 @@ fn move_sphere(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find the sphere.
|
// Find the sphere.
|
||||||
let Some(parent) = meshes
|
let Some(child_of) = meshes
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.filter_map(|(name, parent)| {
|
.filter_map(|(name, child_of)| {
|
||||||
if &**name == "Sphere" {
|
if &**name == "Sphere" {
|
||||||
Some(parent)
|
Some(child_of)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -460,7 +460,7 @@ fn move_sphere(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Grab its transform.
|
// Grab its transform.
|
||||||
let Ok(mut transform) = transforms.get_mut(parent.0) else {
|
let Ok(mut transform) = transforms.get_mut(child_of.0) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -175,19 +175,19 @@ fn setup(
|
|||||||
fn set_visibility_ranges(
|
fn set_visibility_ranges(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
mut new_meshes: Query<Entity, Added<Mesh3d>>,
|
mut new_meshes: Query<Entity, Added<Mesh3d>>,
|
||||||
parents: Query<(Option<&Parent>, Option<&MainModel>)>,
|
children: Query<(Option<&ChildOf>, Option<&MainModel>)>,
|
||||||
) {
|
) {
|
||||||
// Loop over each newly-added mesh.
|
// Loop over each newly-added mesh.
|
||||||
for new_mesh in new_meshes.iter_mut() {
|
for new_mesh in new_meshes.iter_mut() {
|
||||||
// Search for the nearest ancestor `MainModel` component.
|
// Search for the nearest ancestor `MainModel` component.
|
||||||
let (mut current, mut main_model) = (new_mesh, None);
|
let (mut current, mut main_model) = (new_mesh, None);
|
||||||
while let Ok((parent, maybe_main_model)) = parents.get(current) {
|
while let Ok((child_of, maybe_main_model)) = children.get(current) {
|
||||||
if let Some(model) = maybe_main_model {
|
if let Some(model) = maybe_main_model {
|
||||||
main_model = Some(model);
|
main_model = Some(model);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
match parent {
|
match child_of {
|
||||||
Some(parent) => current = parent.0,
|
Some(child_of) => current = child_of.0,
|
||||||
None => break,
|
None => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,21 +44,21 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||||||
/// It is similar to the animation defined in `models/SimpleSkin/SimpleSkin.gltf`.
|
/// It is similar to the animation defined in `models/SimpleSkin/SimpleSkin.gltf`.
|
||||||
fn joint_animation(
|
fn joint_animation(
|
||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
parent_query: Query<&Parent, With<SkinnedMesh>>,
|
children: Query<&ChildOf, With<SkinnedMesh>>,
|
||||||
children_query: Query<&Children>,
|
parents: Query<&Children>,
|
||||||
mut transform_query: Query<&mut Transform>,
|
mut transform_query: Query<&mut Transform>,
|
||||||
) {
|
) {
|
||||||
// Iter skinned mesh entity
|
// Iter skinned mesh entity
|
||||||
for skinned_mesh_parent in &parent_query {
|
for child_of in &children {
|
||||||
// Mesh node is the parent of the skinned mesh entity.
|
// Mesh node is the parent of the skinned mesh entity.
|
||||||
let mesh_node_entity = skinned_mesh_parent.get();
|
let mesh_node_entity = child_of.get();
|
||||||
// Get `Children` in the mesh node.
|
// Get `Children` in the mesh node.
|
||||||
let mesh_node_children = children_query.get(mesh_node_entity).unwrap();
|
let mesh_node_parent = parents.get(mesh_node_entity).unwrap();
|
||||||
|
|
||||||
// First joint is the second child of the mesh node.
|
// First joint is the second child of the mesh node.
|
||||||
let first_joint_entity = mesh_node_children[1];
|
let first_joint_entity = mesh_node_parent[1];
|
||||||
// Get `Children` in the first joint.
|
// Get `Children` in the first joint.
|
||||||
let first_joint_children = children_query.get(first_joint_entity).unwrap();
|
let first_joint_children = parents.get(first_joint_entity).unwrap();
|
||||||
|
|
||||||
// Second joint is the first child of the first joint.
|
// Second joint is the first child of the first joint.
|
||||||
let second_joint_entity = first_joint_children[0];
|
let second_joint_entity = first_joint_children[0];
|
||||||
|
@ -67,7 +67,7 @@ fn rotate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// To iterate through the entities children, just treat the Children component as a Vec
|
// To iterate through the entities children, just treat the Children component as a Vec
|
||||||
// Alternatively, you could query entities that have a Parent component
|
// Alternatively, you could query entities that have a ChildOf component
|
||||||
for child in children {
|
for child in children {
|
||||||
if let Ok(mut transform) = transform_query.get_mut(*child) {
|
if let Ok(mut transform) = transform_query.get_mut(*child) {
|
||||||
transform.rotate_z(PI * time.delta_secs());
|
transform.rotate_z(PI * time.delta_secs());
|
||||||
|
@ -51,9 +51,9 @@ struct Attack {
|
|||||||
// two important pieces of information:
|
// two important pieces of information:
|
||||||
impl Event for Attack {
|
impl Event for Attack {
|
||||||
// 1. Which component we want to propagate along. In this case, we want to "bubble" (meaning propagate
|
// 1. Which component we want to propagate along. In this case, we want to "bubble" (meaning propagate
|
||||||
// from child to parent) so we use the `Parent` component for propagation. The component supplied
|
// from child to parent) so we use the `ChildOf` component for propagation. The component supplied
|
||||||
// must implement the `Traversal` trait.
|
// must implement the `Traversal` trait.
|
||||||
type Traversal = &'static Parent;
|
type Traversal = &'static ChildOf;
|
||||||
// 2. We can also choose whether or not this event will propagate by default when triggered. If this is
|
// 2. We can also choose whether or not this event will propagate by default when triggered. If this is
|
||||||
// false, it will only propagate following a call to `Trigger::propagate(true)`.
|
// false, it will only propagate following a call to `Trigger::propagate(true)`.
|
||||||
const AUTO_PROPAGATE: bool = true;
|
const AUTO_PROPAGATE: bool = true;
|
||||||
|
@ -295,6 +295,6 @@ fn spawn_button(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn despawn_ui(mut commands: Commands, root_node: Single<Entity, (With<Node>, Without<Parent>)>) {
|
fn despawn_ui(mut commands: Commands, root_node: Single<Entity, (With<Node>, Without<ChildOf>)>) {
|
||||||
commands.entity(*root_node).despawn();
|
commands.entity(*root_node).despawn();
|
||||||
}
|
}
|
||||||
|
@ -380,7 +380,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||||||
fn toggle_debug_overlay(
|
fn toggle_debug_overlay(
|
||||||
input: Res<ButtonInput<KeyCode>>,
|
input: Res<ButtonInput<KeyCode>>,
|
||||||
mut debug_options: ResMut<UiDebugOptions>,
|
mut debug_options: ResMut<UiDebugOptions>,
|
||||||
mut root_node_query: Query<&mut Visibility, (With<Node>, Without<Parent>)>,
|
mut root_node_query: Query<&mut Visibility, (With<Node>, Without<ChildOf>)>,
|
||||||
) {
|
) {
|
||||||
info_once!("The debug outlines are enabled, press Space to turn them on/off");
|
info_once!("The debug outlines are enabled, press Space to turn them on/off");
|
||||||
if input.just_pressed(KeyCode::Space) {
|
if input.just_pressed(KeyCode::Space) {
|
||||||
|
@ -37,7 +37,7 @@ impl Clips {
|
|||||||
fn assign_clips(
|
fn assign_clips(
|
||||||
mut players: Query<&mut AnimationPlayer>,
|
mut players: Query<&mut AnimationPlayer>,
|
||||||
targets: Query<(Entity, &AnimationTarget)>,
|
targets: Query<(Entity, &AnimationTarget)>,
|
||||||
parents: Query<&Parent>,
|
children: Query<&ChildOf>,
|
||||||
scene_handle: Res<SceneHandle>,
|
scene_handle: Res<SceneHandle>,
|
||||||
clips: Res<Assets<AnimationClip>>,
|
clips: Res<Assets<AnimationClip>>,
|
||||||
gltf_assets: Res<Assets<Gltf>>,
|
gltf_assets: Res<Assets<Gltf>>,
|
||||||
@ -109,7 +109,7 @@ fn assign_clips(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Go to the next parent.
|
// Go to the next parent.
|
||||||
current = parents.get(entity).ok().map(Parent::get);
|
current = children.get(entity).ok().map(ChildOf::get);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,8 +105,8 @@ fn create_label(text: &str, font: Handle<Font>) -> (Text, TextFont, TextColor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn button_system(
|
fn button_system(
|
||||||
mut interaction_query: Query<(&Interaction, &Parent), (Changed<Interaction>, With<Button>)>,
|
mut interaction_query: Query<(&Interaction, &ChildOf), (Changed<Interaction>, With<Button>)>,
|
||||||
labels_query: Query<(&Children, &Parent), With<Button>>,
|
labels_query: Query<(&Children, &ChildOf), With<Button>>,
|
||||||
mut text_query: Query<&mut Text>,
|
mut text_query: Query<&mut Text>,
|
||||||
mut counter_query: Query<&mut Counter>,
|
mut counter_query: Query<&mut Counter>,
|
||||||
) {
|
) {
|
||||||
@ -119,8 +119,8 @@ fn button_system(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update button labels to match their parent counter
|
// Update button labels to match their parent counter
|
||||||
for (children, parent) in &labels_query {
|
for (children, child_of) in &labels_query {
|
||||||
let counter = counter_query.get(parent.get()).unwrap();
|
let counter = counter_query.get(child_of.get()).unwrap();
|
||||||
let mut text = text_query.get_mut(children[0]).unwrap();
|
let mut text = text_query.get_mut(children[0]).unwrap();
|
||||||
|
|
||||||
**text = counter.0.to_string();
|
**text = counter.0.to_string();
|
||||||
|
Loading…
Reference in New Issue
Block a user