本文我们将会介绍三种时间相关的工具------Time
、Timer
和Stopwatch
、,也就是游戏时间、定时器和秒表。
游戏时间
Time
是获取游戏时间的主要全局资源,我们可以在任何系统中访问时间,如果我们需要时间信息,就一定要通过Time
。Bevy会在每一帧的最开始更新时间。
delta 时间
最常见的用法就是获取delta time ------当前帧与上一帧的时间间隔。该时间可以体现游戏帧率有多快(想象一下30
帧和120
帧的时间间隔),因此我们一般通过这个时间来更新移动和动画等内容。这样做可以确保大家以相同的速度运行,无论游戏的帧率有多高。
rust
fn asteroids_fly(
time: Res<Time>,
mut q: Query<&mut Transform, With<Player>>,
) {
for mut transform in q.iter_mut() {
// 沿X轴以每秒10个单位的速度移动玩家
transform.translation.x += 10.0 * time.delta_seconds();
}
}
总运行时间
我们还可以通过Time
获取到自游戏启动以来的总运行时间:
rust
fn elapsed_info(
time: Res<Time>,
) {
info!("Elapsed Time: {:?}", time.elapsed_secs());
}
定时器
Timer
可以用于定时器相关逻辑,例如检测一段时间间隔。Timer
有两种类型:一次性(Once
)和可重复(Repeating
)的。
Timer
需要我们手动计时,即通过tick
让Timer
累计时间。任何类型的Timer
都可以重置reset
。
使用just_finished
检测时间是否达到设定值:
rust
// 定义一个一次性的计时器类型
#[derive(Component)]
struct OnceTimer(Timer);
// 定义一个可循环使用的计时器类型
#[derive(Component)]
struct RepeatingTimer(Timer);
// 设定计时器,添加计时器到系统
fn set_up_timer(
mut commands: Commands,
) {
// 设定一个一次性计时器,3秒后触发
commands.spawn(OnceTimer(Timer::new(Duration::from_secs(3), TimerMode::Once)));
// 设定一个可重复的计时器,每秒触发一次
commands.spawn(RepeatingTimer(Timer::new(Duration::from_secs(1), TimerMode::Repeating)));
}
// 更新计时器
fn update_timer(
time: Res<Time>,
mut once_timer: Query<&mut OnceTimer>,
mut repeating_timer: Query<&mut RepeatingTimer>,
) {
// 获取 delta 时间
let delta = time.delta();
once_timer.iter_mut().for_each(|mut timer| {
// 步进计时器
timer.0.tick(delta);
// 检查计时器是否达到设定的时间点
if timer.0.just_finished() {
info!("Once timer just finished");
}
});
repeating_timer.iter_mut().for_each(|mut timer| {
timer.0.tick(delta);
if timer.0.just_finished() {
info!("Repeating timer just finished");
}
});
}
rust
// other code...
.add_systems(Startup, set_up_timer)
.add_systems(Update, update_timer)
// other code...
我们看下输出结果:
makefile
2025-03-17T01:30:53.968213Z INFO time: Repeating timer just finished
2025-03-17T01:30:54.968752Z INFO time: Repeating timer just finished
2025-03-17T01:30:55.969461Z INFO time: Once timer just finished
2025-03-17T01:30:55.969547Z INFO time: Repeating timer just finished
2025-03-17T01:30:56.970133Z INFO time: Repeating timer just finished
2025-03-17T01:30:57.971532Z INFO time: Repeating timer just finished
2025-03-17T01:30:58.971745Z INFO time: Repeating timer just finished
2025-03-17T01:30:59.972249Z INFO time: Repeating timer just finished
2025-03-17T01:31:00.957014Z INFO time: Repeating timer just finished
一次性的计时器在3
秒触发,后续不再触发。
可重复计时器会每秒都出发。
如果我们想让一次性定时器再次出发,可以使用reset
重置定时器。
rust
fn reset_once_timer(
mut once_timer: Query<&mut OnceTimer>,
) {
once_timer.iter_mut().for_each(|mut timer| {
// 重置定时器
timer.0.reset();
});
}
当定时器重置之后,定时器又会重新累计时间。
秒表
秒表的用法和定时器Timer
类似,只不过秒表的主要作用是用于跟踪从过去的某个时间点到现在的累计时间(想象一下现实生活中秒表用于记录发令枪发令开始到运动员到达终点的时间间隔)。
他们的大致区别可以概括为:Stopwatch
专注于记录时间累计值(如技能冷却剩余时间),而Timer
更适合周期性触发事件(如每秒恢复生命值)。
rust
#[derive(Component)]
struct RunWatch(Stopwatch);
// 生成秒表
fn setup_watch(
mut commands: Commands,
) {
commands.spawn(RunWatch(Stopwatch::new()));
}
// 秒表相关逻辑
fn run_watch(
time: Res<Time>,
mut watch: Query<&mut RunWatch>,
key_input:Res<ButtonInput<KeyCode>>
) {
watch.iter_mut().for_each(|mut run| {
// 秒表的时间累计
run.0.tick(time.delta());
if key_input.just_pressed(KeyCode::Enter) {
// 打印秒表的累计时间
info!("time gone: {}", run.0.elapsed_secs());
}
})
}