Bevy 时间

本文我们将会介绍三种时间相关的工具------TimeTimerStopwatch、,也就是游戏时间、定时器和秒表。

游戏时间

Time是获取游戏时间的主要全局资源,我们可以在任何系统中访问时间,如果我们需要时间信息,就一定要通过TimeBevy会在每一帧的最开始更新时间。

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需要我们手动计时,即通过tickTimer累计时间。任何类型的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());
        }
    })
}
相关推荐
m0_480502641 天前
Rust 入门 生命周期-next2 (十九)
开发语言·后端·rust
寻月隐君1 天前
Rust Web 开发实战:使用 SQLx 连接 PostgreSQL 数据库
后端·rust·github
百万蹄蹄向前冲2 天前
Trae分析Phaser.js游戏《洋葱头捡星星》
前端·游戏开发·trae
GitLqr2 天前
AI洞察 | 混元、昆仑 重塑 3D 世界新方向
计算机视觉·游戏开发·音视频开发
Moonbit2 天前
MoonBit Pearls Vol.05: 函数式里的依赖注入:Reader Monad
后端·rust·编程语言
Thomas游戏开发2 天前
博毅创为 Unity_0基础就业班
前端框架·unity3d·游戏开发
Vallelonga2 天前
Rust 异步中的 Waker
经验分享·rust·异步·底层
m0_480502643 天前
Rust 入门 KV存储HashMap (十七)
java·开发语言·rust
Include everything3 天前
Rust学习笔记(三)|所有权机制 Ownership
笔记·学习·rust
谷宇.3 天前
【Unity3D实例-功能-拔枪】角色拔枪(二)分割上身和下身
游戏·unity·c#·游戏程序·unity3d·游戏开发·游戏编程