@@ -133,6 +133,80 @@ impl<R: Relationship, F: FnOnce(&mut RelatedSpawner<R>) + Send + Sync + 'static>
133
133
}
134
134
}
135
135
136
+ /// A [`SpawnableList`] that links already spawned entities to the root entity via relations of type `I`.
137
+ ///
138
+ /// This is useful if the entity has already been spawned earlier or if you spawn multiple relationships link to the same entity at the same time.
139
+ /// If you only need to do this for a single entity, consider using [`WithOneRelated`].
140
+ ///
141
+ /// ```
142
+ /// # use bevy_ecs::hierarchy::Children;
143
+ /// # use bevy_ecs::spawn::{Spawn, WithRelated, SpawnRelated};
144
+ /// # use bevy_ecs::name::Name;
145
+ /// # use bevy_ecs::world::World;
146
+ /// let mut world = World::new();
147
+ ///
148
+ /// let child2 = world.spawn(Name::new("Child2")).id();
149
+ /// let child3 = world.spawn(Name::new("Child3")).id();
150
+ ///
151
+ /// world.spawn((
152
+ /// Name::new("Root"),
153
+ /// Children::spawn((
154
+ /// Spawn(Name::new("Child1")),
155
+ /// // This adds the already existing entities as children of Root.
156
+ /// WithRelated([child2, child3].into_iter()),
157
+ /// )),
158
+ /// ));
159
+ /// ```
160
+ pub struct WithRelated < I > ( pub I ) ;
161
+
162
+ impl < R : Relationship , I : Iterator < Item = Entity > > SpawnableList < R > for WithRelated < I > {
163
+ fn spawn ( self , world : & mut World , entity : Entity ) {
164
+ world
165
+ . entity_mut ( entity)
166
+ . add_related :: < R > ( & self . 0 . collect :: < Vec < _ > > ( ) ) ;
167
+ }
168
+
169
+ fn size_hint ( & self ) -> usize {
170
+ self . 0 . size_hint ( ) . 0
171
+ }
172
+ }
173
+
174
+ /// A wrapper over an [`Entity`] indicating that an entity should be added.
175
+ /// This is intended to be used for hierarchical spawning via traits like [`SpawnableList`] and [`SpawnRelated`].
176
+ ///
177
+ /// Unlike [`WithRelated`] this only adds one entity.
178
+ ///
179
+ /// Also see the [`children`](crate::children) and [`related`](crate::related) macros that abstract over the [`Spawn`] API.
180
+ ///
181
+ /// ```
182
+ /// # use bevy_ecs::hierarchy::Children;
183
+ /// # use bevy_ecs::spawn::{Spawn, WithOneRelated, SpawnRelated};
184
+ /// # use bevy_ecs::name::Name;
185
+ /// # use bevy_ecs::world::World;
186
+ /// let mut world = World::new();
187
+ ///
188
+ /// let child1 = world.spawn(Name::new("Child1")).id();
189
+ ///
190
+ /// world.spawn((
191
+ /// Name::new("Root"),
192
+ /// Children::spawn((
193
+ /// // This adds the already existing entity as a child of Root.
194
+ /// WithOneRelated(child1),
195
+ /// )),
196
+ /// ));
197
+ /// ```
198
+ pub struct WithOneRelated ( pub Entity ) ;
199
+
200
+ impl < R : Relationship > SpawnableList < R > for WithOneRelated {
201
+ fn spawn ( self , world : & mut World , entity : Entity ) {
202
+ world. entity_mut ( entity) . add_one_related :: < R > ( self . 0 ) ;
203
+ }
204
+
205
+ fn size_hint ( & self ) -> usize {
206
+ 1
207
+ }
208
+ }
209
+
136
210
macro_rules! spawnable_list_impl {
137
211
( $( $list: ident) ,* ) => {
138
212
#[ expect(
@@ -267,7 +341,7 @@ pub trait SpawnRelated: RelationshipTarget {
267
341
/// Returns a [`Bundle`] containing this [`RelationshipTarget`] component. It also spawns a [`SpawnableList`] of entities, each related to the bundle's entity
268
342
/// via [`RelationshipTarget::Relationship`]. The [`RelationshipTarget`] (when possible) will pre-allocate space for the related entities.
269
343
///
270
- /// See [`Spawn`], [`SpawnIter`], and [`SpawnWith `] for usage examples.
344
+ /// See [`Spawn`], [`SpawnIter`], [`SpawnWith`], [`WithRelated`] and [`WithOneRelated `] for usage examples.
271
345
fn spawn < L : SpawnableList < Self :: Relationship > > (
272
346
list : L ,
273
347
) -> SpawnRelatedBundle < Self :: Relationship , L > ;
@@ -485,3 +559,141 @@ macro_rules! recursive_spawn {
485
559
)
486
560
} ;
487
561
}
562
+
563
+ #[ cfg( test) ]
564
+ mod tests {
565
+
566
+ use crate :: {
567
+ name:: Name ,
568
+ prelude:: { ChildOf , Children , RelationshipTarget } ,
569
+ relationship:: RelatedSpawner ,
570
+ world:: World ,
571
+ } ;
572
+
573
+ use super :: { Spawn , SpawnIter , SpawnRelated , SpawnWith , WithOneRelated , WithRelated } ;
574
+
575
+ #[ test]
576
+ fn spawn ( ) {
577
+ let mut world = World :: new ( ) ;
578
+
579
+ let parent = world
580
+ . spawn ( (
581
+ Name :: new ( "Parent" ) ,
582
+ Children :: spawn ( Spawn ( Name :: new ( "Child1" ) ) ) ,
583
+ ) )
584
+ . id ( ) ;
585
+
586
+ let children = world
587
+ . query :: < & Children > ( )
588
+ . get ( & world, parent)
589
+ . expect ( "An entity with Children should exist" ) ;
590
+
591
+ assert_eq ! ( children. iter( ) . count( ) , 1 ) ;
592
+
593
+ for ChildOf ( child) in world. query :: < & ChildOf > ( ) . iter ( & world) {
594
+ assert_eq ! ( child, & parent) ;
595
+ }
596
+ }
597
+
598
+ #[ test]
599
+ fn spawn_iter ( ) {
600
+ let mut world = World :: new ( ) ;
601
+
602
+ let parent = world
603
+ . spawn ( (
604
+ Name :: new ( "Parent" ) ,
605
+ Children :: spawn ( SpawnIter ( [ "Child1" , "Child2" ] . into_iter ( ) . map ( Name :: new) ) ) ,
606
+ ) )
607
+ . id ( ) ;
608
+
609
+ let children = world
610
+ . query :: < & Children > ( )
611
+ . get ( & world, parent)
612
+ . expect ( "An entity with Children should exist" ) ;
613
+
614
+ assert_eq ! ( children. iter( ) . count( ) , 2 ) ;
615
+
616
+ for ChildOf ( child) in world. query :: < & ChildOf > ( ) . iter ( & world) {
617
+ assert_eq ! ( child, & parent) ;
618
+ }
619
+ }
620
+
621
+ #[ test]
622
+ fn spawn_with ( ) {
623
+ let mut world = World :: new ( ) ;
624
+
625
+ let parent = world
626
+ . spawn ( (
627
+ Name :: new ( "Parent" ) ,
628
+ Children :: spawn ( SpawnWith ( |parent : & mut RelatedSpawner < ChildOf > | {
629
+ parent. spawn ( Name :: new ( "Child1" ) ) ;
630
+ } ) ) ,
631
+ ) )
632
+ . id ( ) ;
633
+
634
+ let children = world
635
+ . query :: < & Children > ( )
636
+ . get ( & world, parent)
637
+ . expect ( "An entity with Children should exist" ) ;
638
+
639
+ assert_eq ! ( children. iter( ) . count( ) , 1 ) ;
640
+
641
+ for ChildOf ( child) in world. query :: < & ChildOf > ( ) . iter ( & world) {
642
+ assert_eq ! ( child, & parent) ;
643
+ }
644
+ }
645
+
646
+ #[ test]
647
+ fn with_related ( ) {
648
+ let mut world = World :: new ( ) ;
649
+
650
+ let child1 = world. spawn ( Name :: new ( "Child1" ) ) . id ( ) ;
651
+ let child2 = world. spawn ( Name :: new ( "Child2" ) ) . id ( ) ;
652
+
653
+ let parent = world
654
+ . spawn ( (
655
+ Name :: new ( "Parent" ) ,
656
+ Children :: spawn ( WithRelated ( [ child1, child2] . into_iter ( ) ) ) ,
657
+ ) )
658
+ . id ( ) ;
659
+
660
+ let children = world
661
+ . query :: < & Children > ( )
662
+ . get ( & world, parent)
663
+ . expect ( "An entity with Children should exist" ) ;
664
+
665
+ assert_eq ! ( children. iter( ) . count( ) , 2 ) ;
666
+
667
+ assert_eq ! (
668
+ world. entity( child1) . get:: <ChildOf >( ) ,
669
+ Some ( & ChildOf ( parent) )
670
+ ) ;
671
+ assert_eq ! (
672
+ world. entity( child2) . get:: <ChildOf >( ) ,
673
+ Some ( & ChildOf ( parent) )
674
+ ) ;
675
+ }
676
+
677
+ #[ test]
678
+ fn with_one_related ( ) {
679
+ let mut world = World :: new ( ) ;
680
+
681
+ let child1 = world. spawn ( Name :: new ( "Child1" ) ) . id ( ) ;
682
+
683
+ let parent = world
684
+ . spawn ( ( Name :: new ( "Parent" ) , Children :: spawn ( WithOneRelated ( child1) ) ) )
685
+ . id ( ) ;
686
+
687
+ let children = world
688
+ . query :: < & Children > ( )
689
+ . get ( & world, parent)
690
+ . expect ( "An entity with Children should exist" ) ;
691
+
692
+ assert_eq ! ( children. iter( ) . count( ) , 1 ) ;
693
+
694
+ assert_eq ! (
695
+ world. entity( child1) . get:: <ChildOf >( ) ,
696
+ Some ( & ChildOf ( parent) )
697
+ ) ;
698
+ }
699
+ }
0 commit comments