bevy_ecs/
spawn.rs

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
4use crate::{
5    bundle::{Bundle, BundleEffect, DynamicBundle, NoBundleEffect},
6    entity::Entity,
7    relationship::{RelatedSpawner, Relationship, RelationshipTarget},
8    world::{EntityWorldMut, World},
9};
10use alloc::vec::Vec;
11use core::marker::PhantomData;
12use 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/// ```
36pub 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.
40pub 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
49impl<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
60impl<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/// ```
86pub struct SpawnIter<I>(pub I);
87
88impl<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/// ```
122pub struct SpawnWith<F>(pub F);
123
124impl<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
136macro_rules! spawnable_list_impl {
137    ($($list: ident),*) => {
138        #[expect(
139            clippy::allow_attributes,
140            reason = "This is a tuple-related macro; as such, the lints below may not always apply."
141        )]
142        impl<R: Relationship, $($list: SpawnableList<R>),*> SpawnableList<R> for ($($list,)*) {
143            fn spawn(self, _world: &mut World, _entity: Entity) {
144                #[allow(
145                    non_snake_case,
146                    reason = "The names of these variables are provided by the caller, not by us."
147                )]
148                let ($($list,)*) = self;
149                $($list.spawn(_world, _entity);)*
150            }
151
152            fn size_hint(&self) -> usize {
153                #[allow(
154                    non_snake_case,
155                    reason = "The names of these variables are provided by the caller, not by us."
156                )]
157                let ($($list,)*) = self;
158                0 $(+ $list.size_hint())*
159            }
160       }
161    }
162}
163
164all_tuples!(spawnable_list_impl, 0, 12, P);
165
166/// A [`Bundle`] that:
167/// 1. Contains a [`RelationshipTarget`] component (associated with the given [`Relationship`]). This reserves space for the [`SpawnableList`].
168/// 2. Spawns a [`SpawnableList`] of related entities with a given [`Relationship`].
169///
170/// This is intended to be created using [`SpawnRelated`].
171pub struct SpawnRelatedBundle<R: Relationship, L: SpawnableList<R>> {
172    list: L,
173    marker: PhantomData<R>,
174}
175
176impl<R: Relationship, L: SpawnableList<R>> BundleEffect for SpawnRelatedBundle<R, L> {
177    fn apply(self, entity: &mut EntityWorldMut) {
178        let id = entity.id();
179        entity.world_scope(|world: &mut World| {
180            self.list.spawn(world, id);
181        });
182    }
183}
184
185// SAFETY: This internally relies on the RelationshipTarget's Bundle implementation, which is sound.
186unsafe impl<R: Relationship, L: SpawnableList<R> + Send + Sync + 'static> Bundle
187    for SpawnRelatedBundle<R, L>
188{
189    fn component_ids(
190        components: &mut crate::component::ComponentsRegistrator,
191        ids: &mut impl FnMut(crate::component::ComponentId),
192    ) {
193        <R::RelationshipTarget as Bundle>::component_ids(components, ids);
194    }
195
196    fn get_component_ids(
197        components: &crate::component::Components,
198        ids: &mut impl FnMut(Option<crate::component::ComponentId>),
199    ) {
200        <R::RelationshipTarget as Bundle>::get_component_ids(components, ids);
201    }
202
203    fn register_required_components(
204        components: &mut crate::component::ComponentsRegistrator,
205        required_components: &mut crate::component::RequiredComponents,
206    ) {
207        <R::RelationshipTarget as Bundle>::register_required_components(
208            components,
209            required_components,
210        );
211    }
212}
213impl<R: Relationship, L: SpawnableList<R>> DynamicBundle for SpawnRelatedBundle<R, L> {
214    type Effect = Self;
215
216    fn get_components(
217        self,
218        func: &mut impl FnMut(crate::component::StorageType, bevy_ptr::OwningPtr<'_>),
219    ) -> Self::Effect {
220        <R::RelationshipTarget as RelationshipTarget>::with_capacity(self.list.size_hint())
221            .get_components(func);
222        self
223    }
224}
225
226/// A [`Bundle`] that:
227/// 1. Contains a [`RelationshipTarget`] component (associated with the given [`Relationship`]). This reserves space for a single entity.
228/// 2. Spawns a single related entity containing the given `B` [`Bundle`] and the given [`Relationship`].
229///
230/// This is intended to be created using [`SpawnRelated`].
231pub struct SpawnOneRelated<R: Relationship, B: Bundle> {
232    bundle: B,
233    marker: PhantomData<R>,
234}
235
236impl<R: Relationship, B: Bundle> BundleEffect for SpawnOneRelated<R, B> {
237    fn apply(self, entity: &mut EntityWorldMut) {
238        entity.with_related::<R>(self.bundle);
239    }
240}
241
242impl<R: Relationship, B: Bundle> DynamicBundle for SpawnOneRelated<R, B> {
243    type Effect = Self;
244
245    fn get_components(
246        self,
247        func: &mut impl FnMut(crate::component::StorageType, bevy_ptr::OwningPtr<'_>),
248    ) -> Self::Effect {
249        <R::RelationshipTarget as RelationshipTarget>::with_capacity(1).get_components(func);
250        self
251    }
252}
253
254// SAFETY: This internally relies on the RelationshipTarget's Bundle implementation, which is sound.
255unsafe impl<R: Relationship, B: Bundle> Bundle for SpawnOneRelated<R, B> {
256    fn component_ids(
257        components: &mut crate::component::ComponentsRegistrator,
258        ids: &mut impl FnMut(crate::component::ComponentId),
259    ) {
260        <R::RelationshipTarget as Bundle>::component_ids(components, ids);
261    }
262
263    fn get_component_ids(
264        components: &crate::component::Components,
265        ids: &mut impl FnMut(Option<crate::component::ComponentId>),
266    ) {
267        <R::RelationshipTarget as Bundle>::get_component_ids(components, ids);
268    }
269
270    fn register_required_components(
271        components: &mut crate::component::ComponentsRegistrator,
272        required_components: &mut crate::component::RequiredComponents,
273    ) {
274        <R::RelationshipTarget as Bundle>::register_required_components(
275            components,
276            required_components,
277        );
278    }
279}
280
281/// [`RelationshipTarget`] methods that create a [`Bundle`] with a [`DynamicBundle::Effect`] that:
282///
283/// 1. Contains the [`RelationshipTarget`] component, pre-allocated with the necessary space for spawned entities.
284/// 2. Spawns an entity (or a list of entities) that relate to the entity the [`Bundle`] is added to via the [`RelationshipTarget::Relationship`].
285pub trait SpawnRelated: RelationshipTarget {
286    /// Returns a [`Bundle`] containing this [`RelationshipTarget`] component. It also spawns a [`SpawnableList`] of entities, each related to the bundle's entity
287    /// via [`RelationshipTarget::Relationship`]. The [`RelationshipTarget`] (when possible) will pre-allocate space for the related entities.
288    ///
289    /// See [`Spawn`], [`SpawnIter`], and [`SpawnWith`] for usage examples.
290    fn spawn<L: SpawnableList<Self::Relationship>>(
291        list: L,
292    ) -> SpawnRelatedBundle<Self::Relationship, L>;
293
294    /// Returns a [`Bundle`] containing this [`RelationshipTarget`] component. It also spawns a single entity containing [`Bundle`] that is related to the bundle's entity
295    /// via [`RelationshipTarget::Relationship`].
296    ///
297    /// ```
298    /// # use bevy_ecs::hierarchy::Children;
299    /// # use bevy_ecs::spawn::SpawnRelated;
300    /// # use bevy_ecs::name::Name;
301    /// # use bevy_ecs::world::World;
302    /// let mut world = World::new();
303    /// world.spawn((
304    ///     Name::new("Root"),
305    ///     Children::spawn_one(Name::new("Child")),
306    /// ));
307    /// ```
308    fn spawn_one<B: Bundle>(bundle: B) -> SpawnOneRelated<Self::Relationship, B>;
309}
310
311impl<T: RelationshipTarget> SpawnRelated for T {
312    fn spawn<L: SpawnableList<Self::Relationship>>(
313        list: L,
314    ) -> SpawnRelatedBundle<Self::Relationship, L> {
315        SpawnRelatedBundle {
316            list,
317            marker: PhantomData,
318        }
319    }
320
321    fn spawn_one<B: Bundle>(bundle: B) -> SpawnOneRelated<Self::Relationship, B> {
322        SpawnOneRelated {
323            bundle,
324            marker: PhantomData,
325        }
326    }
327}
328
329/// Returns a [`SpawnRelatedBundle`] that will insert the given [`RelationshipTarget`], spawn a [`SpawnableList`] of entities with given bundles that
330/// relate to the [`RelationshipTarget`] entity via the [`RelationshipTarget::Relationship`] component, and reserve space in the [`RelationshipTarget`] for each spawned entity.
331///
332/// The first argument is the [`RelationshipTarget`] type. Any additional arguments will be interpreted as bundles to be spawned.
333///
334/// Also see [`children`](crate::children) for a [`Children`](crate::hierarchy::Children)-specific equivalent.
335///
336/// ```
337/// # use bevy_ecs::hierarchy::Children;
338/// # use bevy_ecs::name::Name;
339/// # use bevy_ecs::world::World;
340/// # use bevy_ecs::related;
341/// # use bevy_ecs::spawn::{Spawn, SpawnRelated};
342/// let mut world = World::new();
343/// world.spawn((
344///     Name::new("Root"),
345///     related!(Children[
346///         Name::new("Child1"),
347///         (
348///             Name::new("Child2"),
349///             related!(Children[
350///                 Name::new("Grandchild"),
351///             ])
352///         )
353///     ])
354/// ));
355/// ```
356#[macro_export]
357macro_rules! related {
358    ($relationship_target:ty [$($child:expr),*$(,)?]) => {
359       <$relationship_target>::spawn(($($crate::spawn::Spawn($child)),*))
360    };
361}