Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hierarchy example #565

Merged
merged 4 commits into from
Oct 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@ path = "examples/ecs/ecs_guide.rs"
name = "parallel_query"
path = "examples/ecs/parallel_query.rs"

[[example]]
name = "hierarchy"
path = "examples/ecs/hierarchy.rs"

[[example]]
name = "breakout"
path = "examples/game/breakout.rs"
Expand Down
112 changes: 112 additions & 0 deletions examples/ecs/hierarchy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
use bevy::prelude::*;

fn main() {
App::build()
.add_default_plugins()
.add_startup_system(setup.system())
.add_system(rotate.system())
.run();
}

fn setup(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut materials: ResMut<Assets<ColorMaterial>>,
) {
commands.spawn(Camera2dComponents::default());
let texture = asset_server.load("assets/branding/icon.png").unwrap();

// Spawn a root entity with no parent
let parent = commands
.spawn(SpriteComponents {
transform: Transform::from_scale(0.75),
material: materials.add(ColorMaterial {
color: Color::WHITE,
texture: Some(texture),
}),
..Default::default()
})
// With that entity as a parent, run a lambda that spawns its children
.with_children(|parent| {
// parent is a ChildBuilder, which has a similar API to Commands
parent.spawn(SpriteComponents {
transform: Transform::from_translation(Vec3::new(250.0, 0.0, 0.0)).with_scale(0.75),
material: materials.add(ColorMaterial {
color: Color::BLUE,
texture: Some(texture),
}),
..Default::default()
});
})
// Store parent entity for next sections
.current_entity()
.unwrap();

// Another way to create a hierarchy is to add a Parent component to an entity,
// which would be added automatically to parents with other methods.
// Similarly, adding a Parent component will automatically add a Children component to the parent.
commands
.spawn(SpriteComponents {
transform: Transform::from_translation(Vec3::new(-250.0, 0.0, 0.0)).with_scale(0.75),
material: materials.add(ColorMaterial {
color: Color::RED,
texture: Some(texture),
}),
..Default::default()
})
// Using the entity from the previous section as the parent:
.with(Parent(parent));

// Another way is to use the push_children function to add children after the parent
// entity has already been spawned.
let child = commands
.spawn(SpriteComponents {
transform: Transform::from_translation(Vec3::new(0.0, 250.0, 0.0)).with_scale(0.75),
material: materials.add(ColorMaterial {
color: Color::GREEN,
texture: Some(texture),
}),
..Default::default()
})
.current_entity()
.unwrap();

// Pushing takes a slice of children to add:
commands.push_children(parent, &[child]);
}

// A simple system to rotate the root entity, and rotate all its children separately
fn rotate(
mut commands: Commands,
time: Res<Time>,
mut parents_query: Query<(Entity, &mut Transform, &mut Children, &Sprite)>,
children_query: Query<(&mut Transform, &Sprite)>,
) {
let angle = std::f32::consts::PI / 2.0;
for (parent, mut transform, mut children, _) in &mut parents_query.iter() {
transform.rotate(Quat::from_rotation_z(-angle * time.delta_seconds));

// To iterate through the entities children, just treat the Children component as a Vec
// Alternatively, you could query entities that have a Parent component
for child in children.iter() {
let mut transform = children_query.get_mut::<Transform>(*child).unwrap();
transform.rotate(Quat::from_rotation_z(angle * 2.0 * time.delta_seconds));
}

// To demonstrate removing children, we'll start to remove the children after a couple of seconds
if time.seconds_since_startup >= 2.0 && children.len() == 3 {
// Using .despawn() on an entity does not remove it from its parent's list of children!
// It must be done manually if using .despawn()
// NOTE: This is a bug. Eventually Bevy will update the children list automatically
let child = children.pop().unwrap();
commands.despawn(child);
}

if time.seconds_since_startup >= 4.0 {
// Alternatively, you can use .despawn_recursive()
// This will remove the entity from its parent's list of children, as well as despawn
// any children the entity has.
commands.despawn_recursive(parent);
}
}
}