timers/
timers.rs

1//! Illustrates how `Timer`s can be used both as resources and components.
2
3use bevy::{log::info, prelude::*};
4
5fn main() {
6    App::new()
7        .add_plugins(DefaultPlugins)
8        .init_resource::<Countdown>()
9        .add_systems(Startup, setup)
10        .add_systems(Update, (countdown, print_when_completed))
11        .run();
12}
13
14#[derive(Component, Deref, DerefMut)]
15struct PrintOnCompletionTimer(Timer);
16
17#[derive(Resource)]
18struct Countdown {
19    percent_trigger: Timer,
20    main_timer: Timer,
21}
22
23impl Countdown {
24    pub fn new() -> Self {
25        Self {
26            percent_trigger: Timer::from_seconds(4.0, TimerMode::Repeating),
27            main_timer: Timer::from_seconds(20.0, TimerMode::Once),
28        }
29    }
30}
31
32impl Default for Countdown {
33    fn default() -> Self {
34        Self::new()
35    }
36}
37
38fn setup(mut commands: Commands) {
39    // Add an entity to the world with a timer
40    commands.spawn(PrintOnCompletionTimer(Timer::from_seconds(
41        5.0,
42        TimerMode::Once,
43    )));
44}
45
46/// This system ticks the `Timer` on the entity with the `PrintOnCompletionTimer`
47/// component using bevy's `Time` resource to get the delta between each update.
48fn print_when_completed(time: Res<Time>, mut query: Query<&mut PrintOnCompletionTimer>) {
49    for mut timer in &mut query {
50        if timer.tick(time.delta()).just_finished() {
51            info!("Entity timer just finished");
52        }
53    }
54}
55
56/// This system controls ticking the timer within the countdown resource and
57/// handling its state.
58fn countdown(time: Res<Time>, mut countdown: ResMut<Countdown>) {
59    countdown.main_timer.tick(time.delta());
60
61    // The API encourages this kind of timer state checking (if you're only checking for one value)
62    // Additionally, `is_finished()` would accomplish the same thing as `just_finished` due to the
63    // timer being repeating, however this makes more sense visually.
64    if countdown.percent_trigger.tick(time.delta()).just_finished() {
65        if !countdown.main_timer.is_finished() {
66            // Print the percent complete the main timer is.
67            info!(
68                "Timer is {:0.0}% complete!",
69                countdown.main_timer.fraction() * 100.0
70            );
71        } else {
72            // The timer has finished so we pause the percent output timer
73            countdown.percent_trigger.pause();
74            info!("Paused percent trigger timer");
75        }
76    }
77}