泛型系统
Bevy 系统只是普通的 Rust 函数,这意味着这些函数是可以泛型化的,对不同的 Rust 类型或值进行参数化处理,相同的系统可以多次复用。
组件类型泛型化
你可以使用泛型类型参数来指定你的系统可以对哪些组件类型(以及哪些实体)进行操作。
这在与 Bevy 状态结合使用时会很有用。你可以根据状态对不同的实体集做同样的事情。
例子:清理
一个直观的用例是用于清理。我们可以做一个通用的清理系统,用于将所有具有某种组件类型的实体销毁掉,然后,在退出不同的状态时运行它。
use bevy::ecs::component::Component;
fn cleanup_system<T: Component>(
mut commands: Commands,
q: Query<Entity, With<T>>,
) {
for e in q.iter() {
commands.entity(e).despawn_recursive();
}
}
菜单实体可以用 cleanup::MenuExit
来标记,游戏地图的实体可以用 cleanup::LevelUnload
来标记。
我们可以将通用的清理系统添加到我们的状态转换中,来处理各自的实体:
/// Marker components to group entities for cleanup
mod cleanup {
use bevy::prelude::*;
#[derive(Component)]
pub struct LevelUnload;
#[derive(Component)]
pub struct MenuClose;
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
enum AppState {
MainMenu,
InGame,
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_state(AppState::MainMenu)
// add the cleanup systems
.add_system_set(SystemSet::on_exit(AppState::MainMenu)
.with_system(cleanup_system::<cleanup::MenuClose>))
.add_system_set(SystemSet::on_exit(AppState::InGame)
.with_system(cleanup_system::<cleanup::LevelUnload>))
.run();
}
使用 Trait
当你需要为每种类型提供某种不同的方法或功能时,你可以把它和 Trait 结合起来使用。
例子:Bevy 的摄像机投影
(这是 Bevy 本身的一个用例)
Bevy 有一个 CameraProjection
trait。不同的投影类型,如 PerspectiveProjection
和 OrthographicProjection
都实现了这个 trait,
为如何响应调整窗口大小、计算投影矩阵等提供正确的逻辑。
有一个通用的系统 fn camera_system::<T: CameraProjection + Component>
,它用于处理所有具有给定投影类型的摄像机,它将在适当的时候调用 trait 方法(比如在窗口调整事件中)。
Bevy 手册中的自定义相机投影实例展示了这个 API 的作用。
使用常量泛型
既然 Rust 支持 Const Generics,那么函数也可以通过值来参数化,而不仅仅是类型。
fn process_layer<const LAYER_ID: usize>(
// system params
) {
// do something for this `LAYER_ID`
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_system(process_layer::<1>)
.add_system(process_layer::<2>)
.add_system(process_layer::<3>)
.run();
}
需要注意的是,这些值在编译时是静态/常量。这可能会是一个严重的限制。在某些情况下,当你或在犹疑你可以使用常量泛型时,你可能最终意识到你实际上想要的是一个运行时值。
如果你需要通过传递一些数据来"配置"你的系统,你可以使用一个 Resource 或 Local。
注意:从 Rust 1.59 开始,对使用枚举
值作为常量泛型的支持还不稳定。要使用枚举
,你需要 Rust Nightly 版,并启用实验中和不稳定的特性(把这个放在你的 main.rs
或 lib.rs
的顶部):
#![feature(adt_const_params)]