Skip to content

Hierarchy Child Global Transforms are Not Updated When Spawned as a Child #1354

@zicklag

Description

@zicklag

Bevy version

af67231

Operating system & version

Pop!_OS ( Ubuntu ) 20.04

What you did

Here is a complete, simple demonstration program. We spawn a parent sprite in the setup system, then in the load_child system, we spawn a child sprite with a (-50, -50) offset translation. We also have the move_parent system, which just moves the parent sprite.

use bevy::prelude::*;

fn main() {
    App::build()
        .add_plugins(DefaultPlugins)
        .add_startup_system(setup.system())
        // Comment out the move_parent line below to witness the bugginess 😜
        .add_system(move_parent.system())
        .add_system(load_child.system())
        .run();
}

struct TheParentEnt;
struct Loaded;

fn setup(
    commands: &mut Commands,
    asset_server: Res<AssetServer>,
    mut materials: ResMut<Assets<ColorMaterial>>,
) {
    // Spawn camera
    commands.spawn(Camera2dBundle::default());

    // Load parent sprite
    let texture = asset_server.load("textures/rpg/mobs/boss_bee.png");
    // Spawn parent
    commands
        .spawn(SpriteBundle {
            material: materials.add(ColorMaterial::texture(texture)),
            ..Default::default()
        })
        .with(TheParentEnt);
}

// Move the parent slowly to the left
fn move_parent(mut query: Query<&mut Transform, With<TheParentEnt>>) {
    for mut trans in query.iter_mut() {
        trans.translation.x -= 0.1;
    }
}

// Load the child sprite
fn load_child(
    commands: &mut Commands,
    query: Query<Entity, (Without<Loaded>, With<TheParentEnt>)>,
    asset_server: Res<AssetServer>,
    mut materials: ResMut<Assets<ColorMaterial>>,
) {
    for ent in query.iter() {
        // Spawn the child sprite
        let texture = asset_server.load("textures/rpg/chars/hat-guy/hat-guy.png");
        commands
            .spawn(SpriteBundle {
                material: materials.add(ColorMaterial::texture(texture)),
                transform: Transform::from_translation(Vec3::new(-50., -50., 0.)),
                ..Default::default()
            })
            .with(Parent(ent));

        // Prevent processing parent sprite again by marking it loaded
        commands.insert_one(ent, Loaded);
    }
}

What you expected to happen

When running the example below without changes, everything goes as expected, you have the child sprite moving along with the parent, but offset to the left and down from the parent sprite.

When commenting out the move_parent system, the only difference should be that the sprites aren't moving. The child sprite should still be offset to the left and down from the parent sprite.

What actually happened

When you comment out the move_parent system, when the child sprite is spawned, instead of being offset from the parent, it actually ends up in the center of the world.

Additional information

It seems that the GlobalTransform of the child sprite is not updated when it is spawned as a child, until the parent transform is actually changed. Thus, when the move_parent system is active, the child's transform is properly updated, but if the parent doesn't move, then the child's GlobalTransform is never updated and it remains in the center of the universe!

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-TransformTranslations, rotations and scalesC-UsabilityA targeted quality-of-life change that makes Bevy easier to useS-User-ErrorThis issue was caused by a mistake in the user's approach

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions