Skip to main content

flake/misc/
timer.rs

1use std::cell::RefCell;
2use std::pin::Pin;
3use std::rc::Rc;
4use std::task::{Context, Poll};
5use crate::prelude::add_timer;
6
7/// # Timer
8///
9/// A timer that counts down each frame. Can be paused and extended.
10/// Actions can be boundd to the timer that will run on completion.
11///
12/// Don't put the timer in the loop
13///
14/// Timers won't run by default, you must call `add_timer()` and pass in the timer
15/// to add them to the timer list. Or call `spawn_timer(seconds)` and it will run immediately.
16///
17/// ```
18/// let mut my_timer = add_timer(Timer::new(5.0));
19/// // or
20/// let mut my_timer = spawn_timer(5.0);
21/// ```
22///
23/// ```
24/// println!("Time left: {}", my_timer.time_left);
25/// println!("Timer is paused: {}", my_timer.paused);
26/// ```
27///
28/// ```
29/// my_timer.extend(2.0); // extend by 2 seconds
30///
31/// if my_timer.completed() {
32///     // timer is completed
33/// }
34///
35/// if my_timer.ongoing() {
36///     // timer is active
37/// }
38///
39/// // Pause/Unpause a timer
40/// my_timer.pause();
41/// my_timer.unpause();
42/// my_timer.set_paused(true);
43/// my_timer.toggle_paused();
44///
45/// // Action will run if the timer is completed (must be called each frame)
46/// my_timer.on_completion(|| {
47///     println!("Timer was completed!");
48/// })
49///
50/// // Reset the time left to the original (does not include `extend()`)
51/// my_timer.reset();
52///
53/// // Stop the timer (marks as completed())
54/// my_timer.finish();
55/// ```
56///
57/// Once a timer is completed it will be removed from the timer list.
58/// The timer will stop ticking and `on_completion()` will stop firing.
59///
60/// ```
61/// // Re-add a timer to the timer list (REMEMBER TO RESET IT)
62/// my_timer.reset();
63/// add_timer(my_timer);
64/// ```
65#[derive(Default, Clone, PartialEq, PartialOrd)]
66pub struct Timer(pub Rc<RefCell<TimerData>>);
67
68#[derive(Default, Clone, Copy, PartialEq, PartialOrd)]
69pub struct TimerData {
70    original_time: f32,
71    pub time_left: f32,
72    
73    pub paused: bool,
74    pub is_active: bool,
75    pub repeating: bool,
76}
77
78impl Future for Timer {
79    type Output = ();
80
81    fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
82        if self.completed() {
83            Poll::Ready(())
84        } else {
85            Poll::Pending
86        }
87    }
88}
89
90impl Timer {
91    /// Create a new timer using seconds
92    pub fn new(seconds: f32) -> Self {
93        Self(Rc::new(RefCell::new(TimerData {
94            original_time: seconds,
95            time_left: seconds,
96            
97            paused: false,
98            is_active: false,
99            repeating: false,
100        })))
101    }
102    
103    /// Create a new repeating timer using seconds. Restarts after completing
104    pub fn new_repeating(seconds: f32) -> Self {
105        Self(Rc::new(RefCell::new(TimerData {
106            time_left: seconds,
107            paused: false,
108            is_active: false,
109            repeating: true,
110            original_time: seconds,
111        })))
112    }
113
114    /// Tick down the time left by `dt` (deltatime) only if it's unpaused
115    pub fn tick(&mut self, dt: f32) {
116        if !self.0.borrow().paused {
117            self.0.borrow_mut().time_left -= dt;
118        }
119    }
120
121    /// Reset the timer to original time (does not include `extend()`)
122    pub fn reset(&self) {
123        let mut t = self.0.borrow_mut();
124        t.time_left = t.original_time;
125    }
126
127    /// Sets time left to zero (completed) which may also remove the timer from the timer list
128    pub fn finish(&self) {
129        self.0.borrow_mut().time_left = 0.0;
130    }
131
132    /// Pause the timer
133    pub fn pause(&self) {
134        self.0.borrow_mut().paused = true;
135    }
136
137    /// Unpause the timer
138    pub fn unpause(&self) {
139        self.0.borrow_mut().paused = false;
140    }
141
142    /// Set whether timer is paused or not
143    pub fn set_paused(&self, paused: bool) {
144        self.0.borrow_mut().paused = paused;
145    }
146
147    /// Toggle the timer paused/unpaused
148    pub fn toggle_paused(&self) {
149        let mut t = self.0.borrow_mut();
150        t.paused = !t.paused;
151    }
152
153    /// Extend (or decrease) the timer's time left
154    pub fn extend(&self, seconds: f32) {
155        self.0.borrow_mut().time_left += seconds;
156    }
157
158    /// Check if timer is ongoing (time left > 0)
159    pub fn ongoing(&self) -> bool {
160        self.0.borrow().time_left > 0.0
161    }
162
163    /// Check if timer is active (in the timer list)
164    pub fn is_active(&self) -> bool {
165        self.0.borrow().is_active
166    }
167
168    /// Runs an action if timer is completed (only runs if timer is in timer list)
169    pub fn on_completion(&self, mut action: impl FnMut()) {
170        if !self.ongoing() && self.0.borrow().is_active {
171            action()
172        }
173    }
174
175    /// Returns `true` if the timer was just completed this frame
176    pub fn completed(&self) -> bool {
177        !self.ongoing() && self.0.borrow().is_active
178    }
179
180    /// Restarts the timer and adds it to the timer list
181    pub fn restart(&self) -> Timer {
182        self.reset();
183        self.start()
184    }
185
186    /// Restarts the timer if it just got completed this frame,
187    /// also returns whether its `completed()` or not
188    pub fn completed_and_restart(&self) -> bool {
189        let completed = self.completed();
190        if completed {
191            self.restart();
192        }
193        completed
194    }
195
196    /// Starts the timer (adds it to the timer list)
197    pub fn start(&self) -> Timer {
198        add_timer(self.clone())
199    }
200    
201    pub async fn wait(&self) {
202        self.clone().await
203    }
204}