Skip to content

Commit 3655f24

Browse files
committed
spawn api: ecs/hierarchy.rs
- Update examples to showcase Children, children!, SpawnIter, and related! usage
1 parent a0a8f33 commit 3655f24

File tree

1 file changed

+262
-6
lines changed

1 file changed

+262
-6
lines changed

examples/ecs/hierarchy.rs

Lines changed: 262 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,107 @@
44
//! [`Transform`] and [`Visibility`] from parents to children down the hierarchy,
55
//! resulting in a final [`GlobalTransform`] and [`InheritedVisibility`] component for each entity.
66
7-
use std::f32::consts::*;
7+
use std::{f32::consts::*, time::Duration};
88

99
use bevy::{color::palettes::css::*, prelude::*};
1010

1111
fn main() {
1212
App::new()
1313
.add_plugins(DefaultPlugins)
1414
.add_systems(Startup, setup)
15-
.add_systems(Update, rotate)
15+
.init_state::<Scene>()
16+
.insert_resource(Delta(Duration::ZERO))
17+
.add_systems(OnEnter(Scene::WithChildren), setup_with_children)
18+
.add_systems(OnEnter(Scene::ChildrenSpawn), setup_children_spawn)
19+
.add_systems(OnEnter(Scene::ChildrenMacro), spawn_children_macro)
20+
.add_systems(OnEnter(Scene::ChildrenIter), setup_children_iter)
21+
.add_systems(OnEnter(Scene::Related), setup_children_related)
22+
.add_systems(Update, (rotate, switch_scene))
1623
.run();
1724
}
1825

19-
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
26+
#[derive(Debug, Clone, Eq, PartialEq, Hash, States, Default)]
27+
#[states(scoped_entities)]
28+
enum Scene {
29+
#[default]
30+
WithChildren,
31+
ChildrenSpawn,
32+
ChildrenMacro,
33+
ChildrenIter,
34+
Related,
35+
}
36+
37+
impl Scene {
38+
fn next(&self) -> Self {
39+
match self {
40+
Scene::WithChildren => Scene::ChildrenSpawn,
41+
Scene::ChildrenSpawn => Scene::ChildrenMacro,
42+
Scene::ChildrenMacro => Scene::ChildrenIter,
43+
Scene::ChildrenIter => Scene::Related,
44+
Scene::Related => Scene::WithChildren,
45+
}
46+
}
47+
}
48+
49+
fn switch_scene(
50+
keyboard: Res<ButtonInput<KeyCode>>,
51+
scene: Res<State<Scene>>,
52+
mut next_scene: ResMut<NextState<Scene>>,
53+
) {
54+
if keyboard.just_pressed(KeyCode::Space) {
55+
info!("Switching scene");
56+
next_scene.set(scene.get().next());
57+
}
58+
}
59+
60+
fn setup(mut commands: Commands) {
2061
commands.spawn(Camera2d);
62+
}
63+
64+
#[derive(Resource)]
65+
struct Delta(Duration);
66+
67+
fn setup_common(
68+
commands: &mut Commands,
69+
time: &Res<Time>,
70+
delta: &mut ResMut<Delta>,
71+
title: &str,
72+
stage: Scene,
73+
) {
74+
delta.0 = time.elapsed();
75+
commands.spawn((
76+
Text::new(title),
77+
TextFont {
78+
font: Default::default(),
79+
font_size: 36.,
80+
..default()
81+
},
82+
DespawnOnExitState(stage),
83+
));
84+
}
85+
86+
fn setup_with_children(
87+
mut commands: Commands,
88+
asset_server: Res<AssetServer>,
89+
time: Res<Time>,
90+
mut delta: ResMut<Delta>,
91+
) {
2192
let texture = asset_server.load("branding/icon.png");
2293

94+
setup_common(
95+
&mut commands,
96+
&time,
97+
&mut delta,
98+
"with_children()\nPress Space to continue",
99+
Scene::WithChildren,
100+
);
101+
23102
// Spawn a root entity with no parent
24103
let parent = commands
25104
.spawn((
26105
Sprite::from_image(texture.clone()),
27106
Transform::from_scale(Vec3::splat(0.75)),
107+
DespawnOnExitState(Scene::WithChildren),
28108
))
29109
// With that entity as a parent, run a lambda that spawns its children
30110
.with_children(|parent| {
@@ -46,7 +126,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
46126
let child = commands
47127
.spawn((
48128
Sprite {
49-
image: texture,
129+
image: texture.clone(),
50130
color: LIME.into(),
51131
..default()
52132
},
@@ -58,10 +138,185 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
58138
commands.entity(parent).add_child(child);
59139
}
60140

141+
fn setup_children_spawn(
142+
mut commands: Commands,
143+
asset_server: Res<AssetServer>,
144+
time: Res<Time>,
145+
mut delta: ResMut<Delta>,
146+
) {
147+
let texture = asset_server.load("branding/icon.png");
148+
149+
setup_common(
150+
&mut commands,
151+
&time,
152+
&mut delta,
153+
"Children::spawn() \nPress Space to continue",
154+
Scene::ChildrenSpawn,
155+
);
156+
157+
// Children can also be spawned using the `Children` component as part of the parent's bundle.
158+
commands.spawn((
159+
Sprite::from_image(texture.clone()),
160+
Transform::from_scale(Vec3::splat(0.75)),
161+
DespawnOnExitState(Scene::ChildrenSpawn),
162+
Children::spawn((
163+
Spawn((
164+
Transform::from_xyz(250.0, 0.0, 0.0).with_scale(Vec3::splat(0.75)),
165+
Sprite {
166+
image: texture.clone(),
167+
color: BLUE.into(),
168+
..default()
169+
},
170+
)),
171+
Spawn((
172+
Transform::from_xyz(0.0, 250.0, 0.0).with_scale(Vec3::splat(0.75)),
173+
Sprite {
174+
image: texture,
175+
color: LIME.into(),
176+
..default()
177+
},
178+
)),
179+
)),
180+
));
181+
}
182+
183+
fn spawn_children_macro(
184+
mut commands: Commands,
185+
asset_server: Res<AssetServer>,
186+
time: Res<Time>,
187+
mut delta: ResMut<Delta>,
188+
) {
189+
let texture = asset_server.load("branding/icon.png");
190+
191+
setup_common(
192+
&mut commands,
193+
&time,
194+
&mut delta,
195+
"children!() \nPress Space to continue",
196+
Scene::ChildrenMacro,
197+
);
198+
199+
// The `children!` macro provides a convenient way to define children inline with their parent.
200+
commands.spawn((
201+
Sprite::from_image(texture.clone()),
202+
Transform::from_scale(Vec3::splat(0.75)),
203+
DespawnOnExitState(Scene::ChildrenMacro),
204+
children![
205+
(
206+
Transform::from_xyz(250.0, 0.0, 0.0).with_scale(Vec3::splat(0.75)),
207+
Sprite {
208+
image: texture.clone(),
209+
color: BLUE.into(),
210+
..default()
211+
},
212+
),
213+
(
214+
Transform::from_xyz(0.0, 250.0, 0.0).with_scale(Vec3::splat(0.75)),
215+
Sprite {
216+
image: texture,
217+
color: LIME.into(),
218+
..default()
219+
},
220+
)
221+
],
222+
));
223+
}
224+
225+
fn setup_children_iter(
226+
mut commands: Commands,
227+
asset_server: Res<AssetServer>,
228+
time: Res<Time>,
229+
mut delta: ResMut<Delta>,
230+
) {
231+
let texture = asset_server.load("branding/icon.png");
232+
233+
setup_common(
234+
&mut commands,
235+
&time,
236+
&mut delta,
237+
"SpawnIter() \nPress Space to continue",
238+
Scene::ChildrenIter,
239+
);
240+
241+
// You can also spawn children from an iterator yielding bundles.
242+
let child_components = [
243+
(
244+
Transform::from_xyz(250.0, 0.0, 0.0).with_scale(Vec3::splat(0.75)),
245+
BLUE,
246+
),
247+
(
248+
Transform::from_xyz(0.0, 250.0, 0.0).with_scale(Vec3::splat(0.75)),
249+
LIME,
250+
),
251+
];
252+
253+
commands.spawn((
254+
Sprite::from_image(texture.clone()),
255+
Transform::from_scale(Vec3::splat(0.75)),
256+
DespawnOnExitState(Scene::ChildrenIter),
257+
Children::spawn(SpawnIter(child_components.into_iter().map(
258+
move |(transform, color)| {
259+
(
260+
transform,
261+
Sprite {
262+
image: texture.clone(),
263+
color: color.into(),
264+
..default()
265+
},
266+
)
267+
},
268+
))),
269+
));
270+
}
271+
272+
fn setup_children_related(
273+
mut commands: Commands,
274+
asset_server: Res<AssetServer>,
275+
time: Res<Time>,
276+
mut delta: ResMut<Delta>,
277+
) {
278+
let texture = asset_server.load("branding/icon.png");
279+
280+
setup_common(
281+
&mut commands,
282+
&time,
283+
&mut delta,
284+
"related!() \nPress Space to continue",
285+
Scene::Related,
286+
);
287+
288+
// You can also spawn entities with relationships other than parent/child.
289+
commands.spawn((
290+
Sprite::from_image(texture.clone()),
291+
Transform::from_scale(Vec3::splat(0.75)),
292+
DespawnOnExitState(Scene::Related),
293+
// the `related!` macro will spawn entities according to the `Children: RelationshipTarget` trait, but other types implementing `RelationshipTarget` can be used as well.
294+
related!(Children[
295+
(
296+
Transform::from_xyz(250.0, 0.0, 0.0).with_scale(Vec3::splat(0.75)),
297+
Sprite {
298+
image: texture.clone(),
299+
color: BLUE.into(),
300+
..default()
301+
},
302+
),
303+
(
304+
Transform::from_xyz(0.0, 250.0, 0.0).with_scale(Vec3::splat(0.75)),
305+
Sprite {
306+
image: texture,
307+
color: LIME.into(),
308+
..default()
309+
},
310+
)
311+
]),
312+
));
313+
}
314+
61315
// A simple system to rotate the root entity, and rotate all its children separately
62316
fn rotate(
63317
mut commands: Commands,
64318
time: Res<Time>,
319+
delta: Res<Delta>,
65320
mut parents_query: Query<(Entity, &Children), With<Sprite>>,
66321
mut transform_query: Query<&mut Transform, With<Sprite>>,
67322
) {
@@ -79,12 +334,13 @@ fn rotate(
79334
}
80335

81336
// To demonstrate removing children, we'll remove a child after a couple of seconds.
82-
if time.elapsed_secs() >= 2.0 && children.len() == 2 {
337+
let elapsed = time.elapsed() - delta.0;
338+
if elapsed.as_secs_f32() >= 2.0 && children.len() == 2 {
83339
let child = children.last().unwrap();
84340
commands.entity(*child).despawn();
85341
}
86342

87-
if time.elapsed_secs() >= 4.0 {
343+
if elapsed.as_secs_f32() >= 4.0 {
88344
// This will remove the entity from its parent's list of children, as well as despawn
89345
// any children the entity has.
90346
commands.entity(parent).despawn();

0 commit comments

Comments
 (0)