移除检测
可参考的官方例子:
removal_detection
.
移除检测很特别,这是因为,与变更检测不同,移除对象的数据不再存在于 ECS 中(很明显),所以 Bevy 无法保持跟踪它的元数据。
尽管如此,能够对移除作出反应对某些应用来说是很重要的,所以 Bevy 提供了一种有限的形式。
组件
你可以检查在当前帧中已经被移除的组件,该数据在每一帧更新结束时被清除。注意,这使得这个功能使用起来很麻烦,需要你使用多个阶段。
当你删除一个组件时(使用命令),该操作会在阶段结束时生效,在同一帧更新期间,检查移除的系统必须在移除操作所在阶段的后一个阶段运行。否则,它将无法检测到移除的情况。
使用 RemovedComponents<T>
这个特殊的系统参数类型,可以得到一个迭代器,用来获取所有实体
的 ID,这些实体有一个类型为 T
的组件,在这个帧的早的时候被移除。
/// Some component type for the sake of this example.
#[derive(Component)]
struct Seen;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
// we could add our system to Bevy's `PreUpdate` stage
// (alternatively, you could create your own stage)
.add_system_to_stage(CoreStage::PreUpdate, remove_components)
// our detection system runs in a later stage
// (in this case: Bevy's default `Update` stage)
.add_system(detect_removals)
.run();
}
fn remove_components(
mut commands: Commands,
q: Query<(Entity, &Transform), With<Seen>>,
) {
for (e, transform) in q.iter() {
if transform.translation.y < -10.0 {
// remove the `Seen` component from the entity
commands.entity(e)
.remove::<Seen>();
}
}
}
fn detect_removals(
removals: RemovedComponents<Seen>,
// ... (maybe Commands or a Query ?) ...
) {
for entity in removals.iter() {
// do something with the entity
}
}
(要对这些实体进行处理,你可以直接用 Commands::entity()
或 Query::get()
来使用实体的 ID。)
资源
Bevy 没有提供任何 API 来检测资源何时被移除。
你可以使用 Option
和一个单独的 Local
系统参数来解决这个问题,有效地实现你自己的检测。
fn detect_removed_res(
my_res: Option<Res<MyResource>>,
mut my_res_existed: Local<bool>,
) {
if let Some(my_res) = my_res {
// the resource exists!
// remember that!
*my_res_existed = true;
// (... you can do something with the resource here if you want ...)
} else if *my_res_existed {
// the resource does not exist, but we remember it existed!
// (it was removed)
// forget about it!
*my_res_existed = false;
// ... do something now that it is gone ...
}
}
请注意,由于这个检测是在你的系统本地进行的,所以不要求它要在同一帧更新期间发生。