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
99use bevy:: { color:: palettes:: css:: * , prelude:: * } ;
1010
1111fn 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()\n Press 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() \n Press 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!() \n Press 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() \n Press 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!() \n Press 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
62316fn 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