环境: v0.16.
fn spawn_splash_screen(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.ui_root().insert((
Name::new("Splash screen"),
BackgroundColor(SPLASH_BACKGROUND_COLOR),
StateScoped(Screen::Splash),
children.
"images/splash.png",
|settings: &mut ImageLoaderSettings| {
// Make an exception for the splash image in case
// `ImagePlugin::default_nearest()` is used for pixel art.
settings.sampler = ImageSampler::linear();
},
)),
ImageNodeFadeInOut {
total_duration: SPLASH_DURATION_SECS,
fade_duration: SPLASH_FADE_DURATION_SECS,
t: 0.0,
},
)],
));
}
commands.ui_root 全屏居中Node的快捷方式
/// An extension trait for spawning UI containers.
pub trait Containers {
/// Spawns a root node that covers the full screen
/// and centers its content horizontally and vertically.
fn ui_root(&mut self) -> EntityCommands;
}
impl Containers for Commands<'_, '_> {
fn ui_root(&mut self) -> EntityCommands {
self.spawn((
Name::new("UI Root"),
Node {
width: Percent(100.0),
height: Percent(100.0),
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
flex_direction: FlexDirection::Column,
row_gap: Px(10.0),
position_type: PositionType::Absolute,
..default()
},
))
}
}
children! 声明子实体列表
#[macro_export]
macro_rules! children {
[$($child:expr),*$(,)?] => {
$crate::hierarchy::Children::spawn(($($crate::spawn::Spawn($child)),*))
};
}
Children的定义如下,是组件Component,也是关系目标relationship_target:子实体.
#[derive(Component, Default, Debug, PartialEq, Eq)]
#[relationship_target(relationship = ChildOf, linked_spawn)]
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
#[cfg_attr(feature = "bevy_reflect", reflect(Component, FromWorld, Default))]
#[doc(alias = "IsParent")]
pub struct Children(Vec<Entity>);
Children的方法spawn来自SpawnRelated特型. 翻译一下就是:我有子实体,我就能spawn子实体.
pub trait SpawnRelated: RelationshipTarget {...}
impl<T: RelationshipTarget> SpawnRelated for T {
fn spawn<L: SpawnableList<Self::Relationship>>(
list: L,
) -> SpawnRelatedBundle<Self::Relationship, L> {
SpawnRelatedBundle {
list,
marker: PhantomData,
}
}
}
至于子实体spawn的时机,就在于apply这里,入参是world和id,此id是父实体的Entity,后面会用到:
pub struct SpawnRelatedBundle<R: Relationship, L: SpawnableList<R>> {
list: L,
marker: PhantomData<R>,
}
impl<R: Relationship, L: SpawnableList<R>> BundleEffect for SpawnRelatedBundle<R, L> {
fn apply(self, entity: &mut EntityWorldMut) {
let id = entity.id();
entity.world_scope(|world: &mut World| {
self.list.spawn(world, id);
});
}
}
SpawnableList特型的其中一个实现如下,不继续往下跟踪了,接下来对比一下with_children:
pub struct SpawnWith<F>(pub F);
impl<R: Relationship, F: FnOnce(&mut RelatedSpawner<R>) + Send + Sync + 'static> SpawnableList<R>
for SpawnWith<F>
{
fn spawn(self, world: &mut World, entity: Entity) {
world.entity_mut(entity).with_related_entities(self.0);
}
fn size_hint(&self) -> usize {
1
}
}
常用的with_children如下,和上面的SpawnWith.spawn对比一下, 不难发现两者都是创建子实体(ChildOf,子实体).
impl<'a> EntityCommands<'a> {
/// Spawns children of this entity (with a [`ChildOf`] relationship) by taking a function that operates on a [`ChildSpawner`].
pub fn with_children(
&mut self,
func: impl FnOnce(&mut RelatedSpawnerCommands<ChildOf>),
) -> &mut Self {
self.with_related_entities(func);
self
}
pub fn with_related_entities<R: Relationship>(
&mut self,
func: impl FnOnce(&mut RelatedSpawnerCommands<R>),
) -> &mut Self {
let id = self.id();
func(&mut RelatedSpawnerCommands::new(self.commands(), id));
self
}
}
至于父实体的Children组件的填充,肯定是在子实体创建之后通过Hook再进行填充的.