1use std::{f32::consts::*, time::Duration};
8
9use bevy::{color::palettes::css::*, ecs::relationship::RelatedSpawner, prelude::*};
10
11fn main() {
12 App::new()
13 .add_plugins(DefaultPlugins)
14 .add_systems(Startup, setup)
15 .init_state::<Showcase>()
16 .insert_resource(Delta(Duration::ZERO))
17 .add_systems(OnEnter(Showcase::WithChildren), setup_with_children)
18 .add_systems(OnEnter(Showcase::ChildrenSpawn), setup_children_spawn)
19 .add_systems(OnEnter(Showcase::ChildrenMacro), spawn_children_macro)
20 .add_systems(OnEnter(Showcase::ChildrenIter), setup_children_iter)
21 .add_systems(OnEnter(Showcase::Related), setup_children_related)
22 .add_systems(OnEnter(Showcase::Bsn), setup_bsn)
23 .add_systems(Update, (rotate, switch_scene))
24 .run();
25}
26
27#[derive(Debug, Clone, Eq, PartialEq, Hash, States, Default)]
28enum Showcase {
29 #[default]
30 WithChildren,
31 ChildrenSpawn,
32 ChildrenMacro,
33 ChildrenIter,
34 Related,
35 Bsn,
36}
37
38impl Showcase {
39 fn next(&self) -> Self {
40 match self {
41 Showcase::WithChildren => Showcase::ChildrenSpawn,
42 Showcase::ChildrenSpawn => Showcase::ChildrenMacro,
43 Showcase::ChildrenMacro => Showcase::ChildrenIter,
44 Showcase::ChildrenIter => Showcase::Related,
45 Showcase::Related => Showcase::Bsn,
46 Showcase::Bsn => Showcase::WithChildren,
47 }
48 }
49}
50
51fn switch_scene(
52 keyboard: Res<ButtonInput<KeyCode>>,
53 scene: Res<State<Showcase>>,
54 mut next_scene: ResMut<NextState<Showcase>>,
55) {
56 if keyboard.just_pressed(KeyCode::Space) {
57 info!("Switching scene");
58 next_scene.set(scene.get().next());
59 }
60}
61
62fn setup(mut commands: Commands) {
63 commands.spawn(Camera2d);
64}
65
66#[derive(Resource)]
67struct Delta(Duration);
68
69fn setup_common(
70 commands: &mut Commands,
71 time: &Res<Time>,
72 delta: &mut ResMut<Delta>,
73 title: &str,
74 stage: Showcase,
75) {
76 delta.0 = time.elapsed();
77 commands.spawn((
78 Text::new(title),
79 TextFont::from_font_size(36.),
80 DespawnOnExit(stage),
81 ));
82}
83
84fn setup_with_children(
85 mut commands: Commands,
86 asset_server: Res<AssetServer>,
87 time: Res<Time>,
88 mut delta: ResMut<Delta>,
89) {
90 let texture = asset_server.load("branding/icon.png");
91
92 setup_common(
93 &mut commands,
94 &time,
95 &mut delta,
96 "with_children()\nPress Space to continue",
97 Showcase::WithChildren,
98 );
99
100 let parent = commands
102 .spawn((
103 Sprite::from_image(texture.clone()),
104 Transform::from_scale(Vec3::splat(0.75)),
105 DespawnOnExit(Showcase::WithChildren),
106 ))
107 .with_children(|parent| {
109 parent.spawn((
111 Transform::from_xyz(250.0, 0.0, 0.0).with_scale(Vec3::splat(0.75)),
112 Sprite {
113 image: texture.clone(),
114 color: BLUE.into(),
115 ..default()
116 },
117 ));
118 })
119 .id();
121
122 let child = commands
125 .spawn((
126 Sprite {
127 image: texture.clone(),
128 color: LIME.into(),
129 ..default()
130 },
131 Transform::from_xyz(0.0, 250.0, 0.0).with_scale(Vec3::splat(0.75)),
132 ))
133 .id();
134
135 commands.entity(parent).add_child(child);
137}
138
139fn setup_children_spawn(
140 mut commands: Commands,
141 asset_server: Res<AssetServer>,
142 time: Res<Time>,
143 mut delta: ResMut<Delta>,
144) {
145 let texture = asset_server.load("branding/icon.png");
146
147 setup_common(
148 &mut commands,
149 &time,
150 &mut delta,
151 "Children::spawn() \nPress Space to continue",
152 Showcase::ChildrenSpawn,
153 );
154
155 commands.spawn((
157 Sprite::from_image(texture.clone()),
158 Transform::from_scale(Vec3::splat(0.75)),
159 DespawnOnExit(Showcase::ChildrenSpawn),
160 Children::spawn((
161 Spawn((
162 Transform::from_xyz(250.0, 0.0, 0.0).with_scale(Vec3::splat(0.75)),
163 Sprite {
164 image: texture.clone(),
165 color: BLUE.into(),
166 ..default()
167 },
168 )),
169 SpawnWith(|spawner: &mut RelatedSpawner<'_, ChildOf>| {
172 spawner.spawn((
173 Transform::from_xyz(0.0, 250.0, 0.0).with_scale(Vec3::splat(0.75)),
174 Sprite {
175 image: texture,
176 color: LIME.into(),
177 ..default()
178 },
179 ));
180 }),
181 )),
182 ));
183}
184
185fn spawn_children_macro(
186 mut commands: Commands,
187 asset_server: Res<AssetServer>,
188 time: Res<Time>,
189 mut delta: ResMut<Delta>,
190) {
191 let texture = asset_server.load("branding/icon.png");
192
193 setup_common(
194 &mut commands,
195 &time,
196 &mut delta,
197 "children!() \nPress Space to continue",
198 Showcase::ChildrenMacro,
199 );
200
201 commands.spawn((
203 Sprite::from_image(texture.clone()),
204 Transform::from_scale(Vec3::splat(0.75)),
205 DespawnOnExit(Showcase::ChildrenMacro),
206 children![
207 (
208 Transform::from_xyz(250.0, 0.0, 0.0).with_scale(Vec3::splat(0.75)),
209 Sprite {
210 image: texture.clone(),
211 color: BLUE.into(),
212 ..default()
213 },
214 ),
215 (
216 Transform::from_xyz(0.0, 250.0, 0.0).with_scale(Vec3::splat(0.75)),
217 Sprite {
218 image: texture,
219 color: LIME.into(),
220 ..default()
221 },
222 )
223 ],
224 ));
225}
226
227fn setup_children_iter(
228 mut commands: Commands,
229 asset_server: Res<AssetServer>,
230 time: Res<Time>,
231 mut delta: ResMut<Delta>,
232) {
233 let texture = asset_server.load("branding/icon.png");
234
235 setup_common(
236 &mut commands,
237 &time,
238 &mut delta,
239 "SpawnIter() \nPress Space to continue",
240 Showcase::ChildrenIter,
241 );
242
243 let child_components = [
245 (
246 Transform::from_xyz(250.0, 0.0, 0.0).with_scale(Vec3::splat(0.75)),
247 BLUE,
248 ),
249 (
250 Transform::from_xyz(0.0, 250.0, 0.0).with_scale(Vec3::splat(0.75)),
251 LIME,
252 ),
253 ];
254
255 commands.spawn((
256 Sprite::from_image(texture.clone()),
257 Transform::from_scale(Vec3::splat(0.75)),
258 DespawnOnExit(Showcase::ChildrenIter),
259 Children::spawn(SpawnIter(child_components.into_iter().map(
260 move |(transform, color)| {
261 (
262 transform,
263 Sprite {
264 image: texture.clone(),
265 color: color.into(),
266 ..default()
267 },
268 )
269 },
270 ))),
271 ));
272}
273
274fn setup_children_related(
275 mut commands: Commands,
276 asset_server: Res<AssetServer>,
277 time: Res<Time>,
278 mut delta: ResMut<Delta>,
279) {
280 let texture = asset_server.load("branding/icon.png");
281
282 setup_common(
283 &mut commands,
284 &time,
285 &mut delta,
286 "related!() \nPress Space to continue",
287 Showcase::Related,
288 );
289
290 commands.spawn((
292 Sprite::from_image(texture.clone()),
293 Transform::from_scale(Vec3::splat(0.75)),
294 DespawnOnExit(Showcase::Related),
295 related!(Children[
297 (
298 Transform::from_xyz(250.0, 0.0, 0.0).with_scale(Vec3::splat(0.75)),
299 Sprite {
300 image: texture.clone(),
301 color: BLUE.into(),
302 ..default()
303 },
304 ),
305 (
306 Transform::from_xyz(0.0, 250.0, 0.0).with_scale(Vec3::splat(0.75)),
307 Sprite {
308 image: texture,
309 color: LIME.into(),
310 ..default()
311 },
312 )
313 ]),
314 ));
315}
316
317fn setup_bsn(mut commands: Commands, time: Res<Time>, mut delta: ResMut<Delta>) {
318 setup_common(
319 &mut commands,
320 &time,
321 &mut delta,
322 "BSN\nPress Space to continue",
323 Showcase::Bsn,
324 );
325
326 commands.spawn_scene(bsn! {
328 Sprite { image: "branding/icon.png" }
329 Transform::from_scale(Vec3::splat(0.75))
330 DespawnOnExit::<Showcase>(Showcase::Bsn)
331 Children [
332 Transform::from_xyz(250.0, 0.0, 0.0).with_scale(Vec3::splat(0.75))
333 Sprite {
334 image: "branding/icon.png",
335 color: BLUE,
336 }
337 --
338 Transform::from_xyz(0.0, 250.0, 0.0).with_scale(Vec3::splat(0.75))
339 Sprite {
340 image: "branding/icon.png",
341 color: LIME,
342 }
343 ]
344 });
345}
346
347fn rotate(
349 mut commands: Commands,
350 time: Res<Time>,
351 delta: Res<Delta>,
352 mut parents_query: Query<(Entity, &Children), With<Sprite>>,
353 mut transform_query: Query<&mut Transform, With<Sprite>>,
354) {
355 for (parent, children) in &mut parents_query {
356 if let Ok(mut transform) = transform_query.get_mut(parent) {
357 transform.rotate_z(-PI / 2. * time.delta_secs());
358 }
359
360 for child in children {
363 if let Ok(mut transform) = transform_query.get_mut(*child) {
364 transform.rotate_z(PI * time.delta_secs());
365 }
366 }
367
368 let elapsed = time.elapsed_secs() - delta.0.as_secs_f32();
370 if elapsed >= 2.0 && children.len() == 2 {
371 let child = children.last().unwrap();
372 commands.entity(*child).despawn();
373 }
374
375 if elapsed >= 4.0 {
376 commands.entity(parent).despawn();
379 }
380 }
381}