Hierarchical (Parent/Child) Entities

Relevant official examples: hierarchy, parenting.


Technically, the Entities/Components themselves cannot form a hierarchy (it is a flat data structure). However, logical hierarchies are a common pattern in games.

Bevy supports creating such a logical link between entities, to form a virtual "hierarchy", by simply adding Parent and Children components on the respective entities.

Commands has methods for adding children to entities, which automatically add the correct components:

// spawn the parent and get its Entity id
let parent = commands.spawn_bundle(MyParentBundle::default())
    .id();

// do the same for the child
let child = commands.spawn_bundle(MyChildBundle::default())
    .id();

// add the child to the parent
commands.entity(parent).push_children(&[child]);

// you can also use `with_children`:
commands.spawn_bundle(MyParentBundle::default())
    .with_children(|parent| {
        parent.spawn_bundle(MyChildBundle::default());
    });

You can despawn an entire hierarchy with a single command:

fn close_menu(
    mut commands: Commands,
    query: Query<Entity, With<MainMenuUI>>,
) {
    for entity in query.iter() {
        // despawn the entity and its children
        commands.entity(entity).despawn_recursive();
    }
}

Accessing the Parent or Children

To make a system that works with the hierarchy, you typically need two queries:

  • one with the components you need from the child entities
  • one with the components you need from the parent entities

One of the two queries should include the appropriate component, to obtain the entity ids to use with the other one:

  • Parent in the child query, if you want to iterate entities and look up their parents, or
  • Children in the parent query, if you want to iterate entities and look up their children

For example, if we want to get the Transform of cameras that have a parent, and the GlobalTransform of their parent:

fn camera_with_parent(
    q_child: Query<(&Parent, &Transform), With<Camera>>,
    q_parent: Query<&GlobalTransform>,
) {
    for (parent, child_transform) in q_child.iter() {
        // `parent` contains the Entity ID we can use
        // to query components from the parent:
        let parent_global_transform = q_parent.get(parent.0);

        // do something with the components
    }
}

As another example, say we are making a strategy game, and we have Units that are children of a Squad. Say we need to make a system that works on each Squad, and it needs some information about the children:

fn process_squad_damage(
    q_parent: Query<(&MySquadDamage, &Children)>,
    q_child: Query<&MyUnitHealth>,
) {
    // get the properties of each squad
    for (squad_dmg, children) in q_parent.iter() {
        // `children` is a collection of Entity IDs
        for &child in children.iter() {
            // get the health of each child unit
            let health = q_child.get(child);

            // do something
        }
    }
}

Relative Transforms

If your entities represent "objects in the game world", you probably expect the child to be positioned relative to the parent and move with it.

All Bundles that come with Bevy provide this behavior automatically.

If you are not using such a bundle, you need to make sure to add these components to both the parent and the child: GlobalTransform and Transform.

The Transform represents the relative position. You can manipulate it directly.

The GlobalTransform represents the absolute position. It is managed by bevy internally; do not manipulate it yourself.

For more info, see the dedicated page about transforms.