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 bevy_ecs::bundle::Bundle;
use bevy_ecs::component::ComponentCloneHandler;
use bevy_ecs::hierarchy::Parent;
use bevy_ecs::hierarchy::ChildOf;
use bevy_ecs::reflect::AppTypeRegistry;
use bevy_ecs::{component::Component, world::World};
use bevy_math::Mat4;
@ -142,7 +142,7 @@ fn bench_clone_hierarchy<B: Bundle + Default + GetTypeRegistration>(
for parent_id in current_hierarchy_level {
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);
}
}

View File

@ -65,7 +65,7 @@ pub fn event_propagation(criterion: &mut Criterion) {
struct TestEvent<const N: usize> {}
impl<const N: usize> Event for TestEvent<N> {
type Traversal = &'static Parent;
type Traversal = &'static ChildOf;
const AUTO_PROPAGATE: bool = true;
}

View File

@ -107,7 +107,7 @@ impl Default for App {
{
app.init_resource::<AppTypeRegistry>();
app.register_type::<Name>();
app.register_type::<Parent>();
app.register_type::<ChildOf>();
app.register_type::<Children>();
}

View File

@ -12,7 +12,7 @@ use crate::{
bundle::Bundle,
component::{Component, ComponentCloneHandler, ComponentId, ComponentInfo, Components},
entity::Entity,
hierarchy::{Children, Parent},
hierarchy::{ChildOf, Children},
query::DebugCheckedUnwrap,
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.
pub fn as_child(&mut self, as_child: bool) -> &mut Self {
if as_child {
self.override_component_clone_handler::<Parent>(ComponentCloneHandler::custom_handler(
self.override_component_clone_handler::<ChildOf>(ComponentCloneHandler::custom_handler(
component_clone_parent,
))
} 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);
world.commands().queue(move |world: &mut 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) {
let parent = ctx
.read_source_component::<Parent>()
.read_source_component::<ChildOf>()
.map(|p| p.0)
.expect("Source entity must have Parent component");
world.commands().entity(ctx.target()).insert(Parent(parent));
.expect("Source entity must have a ChildOf component");
world
.commands()
.entity(ctx.target())
.insert(ChildOf(parent));
}
#[cfg(test)]

View File

@ -1,7 +1,7 @@
//! 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
//! [`RelationshipTarget`]: crate::relationship::RelationshipTarget
@ -38,32 +38,32 @@ use log::warn;
/// 3. Ensuring a hierarchy is despawned when an entity is despawned.
/// 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`]
/// 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.
///
/// 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.
///
/// 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::*;
/// # let mut world = World::new();
/// let root = world.spawn_empty().id();
/// let child1 = world.spawn(Parent(root)).id();
/// let child2 = world.spawn(Parent(root)).id();
/// let grandchild = world.spawn(Parent(child1)).id();
/// let child1 = world.spawn(ChildOf(root)).id();
/// let child2 = world.spawn(ChildOf(root)).id();
/// let grandchild = world.spawn(ChildOf(child1)).id();
///
/// assert_eq!(&**world.entity(root).get::<Children>().unwrap(), &[child1, child2]);
/// 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]);
///
/// world.entity_mut(root).despawn();
@ -105,16 +105,16 @@ use log::warn;
)
)]
#[relationship(relationship_target = Children)]
pub struct Parent(pub Entity);
pub struct ChildOf(pub Entity);
impl Parent {
impl ChildOf {
/// Returns the "target" entity.
pub fn get(&self) -> Entity {
self.0
}
}
impl Deref for Parent {
impl Deref for ChildOf {
type Target = Entity;
#[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.
// 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.
impl FromWorld for Parent {
impl FromWorld for ChildOf {
#[inline(always)]
fn from_world(_world: &mut World) -> Self {
Parent(Entity::PLACEHOLDER)
ChildOf(Entity::PLACEHOLDER)
}
}
/// 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.
#[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",
@ -167,14 +167,14 @@ impl Deref for Children {
}
}
/// A type alias over [`RelatedSpawner`] used to spawn child entities containing a [`Parent`] relationship.
pub type ChildSpawner<'w> = RelatedSpawner<'w, Parent>;
/// A type alias over [`RelatedSpawner`] used to spawn child entities containing a [`ChildOf`] relationship.
pub type ChildSpawner<'w> = RelatedSpawner<'w, ChildOf>;
/// A type alias over [`RelatedSpawnerCommands`] used to spawn child entities containing a [`Parent`] relationship.
pub type ChildSpawnerCommands<'w> = RelatedSpawnerCommands<'w, Parent>;
/// A type alias over [`RelatedSpawnerCommands`] used to spawn child entities containing a [`ChildOf`] relationship.
pub type ChildSpawnerCommands<'w> = RelatedSpawnerCommands<'w, ChildOf>;
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 {
self.with_related(func);
self
@ -182,12 +182,12 @@ impl<'w> EntityWorldMut<'w> {
/// Adds the given children to this entity
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
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.
@ -198,31 +198,31 @@ impl<'w> EntityWorldMut<'w> {
pub fn with_child(&mut self, bundle: impl Bundle) -> &mut Self {
let id = self.id();
self.world_scope(|world| {
world.spawn((bundle, Parent(id)));
world.spawn((bundle, ChildOf(id)));
});
self
}
/// Removes the [`Parent`] component, if it exists.
#[deprecated(since = "0.16.0", note = "Use entity_mut.remove::<Parent>()")]
/// Removes the [`ChildOf`] component, if it exists.
#[deprecated(since = "0.16.0", note = "Use entity_mut.remove::<ChildOf>()")]
pub fn remove_parent(&mut self) -> &mut Self {
self.remove::<Parent>();
self.remove::<ChildOf>();
self
}
/// Inserts the [`Parent`] component with the given `parent` entity, if it exists.
#[deprecated(since = "0.16.0", note = "Use entity_mut.insert(Parent(entity))")]
/// Inserts the [`ChildOf`] component with the given `parent` entity, if it exists.
#[deprecated(since = "0.16.0", note = "Use entity_mut.insert(ChildOf(entity))")]
pub fn set_parent(&mut self, parent: Entity) -> &mut Self {
self.insert(Parent(parent));
self.insert(ChildOf(parent));
self
}
}
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(
&mut self,
func: impl FnOnce(&mut RelatedSpawnerCommands<Parent>),
func: impl FnOnce(&mut RelatedSpawnerCommands<ChildOf>),
) -> &mut Self {
self.with_related(func);
self
@ -230,12 +230,12 @@ impl<'a> EntityCommands<'a> {
/// Adds the given children to this entity
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
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.
@ -245,21 +245,21 @@ impl<'a> EntityCommands<'a> {
/// [`with_children`]: EntityCommands::with_children
pub fn with_child(&mut self, bundle: impl Bundle) -> &mut Self {
let id = self.id();
self.commands.spawn((bundle, Parent(id)));
self.commands.spawn((bundle, ChildOf(id)));
self
}
/// Removes the [`Parent`] component, if it exists.
#[deprecated(since = "0.16.0", note = "Use entity_commands.remove::<Parent>()")]
/// Removes the [`ChildOf`] component, if it exists.
#[deprecated(since = "0.16.0", note = "Use entity_commands.remove::<ChildOf>()")]
pub fn remove_parent(&mut self) -> &mut Self {
self.remove::<Parent>();
self.remove::<ChildOf>();
self
}
/// Inserts the [`Parent`] component with the given `parent` entity, if it exists.
#[deprecated(since = "0.16.0", note = "Use entity_commands.insert(Parent(entity))")]
/// Inserts the [`ChildOf`] component with the given `parent` entity, if it exists.
#[deprecated(since = "0.16.0", note = "Use entity_commands.insert(ChildOf(entity))")]
pub fn set_parent(&mut self, parent: Entity) -> &mut Self {
self.insert(Parent(parent));
self.insert(ChildOf(parent));
self
}
}
@ -272,7 +272,7 @@ pub fn validate_parent_has_component<C: Component>(
_: ComponentId,
) {
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;
};
if !world
@ -297,7 +297,7 @@ pub fn validate_parent_has_component<C: Component>(
mod tests {
use crate::{
entity::Entity,
hierarchy::{Children, Parent},
hierarchy::{ChildOf, Children},
relationship::RelationshipTarget,
world::World,
};
@ -338,9 +338,9 @@ mod tests {
fn hierarchy() {
let mut world = World::new();
let root = world.spawn_empty().id();
let child1 = world.spawn(Parent(root)).id();
let grandchild = world.spawn(Parent(child1)).id();
let child2 = world.spawn(Parent(root)).id();
let child1 = world.spawn(ChildOf(root)).id();
let grandchild = world.spawn(ChildOf(child1)).id();
let child2 = world.spawn(ChildOf(root)).id();
// Spawn
let hierarchy = get_hierarchy(&world, root);
@ -356,12 +356,12 @@ mod tests {
);
// Removal
world.entity_mut(child1).remove::<Parent>();
world.entity_mut(child1).remove::<ChildOf>();
let hierarchy = get_hierarchy(&world, root);
assert_eq!(hierarchy, Node::new_with(root, vec![Node::new(child2)]));
// Insert
world.entity_mut(child1).insert(Parent(root));
world.entity_mut(child1).insert(ChildOf(root));
let hierarchy = get_hierarchy(&world, root);
assert_eq!(
hierarchy,
@ -420,10 +420,10 @@ mod tests {
fn self_parenting_invalid() {
let mut world = World::new();
let id = world.spawn_empty().id();
world.entity_mut(id).insert(Parent(id));
world.entity_mut(id).insert(ChildOf(id));
assert!(
world.entity(id).get::<Parent>().is_none(),
"invalid Parent relationships should self-remove"
world.entity(id).get::<ChildOf>().is_none(),
"invalid ChildOf relationships should self-remove"
);
}
@ -432,10 +432,10 @@ mod tests {
let mut world = World::new();
let parent = world.spawn_empty().id();
world.entity_mut(parent).despawn();
let id = world.spawn(Parent(parent)).id();
let id = world.spawn(ChildOf(parent)).id();
assert!(
world.entity(id).get::<Parent>().is_none(),
"invalid Parent relationships should self-remove"
world.entity(id).get::<ChildOf>().is_none(),
"invalid ChildOf relationships should self-remove"
);
}
@ -443,12 +443,12 @@ mod tests {
fn reinsert_same_parent() {
let mut world = World::new();
let parent = world.spawn_empty().id();
let id = world.spawn(Parent(parent)).id();
world.entity_mut(id).insert(Parent(parent));
let id = world.spawn(ChildOf(parent)).id();
world.entity_mut(id).insert(ChildOf(parent));
assert_eq!(
Some(&Parent(parent)),
world.entity(id).get::<Parent>(),
"Parent should still be there"
Some(&ChildOf(parent)),
world.entity(id).get::<ChildOf>(),
"ChildOf should still be there"
);
}
}

View File

@ -76,7 +76,7 @@ pub mod prelude {
component::{require, Component},
entity::{Entity, EntityBorrow, EntityMapper},
event::{Event, EventMutator, EventReader, EventWriter, Events},
hierarchy::{ChildSpawner, ChildSpawnerCommands, Children, Parent},
hierarchy::{ChildOf, ChildSpawner, ChildSpawnerCommands, Children},
name::{Name, NameOrEntity},
observer::{CloneEntityWithObserversExt, Observer, Trigger},
query::{Added, AnyOf, Changed, Has, Or, QueryBuilder, QueryState, With, Without},

View File

@ -800,9 +800,9 @@ mod tests {
}
#[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> {
Some(item.0)
}
@ -812,7 +812,7 @@ mod tests {
struct EventPropagating;
impl Event for EventPropagating {
type Traversal = &'static Parent;
type Traversal = &'static ChildOf;
const AUTO_PROPAGATE: bool = true;
}
@ -1198,7 +1198,7 @@ mod tests {
.id();
let child = world
.spawn(Parent(parent))
.spawn(ChildOf(parent))
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("child");
})
@ -1225,7 +1225,7 @@ mod tests {
.id();
let child = world
.spawn(Parent(parent))
.spawn(ChildOf(parent))
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("child");
})
@ -1255,7 +1255,7 @@ mod tests {
.id();
let child = world
.spawn(Parent(parent))
.spawn(ChildOf(parent))
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("child");
})
@ -1285,7 +1285,7 @@ mod tests {
.id();
let child = world
.spawn(Parent(parent))
.spawn(ChildOf(parent))
.observe(
|mut trigger: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("child");
@ -1315,14 +1315,14 @@ mod tests {
.id();
let child_a = world
.spawn(Parent(parent))
.spawn(ChildOf(parent))
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("child_a");
})
.id();
let child_b = world
.spawn(Parent(parent))
.spawn(ChildOf(parent))
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("child_b");
})
@ -1372,7 +1372,7 @@ mod tests {
.id();
let child_a = world
.spawn(Parent(parent_a))
.spawn(ChildOf(parent_a))
.observe(
|mut trigger: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("child_a");
@ -1389,7 +1389,7 @@ mod tests {
.id();
let child_b = world
.spawn(Parent(parent_b))
.spawn(ChildOf(parent_b))
.observe(|_: Trigger<EventPropagating>, mut res: ResMut<Order>| {
res.observed("child_b");
})
@ -1416,8 +1416,8 @@ mod tests {
});
let grandparent = world.spawn_empty().id();
let parent = world.spawn(Parent(grandparent)).id();
let child = world.spawn(Parent(parent)).id();
let parent = world.spawn(ChildOf(grandparent)).id();
let child = world.spawn(ChildOf(parent)).id();
// TODO: ideally this flush is not necessary, but right now observe() returns WorldEntityMut
// and therefore does not automatically flush.
@ -1441,8 +1441,8 @@ mod tests {
);
let grandparent = world.spawn(A).id();
let parent = world.spawn(Parent(grandparent)).id();
let child = world.spawn((A, Parent(parent))).id();
let parent = world.spawn(ChildOf(grandparent)).id();
let child = world.spawn((A, ChildOf(parent))).id();
// TODO: ideally this flush is not necessary, but right now observe() returns WorldEntityMut
// 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
/// 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 [`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;
/// #[derive(Component)]
/// #[relationship(relationship_target = Children)]
/// pub struct Parent(pub Entity);
/// pub struct ChildOf(pub Entity);
///
/// #[derive(Component)]
/// #[relationship_target(relationship = Parent)]
/// #[relationship_target(relationship = ChildOf)]
/// pub struct Children(Vec<Entity>);
/// ```
///
@ -53,10 +53,10 @@ use log::warn;
/// # use bevy_ecs::entity::Entity;
/// #[derive(Component)]
/// #[relationship(relationship_target = Children)]
/// pub struct Parent(pub Entity);
/// pub struct ChildOf(pub Entity);
///
/// #[derive(Component)]
/// #[relationship_target(relationship = Parent, despawn_descendants)]
/// #[relationship_target(relationship = ChildOf, despawn_descendants)]
/// pub struct Children(Vec<Entity>);
/// ```
pub trait Relationship: Component + Sized {

View File

@ -144,7 +144,7 @@ impl<E: Event + Clone> Event for FocusedInput<E> {
#[derive(QueryData)]
/// These are for accessing components defined on the targeted entity
pub struct WindowTraversal {
parent: Option<&'static Parent>,
parent: Option<&'static ChildOf>,
window: Option<&'static Window>,
}
@ -279,7 +279,7 @@ pub trait IsFocused {
/// When working with the entire [`World`], consider using the [`IsFocused`] instead.
#[derive(SystemParam)]
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_visible: Option<Res<'w, InputFocusVisible>>,
}
@ -327,7 +327,7 @@ impl IsFocused for World {
if e == entity {
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;
} else {
return false;

View File

@ -29,7 +29,7 @@ use bevy_ecs::prelude::ReflectComponent;
use bevy_ecs::{
component::Component,
entity::Entity,
hierarchy::{Children, Parent},
hierarchy::{ChildOf, Children},
observer::Trigger,
query::{With, Without},
system::{Commands, Query, Res, ResMut, SystemParam},
@ -157,7 +157,7 @@ pub struct TabNavigation<'w, 's> {
Without<TabGroup>,
>,
// Query for parents.
parent_query: Query<'w, 's, &'static Parent>,
parent_query: Query<'w, 's, &'static ChildOf>,
}
impl TabNavigation<'_, '_> {
@ -371,8 +371,8 @@ mod tests {
let world = app.world_mut();
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_2 = world.spawn((TabIndex(1), 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), ChildOf(tab_group_entity))).id();
let mut system_state: SystemState<TabNavigation> = SystemState::new(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.
#[derive(QueryData)]
pub struct PointerTraversal {
parent: Option<&'static Parent>,
parent: Option<&'static ChildOf>,
window: Option<&'static Window>,
}

View File

@ -7,7 +7,7 @@ use bevy_ecs::{
component::ComponentId,
entity::Entity,
event::EventCursor,
hierarchy::Parent,
hierarchy::ChildOf,
query::QueryBuilder,
reflect::{AppTypeRegistry, ReflectComponent, ReflectResource},
removal_detection::RemovedComponentEntity,
@ -841,7 +841,7 @@ pub fn process_remote_reparent_request(
// If `None`, remove the entities' parents.
else {
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)]
#[require(InheritedVisibility, ViewVisibility)]
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.
#[default]
@ -47,7 +47,7 @@ pub enum Visibility {
/// An entity with `Visibility::Visible` will be unconditionally visible.
///
/// Note that an entity with `Visibility::Visible` will be visible regardless of whether the
/// [`Parent`] entity is hidden.
/// [`ChildOf`] target entity is hidden.
Visible,
}
@ -316,7 +316,7 @@ pub enum VisibilitySystems {
/// Label for [`update_frusta`] in [`CameraProjectionPlugin`](crate::camera::CameraProjectionPlugin).
UpdateFrusta,
/// Label for the system propagating the [`InheritedVisibility`] in a
/// [`Parent`] / [`Children`] hierarchy.
/// [`ChildOf`] / [`Children`] hierarchy.
VisibilityPropagate,
/// Label for the [`check_visibility`] system updating [`ViewVisibility`]
/// of each entity and the [`VisibleEntities`] of each view.\
@ -387,10 +387,10 @@ pub fn update_frusta(
fn visibility_propagate_system(
changed: Query<
(Entity, &Visibility, Option<&Parent>, Option<&Children>),
(Entity, &Visibility, Option<&ChildOf>, Option<&Children>),
(
With<InheritedVisibility>,
Or<(Changed<Visibility>, Changed<Parent>)>,
Or<(Changed<Visibility>, Changed<ChildOf>)>,
),
>,
mut visibility_query: Query<(&Visibility, &mut InheritedVisibility)>,
@ -761,7 +761,7 @@ mod test {
.entity_mut(parent2)
.insert(Visibility::Visible);
// 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
app.update();

View File

@ -203,7 +203,7 @@ mod tests {
hash_map::EntityHashMap, Entity, EntityMapper, MapEntities, VisitEntities,
VisitEntitiesMut,
},
hierarchy::Parent,
hierarchy::ChildOf,
reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities, ReflectResource},
system::Resource,
world::World,
@ -269,7 +269,7 @@ mod tests {
world
.resource_mut::<AppTypeRegistry>()
.write()
.register::<Parent>();
.register::<ChildOf>();
let original_parent_entity = world.spawn_empty().id();
let original_child_entity = world.spawn_empty().id();
world
@ -305,7 +305,7 @@ mod tests {
world
.get_entity(original_child_entity)
.unwrap()
.get::<Parent>()
.get::<ChildOf>()
.unwrap()
.get(),
"something about reloading the scene is touching entities with the same scene Ids"
@ -315,7 +315,7 @@ mod tests {
world
.get_entity(from_scene_parent_entity)
.unwrap()
.get::<Parent>()
.get::<ChildOf>()
.unwrap()
.get(),
"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
.get_entity(from_scene_child_entity)
.unwrap()
.get::<Parent>()
.get::<ChildOf>()
.expect("something is wrong with this test, and the scene components don't have a parent/child relationship")
.get(),
"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::{
entity::{hash_map::EntityHashMap, Entity},
event::{Event, EventCursor, Events},
hierarchy::Parent,
hierarchy::ChildOf,
reflect::AppTypeRegistry,
system::Resource,
world::{Mut, World},
@ -377,7 +377,7 @@ impl SceneSpawner {
for (instance_id, parent) in scenes_with_parent {
if let Some(instance) = self.spawned_instances.get(&instance_id) {
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
if !world
.get_entity(entity)
@ -386,7 +386,7 @@ impl SceneSpawner {
// scene have a parent
// Entities that wouldn't exist anymore are also skipped
// 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);
}

View File

@ -455,13 +455,13 @@ pub fn detect_text_needs_rerender<Root: Component>(
),
>,
changed_spans: Query<
(Entity, Option<&Parent>, Has<TextLayout>),
(Entity, Option<&ChildOf>, Has<TextLayout>),
(
Or<(
Changed<TextSpan>,
Changed<TextFont>,
Changed<Children>,
Changed<Parent>, // Included to detect broken text block hierarchies.
Changed<ChildOf>, // Included to detect broken text block hierarchies.
Added<TextLayout>,
)>,
With<TextSpan>,
@ -469,7 +469,7 @@ pub fn detect_text_needs_rerender<Root: Component>(
),
>,
mut computed: Query<(
Option<&Parent>,
Option<&ChildOf>,
Option<&mut ComputedTextBlock>,
Has<TextSpan>,
)>,
@ -515,7 +515,7 @@ pub fn detect_text_needs_rerender<Root: Component>(
// is outweighed by the expense of tracking visited spans.
loop {
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",
entity, parent));
break;

View File

@ -2,7 +2,7 @@
//! while preserving [`GlobalTransform`].
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
/// entity's [`GlobalTransform`].
@ -10,7 +10,7 @@ pub trait BuildChildrenTransformExt {
/// Change this entity's parent while preserving this entity's [`GlobalTransform`]
/// 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
/// the next time commands are applied
@ -64,7 +64,7 @@ impl BuildChildrenTransformExt for EntityWorldMut<'_> {
fn remove_parent_in_place(&mut self) -> &mut Self {
let child = self.id();
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.
let mut update_transform = || {
let child_global = *world.get_entity(child).ok()?.get::<GlobalTransform>()?;

View File

@ -28,7 +28,7 @@ use {
/// ## [`Transform`] and [`GlobalTransform`]
///
/// [`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
/// 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`] 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.
///

View File

@ -1,7 +1,7 @@
//! System parameter for computing up-to-date [`GlobalTransform`]s.
use bevy_ecs::{
hierarchy::Parent,
hierarchy::ChildOf,
prelude::Entity,
query::QueryEntityError,
system::{Query, SystemParam},
@ -18,7 +18,7 @@ use crate::components::{GlobalTransform, Transform};
/// the last time the transform propagation systems ran.
#[derive(SystemParam)]
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>,
}
@ -84,7 +84,7 @@ mod tests {
use core::f32::consts::TAU;
use bevy_app::App;
use bevy_ecs::{hierarchy::Parent, system::SystemState};
use bevy_ecs::{hierarchy::ChildOf, system::SystemState};
use bevy_math::{Quat, Vec3};
use crate::{
@ -124,7 +124,7 @@ mod tests {
let mut e = app.world_mut().spawn(transform);
if let Some(entity) = entity {
e.insert(Parent(entity));
e.insert(ChildOf(entity));
}
entity = Some(e.id());

View File

@ -11,13 +11,13 @@ pub fn sync_simple_transforms(
(&Transform, &mut GlobalTransform),
(
Or<(Changed<Transform>, Added<GlobalTransform>)>,
Without<Parent>,
Without<ChildOf>,
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.
query
@ -43,11 +43,14 @@ pub fn sync_simple_transforms(
pub fn propagate_transforms(
mut root_query: Query<
(Entity, &Children, Ref<Transform>, &mut GlobalTransform),
Without<Parent>,
Without<ChildOf>,
>,
mut orphaned: RemovedComponents<Parent>,
transform_query: Query<(Ref<Transform>, &mut GlobalTransform, Option<&Children>), With<Parent>>,
parent_query: Query<(Entity, Ref<Parent>), With<GlobalTransform>>,
mut orphaned: RemovedComponents<ChildOf>,
transform_query: Query<
(Ref<Transform>, &mut GlobalTransform, Option<&Children>),
With<ChildOf>,
>,
parent_query: Query<(Entity, Ref<ChildOf>), With<GlobalTransform>>,
mut orphaned_entities: Local<Vec<Entity>>,
) {
orphaned_entities.clear();
@ -109,9 +112,9 @@ unsafe fn propagate_recursive(
parent: &GlobalTransform,
transform_query: &Query<
(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,
mut changed: bool,
) {
@ -130,7 +133,7 @@ unsafe fn propagate_recursive(
// \ /
// 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.
//
// 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 parent = commands.spawn(offset_transform(4.4)).id();
let child = commands.spawn(offset_transform(5.5)).id();
commands.entity(parent).insert(Parent(root));
commands.entity(child).insert(Parent(parent));
commands.entity(parent).insert(ChildOf(root));
commands.entity(child).insert(ChildOf(parent));
command_queue.apply(&mut world);
schedule.run(&mut world);
@ -217,7 +220,7 @@ mod test {
// Remove parent of `parent`
let mut command_queue = CommandQueue::default();
let mut commands = Commands::new(&mut command_queue, &world);
commands.entity(parent).remove::<Parent>();
commands.entity(parent).remove::<ChildOf>();
command_queue.apply(&mut world);
schedule.run(&mut world);
@ -230,7 +233,7 @@ mod test {
// Remove parent of `child`
let mut command_queue = CommandQueue::default();
let mut commands = Commands::new(&mut command_queue, &world);
commands.entity(child).remove::<Parent>();
commands.entity(child).remove::<ChildOf>();
command_queue.apply(&mut world);
schedule.run(&mut world);
@ -426,7 +429,7 @@ mod test {
#[should_panic]
fn panic_when_hierarchy_cycle() {
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.
let mut temp = World::new();
let mut app = App::new();
@ -456,25 +459,25 @@ mod test {
core::mem::swap(
#[expect(
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 {
&mut *app
.world_mut()
.entity_mut(child)
.get_mut_assume_mutable::<Parent>()
.get_mut_assume_mutable::<ChildOf>()
.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(
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 {
&mut *temp
.entity_mut(grandchild)
.get_mut_assume_mutable::<Parent>()
.get_mut_assume_mutable::<ChildOf>()
.unwrap()
},
);
@ -514,7 +517,7 @@ mod test {
.abs_diff_eq(2. * translation, 0.1));
// Reparent child
world.entity_mut(child).remove::<Parent>();
world.entity_mut(child).remove::<ChildOf>();
world.entity_mut(parent).add_child(child);
// Run schedule to propagate transforms

View File

@ -43,17 +43,17 @@ impl GhostNode {
#[cfg(feature = "ghost_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)]
pub struct UiRootNodes<'w, 's> {
root_node_query: Query<'w, 's, Entity, (With<Node>, Without<Parent>)>,
root_ghost_node_query: Query<'w, 's, Entity, (With<GhostNode>, Without<Parent>)>,
root_node_query: Query<'w, 's, Entity, (With<Node>, Without<ChildOf>)>,
root_ghost_node_query: Query<'w, 's, Entity, (With<GhostNode>, Without<ChildOf>)>,
all_nodes_query: Query<'w, 's, Entity, With<Node>>,
ui_children: UiChildren<'w, 's>,
}
#[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")]
impl<'w, 's> UiRootNodes<'w, 's> {
@ -80,7 +80,7 @@ pub struct UiChildren<'w, 's> {
changed_children_query: Query<'w, 's, Entity, Changed<Children>>,
children_query: Query<'w, 's, &'static Children>,
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"))]
@ -89,7 +89,7 @@ pub struct UiChildren<'w, 's> {
pub struct UiChildren<'w, 's> {
ui_children_query: Query<'w, 's, Option<&'static Children>, With<Node>>,
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")]

View File

@ -107,7 +107,7 @@ pub fn ui_layout_system(
Option<&mut ContentSize>,
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,
mut removed_components: UiLayoutSystemRemovedComponentParam,
mut node_transform_query: Query<(
@ -844,7 +844,7 @@ mod tests {
ui_schedule.run(&mut world);
let overlap_check = world
.query_filtered::<(Entity, &ComputedNode, &GlobalTransform), Without<Parent>>()
.query_filtered::<(Entity, &ComputedNode, &GlobalTransform), Without<ChildOf>>()
.iter(&world)
.fold(
Option::<(Rect, bool)>::None,

View File

@ -179,7 +179,7 @@ fn update_accessibility_nodes(
Entity,
&AccessibilityNode,
Option<&Children>,
Option<&Parent>,
Option<&ChildOf>,
)>,
node_entities: Query<Entity, With<AccessibilityNode>>,
) {
@ -218,7 +218,7 @@ fn update_adapter(
Entity,
&AccessibilityNode,
Option<&Children>,
Option<&Parent>,
Option<&ChildOf>,
)>,
node_entities: Query<Entity, With<AccessibilityNode>>,
primary_window: &Window,
@ -253,12 +253,12 @@ fn update_adapter(
#[inline]
fn queue_node_for_update(
node_entity: Entity,
parent: Option<&Parent>,
child_of: Option<&ChildOf>,
node_entities: &Query<Entity, With<AccessibilityNode>>,
window_children: &mut Vec<NodeId>,
) {
let should_push = if let Some(parent) = parent {
!node_entities.contains(parent.get())
let should_push = if let Some(child_of) = child_of {
!node_entities.contains(child_of.get())
} else {
true
};

View File

@ -2,7 +2,7 @@
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.
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
[`Visibility`]: https://docs.rs/bevy/*/bevy/render/view/struct.Visibility.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

View File

@ -432,7 +432,7 @@ fn reset_sphere_position(
fn move_sphere(
mouse_button_input: Res<ButtonInput<MouseButton>>,
pointers: Query<&PointerInteraction>,
mut meshes: Query<(&Name, &Parent), With<Mesh3d>>,
mut meshes: Query<(&Name, &ChildOf), With<Mesh3d>>,
mut transforms: Query<&mut Transform>,
app_status: Res<AppStatus>,
) {
@ -445,11 +445,11 @@ fn move_sphere(
}
// Find the sphere.
let Some(parent) = meshes
let Some(child_of) = meshes
.iter_mut()
.filter_map(|(name, parent)| {
.filter_map(|(name, child_of)| {
if &**name == "Sphere" {
Some(parent)
Some(child_of)
} else {
None
}
@ -460,7 +460,7 @@ fn move_sphere(
};
// 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;
};

View File

@ -175,19 +175,19 @@ fn setup(
fn set_visibility_ranges(
mut commands: Commands,
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.
for new_mesh in new_meshes.iter_mut() {
// Search for the nearest ancestor `MainModel` component.
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 {
main_model = Some(model);
break;
}
match parent {
Some(parent) => current = parent.0,
match child_of {
Some(child_of) => current = child_of.0,
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`.
fn joint_animation(
time: Res<Time>,
parent_query: Query<&Parent, With<SkinnedMesh>>,
children_query: Query<&Children>,
children: Query<&ChildOf, With<SkinnedMesh>>,
parents: Query<&Children>,
mut transform_query: Query<&mut Transform>,
) {
// 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.
let mesh_node_entity = skinned_mesh_parent.get();
let mesh_node_entity = child_of.get();
// 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.
let first_joint_entity = mesh_node_children[1];
let first_joint_entity = mesh_node_parent[1];
// 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.
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
// Alternatively, you could query entities that have a Parent component
// Alternatively, you could query entities that have a ChildOf component
for child in children {
if let Ok(mut transform) = transform_query.get_mut(*child) {
transform.rotate_z(PI * time.delta_secs());

View File

@ -51,9 +51,9 @@ struct Attack {
// two important pieces of information:
impl Event for Attack {
// 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.
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
// false, it will only propagate following a call to `Trigger::propagate(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();
}

View File

@ -380,7 +380,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
fn toggle_debug_overlay(
input: Res<ButtonInput<KeyCode>>,
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");
if input.just_pressed(KeyCode::Space) {

View File

@ -37,7 +37,7 @@ impl Clips {
fn assign_clips(
mut players: Query<&mut AnimationPlayer>,
targets: Query<(Entity, &AnimationTarget)>,
parents: Query<&Parent>,
children: Query<&ChildOf>,
scene_handle: Res<SceneHandle>,
clips: Res<Assets<AnimationClip>>,
gltf_assets: Res<Assets<Gltf>>,
@ -109,7 +109,7 @@ fn assign_clips(
}
// 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(
mut interaction_query: Query<(&Interaction, &Parent), (Changed<Interaction>, With<Button>)>,
labels_query: Query<(&Children, &Parent), With<Button>>,
mut interaction_query: Query<(&Interaction, &ChildOf), (Changed<Interaction>, With<Button>)>,
labels_query: Query<(&Children, &ChildOf), With<Button>>,
mut text_query: Query<&mut Text>,
mut counter_query: Query<&mut Counter>,
) {
@ -119,8 +119,8 @@ fn button_system(
}
// Update button labels to match their parent counter
for (children, parent) in &labels_query {
let counter = counter_query.get(parent.get()).unwrap();
for (children, child_of) in &labels_query {
let counter = counter_query.get(child_of.get()).unwrap();
let mut text = text_query.get_mut(children[0]).unwrap();
**text = counter.0.to_string();