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());
        }
    })
}
相关推荐
SmalBox11 小时前
【节点】[SampleTexture3D节点]原理解析与实际应用
unity3d·游戏开发·图形学
JCHwa1 天前
UE5 GAS 源码深度解析 | 第2篇:AttributeSet 源码导读
游戏开发·unreal engine
问道飞鱼1 天前
【Tauri框架学习】Tauri 与 React 前端集成:通信机制与交互原理详解
前端·学习·react.js·rust·通信
SmalBox2 天前
【节点】[SampleTexture2DLOD节点]原理解析与实际应用
unity3d·游戏开发·图形学
weixin_387534222 天前
Ownership - Rust Hardcore Head to Toe
开发语言·后端·算法·rust
luffy54592 天前
Rust语言入门-变量篇
开发语言·后端·rust
好家伙VCC2 天前
# 发散创新:用 Rust构建高性能游戏日系统,从零实现事件驱动架构 在现代游戏开发中,**性能与可扩展性**是核心命题。传统基于
java·python·游戏·架构·rust
Source.Liu2 天前
【Iced】transformation.rs文件解析
rust·iced
fetasty2 天前
Godot游戏练习01-第15节-敌人生成动画,翻转,碰撞
游戏开发
小杍随笔2 天前
【Rust 语言编程知识与应用:闭包详解】
开发语言·后端·rust