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:
Carter Anderson 2025-01-20 14:13:29 -08:00 committed by GitHub
parent 000c362de0
commit ba5e71f53d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 203 additions and 197 deletions

View File

@ -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);
} }
} }

View File

@ -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;
} }

View File

@ -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>();
} }

View File

@ -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)]

View File

@ -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"
); );
} }
} }

View File

@ -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},

View File

@ -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.

View File

@ -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 {

View File

@ -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;

View File

@ -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);

View File

@ -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>,
} }

View File

@ -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>();
} }
} }

View File

@ -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();

View File

@ -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"

View File

@ -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);
} }

View File

@ -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;

View File

@ -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>()?;

View File

@ -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

View File

@ -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.
/// ///

View File

@ -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());

View File

@ -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

View File

@ -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")]

View File

@ -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,

View File

@ -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
}; };

View File

@ -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

View File

@ -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;
}; };

View File

@ -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,
} }
} }

View File

@ -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];

View File

@ -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());

View File

@ -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;

View File

@ -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();
} }

View File

@ -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) {

View File

@ -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);
} }
} }

View File

@ -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();