Latest commit 23576f7

时间和计时器

相关的官方文档:[timers]、[move_sprite]


时间

Time 是全局资源,可以从任何系统访问来获取时间信息。

Bevy 在每帧开始时更新这些值。

增量时间

最常用的是 delta 时间:上一帧和当前帧之间经过了多少时间。可以通过 delta 得知游戏运行的速度,使用 delta 能让游戏忽略帧率平稳地运行。

#![allow(unused)]
fn main() {
fn asteroids_fly(
    time: Res<Time>,
    mut q: Query<&mut Transform, With<Asteroid>>,
) {
    for mut transform in q.iter_mut() {
        // 沿 X 轴以每秒 10.0 单位的速度移动小行星
        transform.translation.x += 10.0 * time.delta_seconds();
    }
}
}

持续时间

Time 还提供自 App 启动以来的总运行时间。

#![allow(unused)]
fn main() {
use std::time::Instant;

/// 目标时获取实体生成时的具体时间
#[derive(Component)]
struct SpawnedTime(Instant);

fn spawn_my_stuff(
    mut commands: Commands,
    time: Res<Time>,
) {
    commands
        .spawn()
        .insert(SpawnedTime(time.startup() + time.time_since_startup()));
}
}

计时器和秒表

TimerStopwatch 可以处理时间间隔和定时。可以在自定义的组件和资源中使用。

计时器和秒表需要系统来驱动:在系统中调用 .tick(delta) 函数来使计时器、秒表工作,否则不会开始计时。可以在 Time 资源查看详细信息。

计时器

Timer 可以检测流逝的时间。计时器有一个设定的时间。计时器可以设置成“重复”或“不重复”。

计时器可以手动“重置”(重新开始)和“暂停”(即使调用 .tick() 也不会工作)。

设定为“重复”的计时器会在达到设定的持续时间时自动重置。

todo:需要测试 Use .finished() to detect when a timer has reached its set duration. Use .just_finished(), if you need to detect only on the exact tick when the duration was reached.

#![allow(unused)]
fn main() {
use std::time::Duration;

#[derive(Component)]
struct FuseTime {
    /// 炸弹爆炸倒计时(不重复计时)
    timer: Timer,
}

fn 引爆炸弹(
    mut commands: Commands,
    mut q: Query<(Entity, &mut FuseTime)>,
    time: Res<Time>,
) {
    for (entity, mut fuse_timer) in q.iter_mut() {
        // 计时器必须“滴答”计时才能工作
        fuse_timer.timer.tick(time.delta());

        // 计时完成,由于世界和平,炸弹会被拆除
        if fuse_timer.timer.finished() {
            commands.entity(entity).despawn();
        }
    }
}

struct BombsSpawnConfig {
    // 定义多久产生新的炸弹(重复计时)
    timer: Timer,
}

/// 隔一段时间产生新的炸弹
fn 生成炸弹(
    mut commands: Commands,
    time: Res<Time>,
    mut config: ResMut<BombsSpawnConfig>,
) {
    // 计时器开始计时
    config.timer.tick(time.delta());

    if config.timer.finished() {
        commands
            .spawn()
            .insert(FuseTime {
                // 不重复的计时器
                timer: Timer::new(Duration::from_secs(5), false),
            });
    }
}

// 配置我们的炸弹生成算法
fn 炸弹生成设置(
    mut commands: Commands,
) {
    commands.insert_resource(BombsSpawnConfig {
        // 重复的计时器
        timer: Timer::new(Duration::from_secs(10), true),
    });
}
}

注意,Bevy 的计时器无法像典型的现实计时器那样工作(倒计时)。Bevy 的计时器从零开始计时,直到设定的“持续时间”(duration)。计时器就像秒表,但是多了额外的功能:最大持续时间、可选的“自动重置”。

秒表

todo:新概念。