Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/spawn.rs
6598 views
1
//! Entity spawning abstractions, largely focused on spawning related hierarchies of entities. See [`related`](crate::related) and [`SpawnRelated`]
2
//! for the best entry points into these APIs and examples of how to use them.
3
4
use crate::{
5
bundle::{Bundle, BundleEffect, DynamicBundle, NoBundleEffect},
6
entity::Entity,
7
relationship::{RelatedSpawner, Relationship, RelationshipTarget},
8
world::{EntityWorldMut, World},
9
};
10
use alloc::vec::Vec;
11
use core::marker::PhantomData;
12
use variadics_please::all_tuples;
13
14
/// A wrapper over a [`Bundle`] indicating that an entity should be spawned with that [`Bundle`].
15
/// This is intended to be used for hierarchical spawning via traits like [`SpawnableList`] and [`SpawnRelated`].
16
///
17
/// Also see the [`children`](crate::children) and [`related`](crate::related) macros that abstract over the [`Spawn`] API.
18
///
19
/// ```
20
/// # use bevy_ecs::hierarchy::Children;
21
/// # use bevy_ecs::spawn::{Spawn, SpawnRelated};
22
/// # use bevy_ecs::name::Name;
23
/// # use bevy_ecs::world::World;
24
/// let mut world = World::new();
25
/// world.spawn((
26
/// Name::new("Root"),
27
/// Children::spawn((
28
/// Spawn(Name::new("Child1")),
29
/// Spawn((
30
/// Name::new("Child2"),
31
/// Children::spawn(Spawn(Name::new("Grandchild"))),
32
/// ))
33
/// )),
34
/// ));
35
/// ```
36
pub struct Spawn<B: Bundle>(pub B);
37
38
/// A spawn-able list of changes to a given [`World`] and relative to a given [`Entity`]. This is generally used
39
/// for spawning "related" entities, such as children.
40
pub trait SpawnableList<R> {
41
/// Spawn this list of changes in a given [`World`] and relative to a given [`Entity`]. This is generally used
42
/// for spawning "related" entities, such as children.
43
fn spawn(self, world: &mut World, entity: Entity);
44
/// Returns a size hint, which is used to reserve space for this list in a [`RelationshipTarget`]. This should be
45
/// less than or equal to the actual size of the list. When in doubt, just use 0.
46
fn size_hint(&self) -> usize;
47
}
48
49
impl<R: Relationship, B: Bundle<Effect: NoBundleEffect>> SpawnableList<R> for Vec<B> {
50
fn spawn(self, world: &mut World, entity: Entity) {
51
let mapped_bundles = self.into_iter().map(|b| (R::from(entity), b));
52
world.spawn_batch(mapped_bundles);
53
}
54
55
fn size_hint(&self) -> usize {
56
self.len()
57
}
58
}
59
60
impl<R: Relationship, B: Bundle> SpawnableList<R> for Spawn<B> {
61
fn spawn(self, world: &mut World, entity: Entity) {
62
world.spawn((R::from(entity), self.0));
63
}
64
65
fn size_hint(&self) -> usize {
66
1
67
}
68
}
69
70
/// A [`SpawnableList`] that spawns entities using an iterator of a given [`Bundle`]:
71
///
72
/// ```
73
/// # use bevy_ecs::hierarchy::Children;
74
/// # use bevy_ecs::spawn::{Spawn, SpawnIter, SpawnRelated};
75
/// # use bevy_ecs::name::Name;
76
/// # use bevy_ecs::world::World;
77
/// let mut world = World::new();
78
/// world.spawn((
79
/// Name::new("Root"),
80
/// Children::spawn((
81
/// Spawn(Name::new("Child1")),
82
/// SpawnIter(["Child2", "Child3"].into_iter().map(Name::new)),
83
/// )),
84
/// ));
85
/// ```
86
pub struct SpawnIter<I>(pub I);
87
88
impl<R: Relationship, I: Iterator<Item = B> + Send + Sync + 'static, B: Bundle> SpawnableList<R>
89
for SpawnIter<I>
90
{
91
fn spawn(self, world: &mut World, entity: Entity) {
92
for bundle in self.0 {
93
world.spawn((R::from(entity), bundle));
94
}
95
}
96
97
fn size_hint(&self) -> usize {
98
self.0.size_hint().0
99
}
100
}
101
102
/// A [`SpawnableList`] that spawns entities using a [`FnOnce`] with a [`RelatedSpawner`] as an argument:
103
///
104
/// ```
105
/// # use bevy_ecs::hierarchy::{Children, ChildOf};
106
/// # use bevy_ecs::spawn::{Spawn, SpawnWith, SpawnRelated};
107
/// # use bevy_ecs::name::Name;
108
/// # use bevy_ecs::relationship::RelatedSpawner;
109
/// # use bevy_ecs::world::World;
110
/// let mut world = World::new();
111
/// world.spawn((
112
/// Name::new("Root"),
113
/// Children::spawn((
114
/// Spawn(Name::new("Child1")),
115
/// SpawnWith(|parent: &mut RelatedSpawner<ChildOf>| {
116
/// parent.spawn(Name::new("Child2"));
117
/// parent.spawn(Name::new("Child3"));
118
/// }),
119
/// )),
120
/// ));
121
/// ```
122
pub struct SpawnWith<F>(pub F);
123
124
impl<R: Relationship, F: FnOnce(&mut RelatedSpawner<R>) + Send + Sync + 'static> SpawnableList<R>
125
for SpawnWith<F>
126
{
127
fn spawn(self, world: &mut World, entity: Entity) {
128
world.entity_mut(entity).with_related_entities(self.0);
129
}
130
131
fn size_hint(&self) -> usize {
132
1
133
}
134
}
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::new([child2, child3]),
157
/// )),
158
/// ));
159
/// ```
160
pub struct WithRelated<I>(pub I);
161
162
impl<I> WithRelated<I> {
163
/// Creates a new [`WithRelated`] from a collection of entities.
164
pub fn new(iter: impl IntoIterator<IntoIter = I>) -> Self {
165
Self(iter.into_iter())
166
}
167
}
168
169
impl<R: Relationship, I: Iterator<Item = Entity>> SpawnableList<R> for WithRelated<I> {
170
fn spawn(self, world: &mut World, entity: Entity) {
171
world
172
.entity_mut(entity)
173
.add_related::<R>(&self.0.collect::<Vec<_>>());
174
}
175
176
fn size_hint(&self) -> usize {
177
self.0.size_hint().0
178
}
179
}
180
181
/// A wrapper over an [`Entity`] indicating that an entity should be added.
182
/// This is intended to be used for hierarchical spawning via traits like [`SpawnableList`] and [`SpawnRelated`].
183
///
184
/// Unlike [`WithRelated`] this only adds one entity.
185
///
186
/// Also see the [`children`](crate::children) and [`related`](crate::related) macros that abstract over the [`Spawn`] API.
187
///
188
/// ```
189
/// # use bevy_ecs::hierarchy::Children;
190
/// # use bevy_ecs::spawn::{Spawn, WithOneRelated, SpawnRelated};
191
/// # use bevy_ecs::name::Name;
192
/// # use bevy_ecs::world::World;
193
/// let mut world = World::new();
194
///
195
/// let child1 = world.spawn(Name::new("Child1")).id();
196
///
197
/// world.spawn((
198
/// Name::new("Root"),
199
/// Children::spawn((
200
/// // This adds the already existing entity as a child of Root.
201
/// WithOneRelated(child1),
202
/// )),
203
/// ));
204
/// ```
205
pub struct WithOneRelated(pub Entity);
206
207
impl<R: Relationship> SpawnableList<R> for WithOneRelated {
208
fn spawn(self, world: &mut World, entity: Entity) {
209
world.entity_mut(entity).add_one_related::<R>(self.0);
210
}
211
212
fn size_hint(&self) -> usize {
213
1
214
}
215
}
216
217
macro_rules! spawnable_list_impl {
218
($(#[$meta:meta])* $($list: ident),*) => {
219
#[expect(
220
clippy::allow_attributes,
221
reason = "This is a tuple-related macro; as such, the lints below may not always apply."
222
)]
223
$(#[$meta])*
224
impl<R: Relationship, $($list: SpawnableList<R>),*> SpawnableList<R> for ($($list,)*) {
225
fn spawn(self, _world: &mut World, _entity: Entity) {
226
#[allow(
227
non_snake_case,
228
reason = "The names of these variables are provided by the caller, not by us."
229
)]
230
let ($($list,)*) = self;
231
$($list.spawn(_world, _entity);)*
232
}
233
234
fn size_hint(&self) -> usize {
235
#[allow(
236
non_snake_case,
237
reason = "The names of these variables are provided by the caller, not by us."
238
)]
239
let ($($list,)*) = self;
240
0 $(+ $list.size_hint())*
241
}
242
}
243
}
244
}
245
246
all_tuples!(
247
#[doc(fake_variadic)]
248
spawnable_list_impl,
249
0,
250
12,
251
P
252
);
253
254
/// A [`Bundle`] that:
255
/// 1. Contains a [`RelationshipTarget`] component (associated with the given [`Relationship`]). This reserves space for the [`SpawnableList`].
256
/// 2. Spawns a [`SpawnableList`] of related entities with a given [`Relationship`].
257
///
258
/// This is intended to be created using [`SpawnRelated`].
259
pub struct SpawnRelatedBundle<R: Relationship, L: SpawnableList<R>> {
260
list: L,
261
marker: PhantomData<R>,
262
}
263
264
impl<R: Relationship, L: SpawnableList<R>> BundleEffect for SpawnRelatedBundle<R, L> {
265
fn apply(self, entity: &mut EntityWorldMut) {
266
let id = entity.id();
267
entity.world_scope(|world: &mut World| {
268
self.list.spawn(world, id);
269
});
270
}
271
}
272
273
// SAFETY: This internally relies on the RelationshipTarget's Bundle implementation, which is sound.
274
unsafe impl<R: Relationship, L: SpawnableList<R> + Send + Sync + 'static> Bundle
275
for SpawnRelatedBundle<R, L>
276
{
277
fn component_ids(
278
components: &mut crate::component::ComponentsRegistrator,
279
ids: &mut impl FnMut(crate::component::ComponentId),
280
) {
281
<R::RelationshipTarget as Bundle>::component_ids(components, ids);
282
}
283
284
fn get_component_ids(
285
components: &crate::component::Components,
286
ids: &mut impl FnMut(Option<crate::component::ComponentId>),
287
) {
288
<R::RelationshipTarget as Bundle>::get_component_ids(components, ids);
289
}
290
}
291
292
impl<R: Relationship, L: SpawnableList<R>> DynamicBundle for SpawnRelatedBundle<R, L> {
293
type Effect = Self;
294
295
fn get_components(
296
self,
297
func: &mut impl FnMut(crate::component::StorageType, bevy_ptr::OwningPtr<'_>),
298
) -> Self::Effect {
299
<R::RelationshipTarget as RelationshipTarget>::with_capacity(self.list.size_hint())
300
.get_components(func);
301
self
302
}
303
}
304
305
/// A [`Bundle`] that:
306
/// 1. Contains a [`RelationshipTarget`] component (associated with the given [`Relationship`]). This reserves space for a single entity.
307
/// 2. Spawns a single related entity containing the given `B` [`Bundle`] and the given [`Relationship`].
308
///
309
/// This is intended to be created using [`SpawnRelated`].
310
pub struct SpawnOneRelated<R: Relationship, B: Bundle> {
311
bundle: B,
312
marker: PhantomData<R>,
313
}
314
315
impl<R: Relationship, B: Bundle> BundleEffect for SpawnOneRelated<R, B> {
316
fn apply(self, entity: &mut EntityWorldMut) {
317
entity.with_related::<R>(self.bundle);
318
}
319
}
320
321
impl<R: Relationship, B: Bundle> DynamicBundle for SpawnOneRelated<R, B> {
322
type Effect = Self;
323
324
fn get_components(
325
self,
326
func: &mut impl FnMut(crate::component::StorageType, bevy_ptr::OwningPtr<'_>),
327
) -> Self::Effect {
328
<R::RelationshipTarget as RelationshipTarget>::with_capacity(1).get_components(func);
329
self
330
}
331
}
332
333
// SAFETY: This internally relies on the RelationshipTarget's Bundle implementation, which is sound.
334
unsafe impl<R: Relationship, B: Bundle> Bundle for SpawnOneRelated<R, B> {
335
fn component_ids(
336
components: &mut crate::component::ComponentsRegistrator,
337
ids: &mut impl FnMut(crate::component::ComponentId),
338
) {
339
<R::RelationshipTarget as Bundle>::component_ids(components, ids);
340
}
341
342
fn get_component_ids(
343
components: &crate::component::Components,
344
ids: &mut impl FnMut(Option<crate::component::ComponentId>),
345
) {
346
<R::RelationshipTarget as Bundle>::get_component_ids(components, ids);
347
}
348
}
349
350
/// [`RelationshipTarget`] methods that create a [`Bundle`] with a [`DynamicBundle::Effect`] that:
351
///
352
/// 1. Contains the [`RelationshipTarget`] component, pre-allocated with the necessary space for spawned entities.
353
/// 2. Spawns an entity (or a list of entities) that relate to the entity the [`Bundle`] is added to via the [`RelationshipTarget::Relationship`].
354
pub trait SpawnRelated: RelationshipTarget {
355
/// Returns a [`Bundle`] containing this [`RelationshipTarget`] component. It also spawns a [`SpawnableList`] of entities, each related to the bundle's entity
356
/// via [`RelationshipTarget::Relationship`]. The [`RelationshipTarget`] (when possible) will pre-allocate space for the related entities.
357
///
358
/// See [`Spawn`], [`SpawnIter`], [`SpawnWith`], [`WithRelated`] and [`WithOneRelated`] for usage examples.
359
fn spawn<L: SpawnableList<Self::Relationship>>(
360
list: L,
361
) -> SpawnRelatedBundle<Self::Relationship, L>;
362
363
/// Returns a [`Bundle`] containing this [`RelationshipTarget`] component. It also spawns a single entity containing [`Bundle`] that is related to the bundle's entity
364
/// via [`RelationshipTarget::Relationship`].
365
///
366
/// ```
367
/// # use bevy_ecs::hierarchy::Children;
368
/// # use bevy_ecs::spawn::SpawnRelated;
369
/// # use bevy_ecs::name::Name;
370
/// # use bevy_ecs::world::World;
371
/// let mut world = World::new();
372
/// world.spawn((
373
/// Name::new("Root"),
374
/// Children::spawn_one(Name::new("Child")),
375
/// ));
376
/// ```
377
fn spawn_one<B: Bundle>(bundle: B) -> SpawnOneRelated<Self::Relationship, B>;
378
}
379
380
impl<T: RelationshipTarget> SpawnRelated for T {
381
fn spawn<L: SpawnableList<Self::Relationship>>(
382
list: L,
383
) -> SpawnRelatedBundle<Self::Relationship, L> {
384
SpawnRelatedBundle {
385
list,
386
marker: PhantomData,
387
}
388
}
389
390
fn spawn_one<B: Bundle>(bundle: B) -> SpawnOneRelated<Self::Relationship, B> {
391
SpawnOneRelated {
392
bundle,
393
marker: PhantomData,
394
}
395
}
396
}
397
398
/// Returns a [`SpawnRelatedBundle`] that will insert the given [`RelationshipTarget`], spawn a [`SpawnableList`] of entities with given bundles that
399
/// relate to the [`RelationshipTarget`] entity via the [`RelationshipTarget::Relationship`] component, and reserve space in the [`RelationshipTarget`] for each spawned entity.
400
///
401
/// The first argument is the [`RelationshipTarget`] type. Any additional arguments will be interpreted as bundles to be spawned.
402
///
403
/// Also see [`children`](crate::children) for a [`Children`](crate::hierarchy::Children)-specific equivalent.
404
///
405
/// ```
406
/// # use bevy_ecs::hierarchy::Children;
407
/// # use bevy_ecs::name::Name;
408
/// # use bevy_ecs::world::World;
409
/// # use bevy_ecs::related;
410
/// # use bevy_ecs::spawn::{Spawn, SpawnRelated};
411
/// let mut world = World::new();
412
/// world.spawn((
413
/// Name::new("Root"),
414
/// related!(Children[
415
/// Name::new("Child1"),
416
/// (
417
/// Name::new("Child2"),
418
/// related!(Children[
419
/// Name::new("Grandchild"),
420
/// ])
421
/// )
422
/// ])
423
/// ));
424
/// ```
425
#[macro_export]
426
macro_rules! related {
427
($relationship_target:ty [$($child:expr),*$(,)?]) => {
428
<$relationship_target>::spawn($crate::recursive_spawn!($($child),*))
429
};
430
}
431
432
// A tail-recursive spawn utility.
433
//
434
// Since `SpawnableList` is only implemented for tuples
435
// up to twelve elements long, this macro will nest
436
// longer sequences recursively. By default, this recursion
437
// will top out at around 1400 elements, but it would be
438
// ill-advised to spawn that many entities with this method.
439
//
440
// For spawning large batches of entities at a time,
441
// consider `SpawnIter` or eagerly spawning with `Commands`.
442
#[macro_export]
443
#[doc(hidden)]
444
macro_rules! recursive_spawn {
445
// direct expansion
446
($a:expr) => {
447
$crate::spawn::Spawn($a)
448
};
449
($a:expr, $b:expr) => {
450
(
451
$crate::spawn::Spawn($a),
452
$crate::spawn::Spawn($b),
453
)
454
};
455
($a:expr, $b:expr, $c:expr) => {
456
(
457
$crate::spawn::Spawn($a),
458
$crate::spawn::Spawn($b),
459
$crate::spawn::Spawn($c),
460
)
461
};
462
($a:expr, $b:expr, $c:expr, $d:expr) => {
463
(
464
$crate::spawn::Spawn($a),
465
$crate::spawn::Spawn($b),
466
$crate::spawn::Spawn($c),
467
$crate::spawn::Spawn($d),
468
)
469
};
470
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr) => {
471
(
472
$crate::spawn::Spawn($a),
473
$crate::spawn::Spawn($b),
474
$crate::spawn::Spawn($c),
475
$crate::spawn::Spawn($d),
476
$crate::spawn::Spawn($e),
477
)
478
};
479
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr) => {
480
(
481
$crate::spawn::Spawn($a),
482
$crate::spawn::Spawn($b),
483
$crate::spawn::Spawn($c),
484
$crate::spawn::Spawn($d),
485
$crate::spawn::Spawn($e),
486
$crate::spawn::Spawn($f),
487
)
488
};
489
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr) => {
490
(
491
$crate::spawn::Spawn($a),
492
$crate::spawn::Spawn($b),
493
$crate::spawn::Spawn($c),
494
$crate::spawn::Spawn($d),
495
$crate::spawn::Spawn($e),
496
$crate::spawn::Spawn($f),
497
$crate::spawn::Spawn($g),
498
)
499
};
500
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr) => {
501
(
502
$crate::spawn::Spawn($a),
503
$crate::spawn::Spawn($b),
504
$crate::spawn::Spawn($c),
505
$crate::spawn::Spawn($d),
506
$crate::spawn::Spawn($e),
507
$crate::spawn::Spawn($f),
508
$crate::spawn::Spawn($g),
509
$crate::spawn::Spawn($h),
510
)
511
};
512
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $i:expr) => {
513
(
514
$crate::spawn::Spawn($a),
515
$crate::spawn::Spawn($b),
516
$crate::spawn::Spawn($c),
517
$crate::spawn::Spawn($d),
518
$crate::spawn::Spawn($e),
519
$crate::spawn::Spawn($f),
520
$crate::spawn::Spawn($g),
521
$crate::spawn::Spawn($h),
522
$crate::spawn::Spawn($i),
523
)
524
};
525
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $i:expr, $j:expr) => {
526
(
527
$crate::spawn::Spawn($a),
528
$crate::spawn::Spawn($b),
529
$crate::spawn::Spawn($c),
530
$crate::spawn::Spawn($d),
531
$crate::spawn::Spawn($e),
532
$crate::spawn::Spawn($f),
533
$crate::spawn::Spawn($g),
534
$crate::spawn::Spawn($h),
535
$crate::spawn::Spawn($i),
536
$crate::spawn::Spawn($j),
537
)
538
};
539
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $i:expr, $j:expr, $k:expr) => {
540
(
541
$crate::spawn::Spawn($a),
542
$crate::spawn::Spawn($b),
543
$crate::spawn::Spawn($c),
544
$crate::spawn::Spawn($d),
545
$crate::spawn::Spawn($e),
546
$crate::spawn::Spawn($f),
547
$crate::spawn::Spawn($g),
548
$crate::spawn::Spawn($h),
549
$crate::spawn::Spawn($i),
550
$crate::spawn::Spawn($j),
551
$crate::spawn::Spawn($k),
552
)
553
};
554
555
// recursive expansion
556
(
557
$a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr,
558
$g:expr, $h:expr, $i:expr, $j:expr, $k:expr, $($rest:expr),*
559
) => {
560
(
561
$crate::spawn::Spawn($a),
562
$crate::spawn::Spawn($b),
563
$crate::spawn::Spawn($c),
564
$crate::spawn::Spawn($d),
565
$crate::spawn::Spawn($e),
566
$crate::spawn::Spawn($f),
567
$crate::spawn::Spawn($g),
568
$crate::spawn::Spawn($h),
569
$crate::spawn::Spawn($i),
570
$crate::spawn::Spawn($j),
571
$crate::spawn::Spawn($k),
572
$crate::recursive_spawn!($($rest),*)
573
)
574
};
575
}
576
577
#[cfg(test)]
578
mod tests {
579
580
use crate::{
581
name::Name,
582
prelude::{ChildOf, Children, RelationshipTarget},
583
relationship::RelatedSpawner,
584
world::World,
585
};
586
587
use super::{Spawn, SpawnIter, SpawnRelated, SpawnWith, WithOneRelated, WithRelated};
588
589
#[test]
590
fn spawn() {
591
let mut world = World::new();
592
593
let parent = world
594
.spawn((
595
Name::new("Parent"),
596
Children::spawn(Spawn(Name::new("Child1"))),
597
))
598
.id();
599
600
let children = world
601
.query::<&Children>()
602
.get(&world, parent)
603
.expect("An entity with Children should exist");
604
605
assert_eq!(children.iter().count(), 1);
606
607
for ChildOf(child) in world.query::<&ChildOf>().iter(&world) {
608
assert_eq!(child, &parent);
609
}
610
}
611
612
#[test]
613
fn spawn_iter() {
614
let mut world = World::new();
615
616
let parent = world
617
.spawn((
618
Name::new("Parent"),
619
Children::spawn(SpawnIter(["Child1", "Child2"].into_iter().map(Name::new))),
620
))
621
.id();
622
623
let children = world
624
.query::<&Children>()
625
.get(&world, parent)
626
.expect("An entity with Children should exist");
627
628
assert_eq!(children.iter().count(), 2);
629
630
for ChildOf(child) in world.query::<&ChildOf>().iter(&world) {
631
assert_eq!(child, &parent);
632
}
633
}
634
635
#[test]
636
fn spawn_with() {
637
let mut world = World::new();
638
639
let parent = world
640
.spawn((
641
Name::new("Parent"),
642
Children::spawn(SpawnWith(|parent: &mut RelatedSpawner<ChildOf>| {
643
parent.spawn(Name::new("Child1"));
644
})),
645
))
646
.id();
647
648
let children = world
649
.query::<&Children>()
650
.get(&world, parent)
651
.expect("An entity with Children should exist");
652
653
assert_eq!(children.iter().count(), 1);
654
655
for ChildOf(child) in world.query::<&ChildOf>().iter(&world) {
656
assert_eq!(child, &parent);
657
}
658
}
659
660
#[test]
661
fn with_related() {
662
let mut world = World::new();
663
664
let child1 = world.spawn(Name::new("Child1")).id();
665
let child2 = world.spawn(Name::new("Child2")).id();
666
667
let parent = world
668
.spawn((
669
Name::new("Parent"),
670
Children::spawn(WithRelated::new([child1, child2])),
671
))
672
.id();
673
674
let children = world
675
.query::<&Children>()
676
.get(&world, parent)
677
.expect("An entity with Children should exist");
678
679
assert_eq!(children.iter().count(), 2);
680
681
assert_eq!(
682
world.entity(child1).get::<ChildOf>(),
683
Some(&ChildOf(parent))
684
);
685
assert_eq!(
686
world.entity(child2).get::<ChildOf>(),
687
Some(&ChildOf(parent))
688
);
689
}
690
691
#[test]
692
fn with_one_related() {
693
let mut world = World::new();
694
695
let child1 = world.spawn(Name::new("Child1")).id();
696
697
let parent = world
698
.spawn((Name::new("Parent"), Children::spawn(WithOneRelated(child1))))
699
.id();
700
701
let children = world
702
.query::<&Children>()
703
.get(&world, parent)
704
.expect("An entity with Children should exist");
705
706
assert_eq!(children.iter().count(), 1);
707
708
assert_eq!(
709
world.entity(child1).get::<ChildOf>(),
710
Some(&ChildOf(parent))
711
);
712
}
713
}
714
715