父子层级结构
可参考的官方例子:
hierarchy
,
parenting
.
从技术上讲,实体/组件 本身不能形成一个层级结构(ECS 是一个一维平面数据结构)。然而,逻辑层级结构是游戏中的一种常见模式。
Bevy 支持在实体之间建立这样的逻辑联系:以形成一个虚拟的 "层级",只需在各自的实体上添加 Parent
、Children
组件即可。
当使用 Commands 来生成实体时,Commands 有向实体添加子对象的方法,这个方法同时可以为子对象自动添加正确的组件。
// spawn the parent and get its Entity id
let parent = commands.spawn_bundle(MyParentBundle::default())
.id();
// do the same for the child
let child = commands.spawn_bundle(MyChildBundle::default())
.id();
// add the child to the parent
commands.entity(parent).push_children(&[child]);
// you can also use `with_children`:
commands.spawn_bundle(MyParentBundle::default())
.with_children(|parent| {
parent.spawn_bundle(MyChildBundle::default());
});
你可以通过一条 command 命令将某个层级包含的所有实体全部销毁:
fn close_menu(
mut commands: Commands,
query: Query<Entity, With<MainMenuUI>>,
) {
for entity in query.iter() {
// despawn the entity and its children
commands.entity(entity).despawn_recursive();
}
}
访问父对象或子对象
为了开发一个能与层级结构一起工作的 system 函数,你通常需要两个Query查询参数:
- 一个用来访问包含你想要组件的子实体
- 一个用来访问包含你想要组件的父实体
在这两个查询参数中,一个参数应该包含适当的组件(Component),获得实体的 ID,以便与另一个参数查询到的结果一起使用:
例如,如果我们想获得有父对象的摄相机(Camera)的 Transform
,以及它们父对象的 GlobalTransform
:
fn camera_with_parent(
q_child: Query<(&Parent, &Transform), With<Camera>>,
q_parent: Query<&GlobalTransform>,
) {
for (parent, child_transform) in q_child.iter() {
// `parent` contains the Entity ID we can use
// to query components from the parent:
let parent_global_transform = q_parent.get(parent.0);
// do something with the components
}
}
再举个例子,比如我们在开发一个策略游戏,我们有一群作战单元是隶属于同一个小分队的子对象。假设我们需要编写一个对每个小分队起作用的系统,这个系统需要访问关于子对象的一些信息:
fn process_squad_damage(
q_parent: Query<(&MySquadDamage, &Children)>,
q_child: Query<&MyUnitHealth>,
) {
// get the properties of each squad
for (squad_dmg, children) in q_parent.iter() {
// `children` is a collection of Entity IDs
for &child in children.iter() {
// get the health of each child unit
let health = q_child.get(child);
// do something
}
}
}
相对变换
如果你的实体代表某种 "游戏世界中的对象",你可能希望子对象能相对于父对象定位,并随其移动。
Bevy 内置 Bundles 创建的对象,都会自动为它们提供了上面提到的父子相对定位行为。
如果你没有使用这样的 Bundle,你需要确保在父对象和子对象中都添加这些组件:GlobalTransform
和 Transform
。
Transform
表示相对位置,你可以直接修改它。
GlobalTransform
代表绝对位置,它是由 bevy 内部管理的,不要自己修改和维护它。
更多信息,请访问关于变换的专门页面。