bevy/errors/B0004.md
Nicola Papale 6c5403cf47 Add warning when a hierarchy component is missing (#5590)
# Objective

A common pitfall since 0.8 is the requirement on `ComputedVisibility`
being present on all ancestors of an entity that itself has
`ComputedVisibility`, without which, the entity becomes invisible.

I myself hit the issue and got very confused, and saw a few people hit
it as well, so it makes sense to provide a hint of what to do when such
a situation is encountered.

- Fixes #5849
- Closes #5616
- Closes #2277 
- Closes #5081

## Solution

We now check that all entities with both a `Parent` and a
`ComputedVisibility` component have parents that themselves have a
`ComputedVisibility` component.

Note that the warning is only printed once.

We also add a similar warning to `GlobalTransform`.

This only emits a warning. Because sometimes it could be an intended
behavior.

Alternatives:
- Do nothing and keep repeating to newcomers how to avoid recurring
  pitfalls
- Make the transform and visibility propagation tolerant to missing
  components (#5616)
- Probably archetype invariants, though the current draft would not
  allow detecting that kind of errors

---

## Changelog

- Add a warning when encountering dubious component hierarchy structure


Co-authored-by: Nicola Papale <nicopap@users.noreply.github.com>
2022-09-19 16:12:11 +00:00

4 KiB

B0004

A runtime warning.

An Entity with a hierarchy-inherited component has a Parent without the hierarchy-inherited component in question.

The hierarchy-inherited components defined in bevy include:

Third party plugins may also define their own hierarchy components, so read the warning message carefully and pay attention to the exact type of the missing component.

To fix this warning, add the missing hierarchy component to all ancestors of entities with the hierarchy component you wish to use.

The following code will cause a warning to be emitted:

use bevy::prelude::*;

// WARNING: this code is buggy
fn setup_cube(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    commands
        .spawn_bundle(TransformBundle::default())
        .with_children(|parent| {
            // cube
            parent.spawn_bundle(PbrBundle {
                mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
                material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()),
                transform: Transform::from_xyz(0.0, 0.5, 0.0),
                ..default()
            });
        });

    // camera
    commands.spawn_bundle(Camera3dBundle {
        transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
        ..default()
    });
}

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_startup_system(setup_cube)
        .run();
}

This code will not show a cube on screen. This is because the entity spawned with commands.spawn_bundle(…) doesn't have a ComputedVisibility component. Since the cube is spawned as a child of an entity without the ComputedVisibility component, it will not be visible at all.

To fix this, you must use SpatialBundle over TransformBundle, as follows:

use bevy::prelude::*;

fn setup_cube(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    commands
        // We use SpatialBundle instead of TransformBundle, it contains the
        // ComputedVisibility component needed to display the cube,
        // In addition to the Transform and GlobalTransform components.
        .spawn_bundle(SpatialBundle::default())
        .with_children(|parent| {
            // cube
            parent.spawn_bundle(PbrBundle {
                mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
                material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()),
                transform: Transform::from_xyz(0.0, 0.5, 0.0),
                ..default()
            });
        });

    // camera
    commands.spawn_bundle(Camera3dBundle {
        transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
        ..default()
    });
}

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_startup_system(setup_cube)
        .run();
}

A similar problem occurs when the GlobalTransform component is missing. However, when a parent GlobalTransform is missing, it will simply prevent all transform propagation, including when updating the Transform component of the child.

You will most likely encounter this warning when loading a scene as a child of a pre-existing Entity that does not have the proper components.