mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 04:33:37 +00:00
Add run conditions for executing a system after a delay (#11095)
# Objective I want to run a system once after a given delay. - First, I tried using the `on_timer` run condition, but it uses a repeating timer, causing the system to run multiple times. - Next, I tried combining the `on_timer` with the `run_once` run condition. However, this causes the timer to *tick* only once, so the system is never executed. ## Solution - ~~Replace `on_timer` by `on_time_interval` and `on_real_timer` by `on_real_time_interval` to clarify the meaning (the old ones are deprecated to avoid a breaking change).~~ (Reverted according to feedback) - Add `once_after_delay` and `once_after_real_delay` to run the system exactly once after the delay, using `TimerMode::Once`. - Add `repeating_after_delay` and `repeating_after_real_delay` to run the system indefinitely after the delay, using `Timer::finished` instead of `Timer::just_finished`. --- ## Changelog ### Added - `once_after_delay` and `once_after_real_delay` run conditions to run the system exactly once after the delay, using `TimerMode::Once`. - `repeating_after_delay` and `repeating_after_real_delay` run conditions to run the system indefinitely after the delay, using `Timer::finished` instead of `Timer::just_finished`.
This commit is contained in:
parent
b257fffef8
commit
cf3105a0db
1 changed files with 135 additions and 5 deletions
|
@ -13,8 +13,11 @@ use bevy_utils::Duration;
|
|||
/// fn main() {
|
||||
/// App::new()
|
||||
/// .add_plugins(DefaultPlugins)
|
||||
/// .add_systems(Update, tick.run_if(on_timer(Duration::from_secs(1))))
|
||||
/// .run();
|
||||
/// .add_systems(
|
||||
/// Update,
|
||||
/// tick.run_if(on_timer(Duration::from_secs(1))),
|
||||
/// )
|
||||
/// .run();
|
||||
/// }
|
||||
/// fn tick() {
|
||||
/// // ran once a second
|
||||
|
@ -38,8 +41,9 @@ pub fn on_timer(duration: Duration) -> impl FnMut(Res<Time>) -> bool + Clone {
|
|||
}
|
||||
}
|
||||
|
||||
/// Run condition that is active on a regular time interval, using [`Time<Real>`] to advance
|
||||
/// the timer. The timer ticks are not scaled.
|
||||
/// Run condition that is active on a regular time interval,
|
||||
/// using [`Time<Real>`] to advance the timer.
|
||||
/// The timer ticks are not scaled.
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use bevy_app::{App, NoopPluginGroup as DefaultPlugins, PluginGroup, Update};
|
||||
|
@ -49,7 +53,10 @@ pub fn on_timer(duration: Duration) -> impl FnMut(Res<Time>) -> bool + Clone {
|
|||
/// fn main() {
|
||||
/// App::new()
|
||||
/// .add_plugins(DefaultPlugins)
|
||||
/// .add_systems(Update, tick.run_if(on_real_timer(Duration::from_secs(1))))
|
||||
/// .add_systems(
|
||||
/// Update,
|
||||
/// tick.run_if(on_real_timer(Duration::from_secs(1))),
|
||||
/// )
|
||||
/// .run();
|
||||
/// }
|
||||
/// fn tick() {
|
||||
|
@ -74,10 +81,133 @@ pub fn on_real_timer(duration: Duration) -> impl FnMut(Res<Time<Real>>) -> bool
|
|||
}
|
||||
}
|
||||
|
||||
/// Run condition that is active *once* after the specified delay,
|
||||
/// using [`Time`] to advance the timer.
|
||||
/// The timer ticks at the rate of [`Time::relative_speed`].
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use bevy_app::{App, NoopPluginGroup as DefaultPlugins, PluginGroup, Update};
|
||||
/// # use bevy_ecs::schedule::IntoSystemConfigs;
|
||||
/// # use bevy_utils::Duration;
|
||||
/// # use bevy_time::common_conditions::once_after_delay;
|
||||
/// fn main() {
|
||||
/// App::new()
|
||||
/// .add_plugins(DefaultPlugins)
|
||||
/// .add_systems(
|
||||
/// Update,
|
||||
/// tick.run_if(once_after_delay(Duration::from_secs(1))),
|
||||
/// )
|
||||
/// .run();
|
||||
/// }
|
||||
/// fn tick() {
|
||||
/// // ran once, after a second
|
||||
/// }
|
||||
/// ```
|
||||
pub fn once_after_delay(duration: Duration) -> impl FnMut(Res<Time>) -> bool + Clone {
|
||||
let mut timer = Timer::new(duration, TimerMode::Once);
|
||||
move |time: Res<Time>| {
|
||||
timer.tick(time.delta());
|
||||
timer.just_finished()
|
||||
}
|
||||
}
|
||||
|
||||
/// Run condition that is active *once* after the specified delay,
|
||||
/// using [`Time<Real>`] to advance the timer.
|
||||
/// The timer ticks are not scaled.
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use bevy_app::{App, NoopPluginGroup as DefaultPlugins, PluginGroup, Update};
|
||||
/// # use bevy_ecs::schedule::IntoSystemConfigs;
|
||||
/// # use bevy_utils::Duration;
|
||||
/// # use bevy_time::common_conditions::once_after_delay;
|
||||
/// fn main() {
|
||||
/// App::new()
|
||||
/// .add_plugins(DefaultPlugins)
|
||||
/// .add_systems(
|
||||
/// Update,
|
||||
/// tick.run_if(once_after_delay(Duration::from_secs(1))),
|
||||
/// )
|
||||
/// .run();
|
||||
/// }
|
||||
/// fn tick() {
|
||||
/// // ran once, after a second
|
||||
/// }
|
||||
/// ```
|
||||
pub fn once_after_real_delay(duration: Duration) -> impl FnMut(Res<Time<Real>>) -> bool + Clone {
|
||||
let mut timer = Timer::new(duration, crate::TimerMode::Once);
|
||||
move |time: Res<Time<Real>>| {
|
||||
timer.tick(time.delta());
|
||||
timer.just_finished()
|
||||
}
|
||||
}
|
||||
|
||||
/// Run condition that is active *indefinitely* after the specified delay,
|
||||
/// using [`Time`] to advance the timer.
|
||||
/// The timer ticks at the rate of [`Time::relative_speed`].
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use bevy_app::{App, NoopPluginGroup as DefaultPlugins, PluginGroup, Update};
|
||||
/// # use bevy_ecs::schedule::IntoSystemConfigs;
|
||||
/// # use bevy_utils::Duration;
|
||||
/// # use bevy_time::common_conditions::repeating_after_delay;
|
||||
/// fn main() {
|
||||
/// App::new()
|
||||
/// .add_plugins(DefaultPlugins)
|
||||
/// .add_systems(
|
||||
/// Update,
|
||||
/// tick.run_if(repeating_after_delay(Duration::from_secs(1))),
|
||||
/// )
|
||||
/// .run();
|
||||
/// }
|
||||
/// fn tick() {
|
||||
/// // ran every frame, after a second
|
||||
/// }
|
||||
/// ```
|
||||
pub fn repeating_after_delay(duration: Duration) -> impl FnMut(Res<Time>) -> bool + Clone {
|
||||
let mut timer = Timer::new(duration, TimerMode::Once);
|
||||
move |time: Res<Time>| {
|
||||
timer.tick(time.delta());
|
||||
timer.finished()
|
||||
}
|
||||
}
|
||||
|
||||
/// Run condition that is active *indefinitely* after the specified delay,
|
||||
/// using [`Time<Real>`] to advance the timer.
|
||||
/// The timer ticks are not scaled.
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use bevy_app::{App, NoopPluginGroup as DefaultPlugins, PluginGroup, Update};
|
||||
/// # use bevy_ecs::schedule::IntoSystemConfigs;
|
||||
/// # use bevy_utils::Duration;
|
||||
/// # use bevy_time::common_conditions::repeating_after_real_delay;
|
||||
/// fn main() {
|
||||
/// App::new()
|
||||
/// .add_plugins(DefaultPlugins)
|
||||
/// .add_systems(
|
||||
/// Update,
|
||||
/// tick.run_if(repeating_after_real_delay(Duration::from_secs(1))),
|
||||
/// )
|
||||
/// .run();
|
||||
/// }
|
||||
/// fn tick() {
|
||||
/// // ran every frame, after a second
|
||||
/// }
|
||||
/// ```
|
||||
pub fn repeating_after_real_delay(
|
||||
duration: Duration,
|
||||
) -> impl FnMut(Res<Time<Real>>) -> bool + Clone {
|
||||
let mut timer = Timer::new(duration, TimerMode::Once);
|
||||
move |time: Res<Time<Real>>| {
|
||||
timer.tick(time.delta());
|
||||
timer.finished()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use bevy_ecs::schedule::{IntoSystemConfigs, Schedule};
|
||||
use std::time::Duration;
|
||||
|
||||
fn test_system() {}
|
||||
|
||||
|
|
Loading…
Reference in a new issue