mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
Timer Polishing (#931)
* Pause stops ticks. Consistent getter method names. Update tests. * Add timing example * Format with the nightly formatter Co-authored-by: Amber Kowalski <amberkowalski03@gmail.com>
This commit is contained in:
parent
f69cc6f94c
commit
12f29bd38c
9 changed files with 126 additions and 33 deletions
|
@ -12,7 +12,8 @@ current changes on git with [previous release tags][git_tag_comparison].
|
|||
### Added
|
||||
|
||||
### Changed
|
||||
|
||||
- [Breaking changes to timer API][914]
|
||||
- [Removed timer auto-ticking system][931]
|
||||
### Fixed
|
||||
|
||||
|
||||
|
|
|
@ -198,6 +198,10 @@ path = "examples/ecs/startup_system.rs"
|
|||
name = "system_chaining"
|
||||
path = "examples/ecs/system_chaining.rs"
|
||||
|
||||
[[example]]
|
||||
name = "timers"
|
||||
path = "examples/ecs/timers.rs"
|
||||
|
||||
[[example]]
|
||||
name = "ecs_guide"
|
||||
path = "examples/ecs/ecs_guide.rs"
|
||||
|
|
|
@ -41,12 +41,12 @@ impl Timer {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn resume(&mut self) {
|
||||
pub fn unpause(&mut self) {
|
||||
self.paused = false
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_paused(&self) -> bool {
|
||||
pub fn paused(&self) -> bool {
|
||||
self.paused
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,7 @@ impl Timer {
|
|||
/// Non repeating timers will stop tracking and stay in the finished state until reset.
|
||||
/// Repeating timers will only be in the finished state on each tick `duration` is reached or exceeded, and can still be reset at any given point.
|
||||
#[inline]
|
||||
pub fn is_finished(&self) -> bool {
|
||||
pub fn finished(&self) -> bool {
|
||||
self.finished
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ impl Timer {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_repeating(&self) -> bool {
|
||||
pub fn repeating(&self) -> bool {
|
||||
self.repeating
|
||||
}
|
||||
|
||||
|
@ -98,11 +98,15 @@ impl Timer {
|
|||
|
||||
/// Advances the timer by `delta` seconds.
|
||||
pub fn tick(&mut self, delta: f32) -> &Self {
|
||||
if self.paused {
|
||||
return self;
|
||||
}
|
||||
let prev_finished = self.finished;
|
||||
self.elapsed += delta;
|
||||
|
||||
self.finished = self.elapsed >= self.duration;
|
||||
self.just_finished = !prev_finished && self.finished;
|
||||
|
||||
if self.finished {
|
||||
if self.repeating {
|
||||
// Repeating timers wrap around
|
||||
|
@ -142,25 +146,36 @@ mod tests {
|
|||
let mut t = Timer::from_seconds(10.0, false);
|
||||
// Tick once, check all attributes
|
||||
t.tick(0.25);
|
||||
assert_eq!(t.elapsed, 0.25);
|
||||
assert_eq!(t.duration, 10.0);
|
||||
assert_eq!(t.finished, false);
|
||||
assert_eq!(t.just_finished, false);
|
||||
assert_eq!(t.repeating, false);
|
||||
assert_eq!(t.elapsed(), 0.25);
|
||||
assert_eq!(t.duration(), 10.0);
|
||||
assert_eq!(t.finished(), false);
|
||||
assert_eq!(t.just_finished(), false);
|
||||
assert_eq!(t.repeating(), false);
|
||||
assert_eq!(t.percent(), 0.025);
|
||||
assert_eq!(t.percent_left(), 0.975);
|
||||
// Ticking while paused changes nothing
|
||||
t.pause();
|
||||
t.tick(500.0);
|
||||
assert_eq!(t.elapsed(), 0.25);
|
||||
assert_eq!(t.duration(), 10.0);
|
||||
assert_eq!(t.finished(), false);
|
||||
assert_eq!(t.just_finished(), false);
|
||||
assert_eq!(t.repeating(), false);
|
||||
assert_eq!(t.percent(), 0.025);
|
||||
assert_eq!(t.percent_left(), 0.975);
|
||||
// Tick past the end and make sure elapsed doesn't go past 0.0 and other things update
|
||||
t.unpause();
|
||||
t.tick(500.0);
|
||||
assert_eq!(t.elapsed, 10.0);
|
||||
assert_eq!(t.finished, true);
|
||||
assert_eq!(t.just_finished, true);
|
||||
assert_eq!(t.elapsed(), 10.0);
|
||||
assert_eq!(t.finished(), true);
|
||||
assert_eq!(t.just_finished(), true);
|
||||
assert_eq!(t.percent(), 1.0);
|
||||
assert_eq!(t.percent_left(), 0.0);
|
||||
// Continuing to tick when finished should only change just_finished
|
||||
t.tick(1.0);
|
||||
assert_eq!(t.elapsed, 10.0);
|
||||
assert_eq!(t.finished, true);
|
||||
assert_eq!(t.just_finished, false);
|
||||
assert_eq!(t.elapsed(), 10.0);
|
||||
assert_eq!(t.finished(), true);
|
||||
assert_eq!(t.just_finished(), false);
|
||||
assert_eq!(t.percent(), 1.0);
|
||||
assert_eq!(t.percent_left(), 0.0);
|
||||
}
|
||||
|
@ -170,25 +185,25 @@ mod tests {
|
|||
let mut t = Timer::from_seconds(2.0, true);
|
||||
// Tick once, check all attributes
|
||||
t.tick(0.75);
|
||||
assert_eq!(t.elapsed, 0.75);
|
||||
assert_eq!(t.duration, 2.0);
|
||||
assert_eq!(t.finished, false);
|
||||
assert_eq!(t.just_finished, false);
|
||||
assert_eq!(t.repeating, true);
|
||||
assert_eq!(t.elapsed(), 0.75);
|
||||
assert_eq!(t.duration(), 2.0);
|
||||
assert_eq!(t.finished(), false);
|
||||
assert_eq!(t.just_finished(), false);
|
||||
assert_eq!(t.repeating(), true);
|
||||
assert_eq!(t.percent(), 0.375);
|
||||
assert_eq!(t.percent_left(), 0.625);
|
||||
// Tick past the end and make sure elapsed wraps
|
||||
t.tick(1.5);
|
||||
assert_eq!(t.elapsed, 0.25);
|
||||
assert_eq!(t.finished, true);
|
||||
assert_eq!(t.just_finished, true);
|
||||
assert_eq!(t.elapsed(), 0.25);
|
||||
assert_eq!(t.finished(), true);
|
||||
assert_eq!(t.just_finished(), true);
|
||||
assert_eq!(t.percent(), 0.125);
|
||||
assert_eq!(t.percent_left(), 0.875);
|
||||
// Continuing to tick should turn off both finished & just_finished for repeating timers
|
||||
t.tick(1.0);
|
||||
assert_eq!(t.elapsed, 1.25);
|
||||
assert_eq!(t.finished, false);
|
||||
assert_eq!(t.just_finished, false);
|
||||
assert_eq!(t.elapsed(), 1.25);
|
||||
assert_eq!(t.finished(), false);
|
||||
assert_eq!(t.just_finished(), false);
|
||||
assert_eq!(t.percent(), 0.625);
|
||||
assert_eq!(t.percent_left(), 0.375);
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ impl PrintDiagnosticsPlugin {
|
|||
time: Res<Time>,
|
||||
diagnostics: Res<Diagnostics>,
|
||||
) {
|
||||
if state.timer.tick(time.delta_seconds).is_finished() {
|
||||
if state.timer.tick(time.delta_seconds).finished() {
|
||||
println!("Diagnostics:");
|
||||
println!("{}", "-".repeat(93));
|
||||
if let Some(ref filter) = state.filter {
|
||||
|
@ -86,7 +86,7 @@ impl PrintDiagnosticsPlugin {
|
|||
time: Res<Time>,
|
||||
diagnostics: Res<Diagnostics>,
|
||||
) {
|
||||
if state.timer.tick(time.delta_seconds).is_finished() {
|
||||
if state.timer.tick(time.delta_seconds).finished() {
|
||||
println!("Diagnostics (Debug):");
|
||||
println!("{}", "-".repeat(93));
|
||||
if let Some(ref filter) = state.filter {
|
||||
|
|
|
@ -13,7 +13,7 @@ fn animate_sprite_system(
|
|||
mut query: Query<(&mut Timer, &mut TextureAtlasSprite, &Handle<TextureAtlas>)>,
|
||||
) {
|
||||
for (timer, mut sprite, texture_atlas_handle) in query.iter_mut() {
|
||||
if timer.is_finished() {
|
||||
if timer.finished() {
|
||||
let texture_atlas = texture_atlases.get(texture_atlas_handle).unwrap();
|
||||
sprite.index = ((sprite.index as usize + 1) % texture_atlas.textures.len()) as u32;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ struct PrintMessageState {
|
|||
}
|
||||
|
||||
fn print_message_system(mut state: ResMut<PrintMessageState>, time: Res<Time>) {
|
||||
if state.timer.tick(time.delta_seconds).is_finished() {
|
||||
if state.timer.tick(time.delta_seconds).finished() {
|
||||
println!("{}", state.message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ fn event_trigger_system(
|
|||
mut state: ResMut<EventTriggerState>,
|
||||
mut my_events: ResMut<Events<MyEvent>>,
|
||||
) {
|
||||
if state.event_timer.tick(time.delta_seconds).is_finished() {
|
||||
if state.event_timer.tick(time.delta_seconds).finished() {
|
||||
my_events.send(MyEvent {
|
||||
message: "MyEvent just happened!".to_string(),
|
||||
});
|
||||
|
|
73
examples/ecs/timers.rs
Normal file
73
examples/ecs/timers.rs
Normal file
|
@ -0,0 +1,73 @@
|
|||
use bevy::{log::info, prelude::*};
|
||||
|
||||
fn main() {
|
||||
App::build()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_resource(Countdown::default())
|
||||
.add_startup_system(setup_system)
|
||||
.add_system(countdown_system)
|
||||
.add_system(timer_system)
|
||||
.run();
|
||||
}
|
||||
|
||||
pub struct Countdown {
|
||||
pub percent_trigger: Timer,
|
||||
pub main_timer: Timer,
|
||||
}
|
||||
|
||||
impl Countdown {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
percent_trigger: Timer::from_seconds(4.0, true),
|
||||
main_timer: Timer::from_seconds(20.0, false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Countdown {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_system(commands: &mut Commands) {
|
||||
// Add an entity to the world with a timer
|
||||
commands.spawn((Timer::from_seconds(5.0, false),));
|
||||
}
|
||||
|
||||
/// This system ticks all the `Timer` components on entities within the scene
|
||||
/// using bevy's `Time` resource to get the delta between each update.
|
||||
fn timer_system(time: Res<Time>, mut query: Query<&mut Timer>) {
|
||||
for mut timer in query.iter_mut() {
|
||||
if timer.tick(time.delta_seconds).just_finished() {
|
||||
info!("Entity timer just finished")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This system controls ticking the timer within the countdown resource and
|
||||
/// handling its state.
|
||||
fn countdown_system(time: Res<Time>, mut countdown: ResMut<Countdown>) {
|
||||
countdown.main_timer.tick(time.delta_seconds);
|
||||
|
||||
// The API encourages this kind of timer state checking (if you're only checking for one value)
|
||||
// Additionally, `finished()` would accomplish the same thing as `just_finished` due to the timer
|
||||
// being repeating, however this makes more sense visually.
|
||||
if countdown
|
||||
.percent_trigger
|
||||
.tick(time.delta_seconds)
|
||||
.just_finished()
|
||||
{
|
||||
if !countdown.main_timer.finished() {
|
||||
// Print the percent complete the main timer is.
|
||||
info!(
|
||||
"Timer is {:0.0}% complete!",
|
||||
countdown.main_timer.percent() * 100.0
|
||||
);
|
||||
} else {
|
||||
// The timer has finished so we pause the percent output timer
|
||||
countdown.percent_trigger.pause();
|
||||
info!("Paused percent trigger timer")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -62,7 +62,7 @@ fn atlas_render_system(
|
|||
}
|
||||
|
||||
fn text_update_system(mut state: ResMut<State>, time: Res<Time>, mut query: Query<&mut Text>) {
|
||||
if state.timer.tick(time.delta_seconds).is_finished() {
|
||||
if state.timer.tick(time.delta_seconds).finished() {
|
||||
for mut text in query.iter_mut() {
|
||||
let c = rand::random::<u8>() as char;
|
||||
if !text.value.contains(c) {
|
||||
|
|
Loading…
Reference in a new issue