Latest commit c8a3aaa
Hierarchical(Parent/Child) Entities
相关的官方文档:[hierarchy]、[parenting]
从技术上讲,实体/组件本身不能形成层次结构(它们是扁平数据结构)。但是,逻辑层次结构是游戏中常见的模式,Bevy 支持在实体之间建立有层次的逻辑联系,形成虚拟的 “层次结构”,方法是在实体上添加 Parent 组件和 Children 组件。
可以用 Commands 自带的方法给实体添加子实体,这些方法会自动添加正确的组件:
#![allow(unused)] fn main() { // 生成父实体并获取 ID let parent = commands.spawn_bundle(MyParentBundle::default()).id(); // 生成子实体并获取 ID let child = commands.spawn_bundle(MyChildBundle::default()).id(); // 把子实体添加到父实体,形成层级关系 commands.entity(parent).push_children(&[child]); // 也可以用 `with_children` commands.spawn_bundle(MyParentBundle::default()) .with_children(|child_builder| { cchild_builder.spawn_bundle(MyChildBundle::default()); }); }
可以用一个命令来销毁实体层级:
#![allow(unused)] fn main() { fn close_menu( mut commands: Commands, query: Query<Entity, With<MainMenuUI>>, ) { for entity in query.iter() { // 销毁实体和它的所有子级实体 commands.entity(entity).despawn_recursive(); } } }
访问父实体或子实体
要让系统处理具有层次结构的实体,要用到两个 Query:
- 一个查询子实体的组件
- 另一个查询父实体的组件
其中的一个查询应该包含合适的组件,才能获取所需的实体 ID:
- 如果在查询实体时要获取父实体的数据,就要用
Parent组件来获取父实体的 ID - 如果在查询实体时要获取子实体的数据,就要用
Children组件来获取子实体的 ID
例如,某个相机有一个父实体,需要获取相机的 Transform 和父实体的 GlobalTransform:
#![allow(unused)] fn main() { fn camera_with_parent( q_child: Query<(&Parent, &Transform), With<Camera>>, q_parent: Query<&GlobalTransform>, ) { for (parent, child_transform) in q_child.iter() { // `parent` 变量包含 Entity 的 ID,可以用这个 ID 来查询父实体的组件 let parent_global_transform = q_parent.get(parent.0); // 做一些事 } } }
再举一个例子,假设我们正在做一个战略游戏,游戏中的某个小分队(父实体)有一些成员(子实体)。为了使某个系统在每个小分队(父实体)上都有效,这个系统需要这些成员(子实体)的信息:
#![allow(unused)] fn main() { fn process_squad_damage( q_parent: Query<(&MySquadDamage, &Children)>, q_child: Query<&MyUnitHealth>, ) { // 获取每个小队的属性 for (squad_dmg, children) in q_parent.iter() { // `children` 是实体 ID 的集合 for &child in children.iter() { // 获取每个子实体单位的 “Health” let health = q_child.get(child); // 做一些事 } } } }
相对变换
如果实体代表“游戏世界中的对象”,那么子实体应该相对于父实体定位,并随父实体移动。
所有 Bevy 内置的 Bundle 自动提供“相对变换”功能。如果只要变换,不需要其他东西,可以使用 TransformBundle。
更多信息请查看[Transforms and Coordinates]。
变换和可见性传播
如果实体代表“游戏世界中的对象”,那么子实体应该受到父实体的影响:
- Transform:子实体相对于父实体定位,并随父实体移动
- Visibility:父实体的可见性会影响子实体的可见性
所有 Bevy 内置 Bundle 都是这样。自定义 Bundle 可以用 SpatialBundle 来添加 Transform 和 Visibility。