在之前的Bevy ECS章节,我们简单的介绍了Bevy中Entity,Component,System的功能。当时我们定义System提供了修改游戏行为的能力。这篇文章,我们更加深入的使用System,带给大家更多的System用法。
何时运行System
我们先创建一个简单的System:
fn update_system() {
info!("Updating system");
}
该System就简单的在控制台输入一个日志。
在Bevy中,打印日志可以使用宏info!,debug!,warn!,error!,用法与print!宏类似。
我们将其添加到App中:
App::new()
// other code...
.add_systems(Update, update_system)
// other code...
此处我们看到,在添加到App中时,函数add_systems需要两个参数,第二个参数就是我们的System函数,而第一个参数,就是用来设置我们的System何时运行的,也就是调度——Schedule。当前使用了Update,这个调度就是游戏运行的每一帧执行一次。
当我们运行这段代码的时候,我们会发现,控制台打印非常多,也就对应了游戏中的帧数非常高(一般是60FPS)。
Bevy中还有其他很多的调度,这里列出三个常用的,其他的随着文章的进行,会进一步讲解:
Update,每个渲染帧运行一次。Startup,应用启动时运行一次。FixedUpdate,大部分游戏逻辑的调度(如物理模拟)。它以固定速率运行,与。如果应该每个渲染帧运行一次的逻辑,请使用Update。
闭包System
如果只是测试或者写一个比较简单的System,我们可以使用Rust闭包来编写System:
//other code...
.add_systems(Startup, || {
info!("Startup");
})
.add_systems(Update, || {
info!("Updating");
})
.add_systems(FixedUpdate, || {
info!("FixedUpdate");
})
//other code...
结合刚刚学到的内容,我们使用闭包来编写System,大家可以看看控制台输出,在Startup输出之后,Updating和FixedUpdate会一直轮流输出。对应着Startup在应用启动时执行一次,而Update和FixedUpdate会在应用运行期间,执行很多次。
多个System
如果我们想在一个调度中,加入多个System(显然,这很常见),可以使用元组(Tuple)的方式添加:
.add_systems(Update, (system_a, system_b))
指定执行顺序
在Bevy中,System的默认执行方式是并行的,当多个System之间的没有显示的指定顺序且没有冲突,那么System的执行就是多线程并行,如果我们想指定System的执行顺序,那么可以使用chain方式:
// 指定 system_c --> system_b --> system_a 的执行顺序
.add_systems(Update, (system_c, system_b, system_a).chain())
条件系统
如果我们想设定System在某些条件下运行,那么我们就需要使用运行条件:
// 指定系统在敲击空格键的时候执行
.add_systems(Update, system_a.run_if(input_just_pressed(KeyCode::Space)))
当然,我们也可以自己制定运行条件,例如,设置系统在2秒钟之后执行:
// 编写一个运行条件函数,该函数返回一个bool类型
fn time_passed(t: f32) -> impl FnMut(Local<f32>, Res<Time>) -> bool {
move |mut timer: Local<f32>, time: Res<Time>| {
// Tick the timer
*timer += time.delta_secs();
// Return true if the timer has passed the time
*timer >= t
}
}
添加到系统:
// 设定系统在两秒中之后运行
.add_systems(Update, system_c.run_if(time_passed(2f32)))
OK,关于System的初阶知识,就到这里。