-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Discrete timer and stopwatch #2683
Conversation
Directly mirrors existing Stopwatch, but for discrete time step use cases
Mirrors API and impl of Timer
Code duplication could be reduced somewhat by refactoring these types to use a shared trait. I decided not to for simplicity (there are only two variants, and no obvious extensions), but I'm happy to change that if others feel that I should. I'm not sure where you would want to accept either a |
Is any of this code taken from @maplant's repo? If so, it would be good to make sure we record that properly (I don't expect that we'll need to get in touch with all contributors again, but I don't want to miss any if we do) |
/// assert_eq!(stopwatch.elapsed(), 1); | ||
/// ``` | ||
#[inline] | ||
pub fn unpause(&mut self) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about continue
in favor of unpause
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd probably call that out-of-scope for this PR; I'm just following the existing API :)
(I also slightly prefer unpause
, and think resume
is also better than continue
if we want to change.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple doctests weren't updated from the original timer, but other than that LGTM.
Nope, this is written completely from scratch. |
Is this really a fundamental feature? I couldn't find something similar in Unity or Godot after a quick look. As you mentioned, if the goal is to keep the API close to I would prefer the names ( |
7f3d886
to
a0f4cf7
Compare
It is definitely an important, fundamental feature. Unity does not have this because components have an |
I think this deserves to be in the engine to provide a consistent, useful API and point beginners in the right direction (rather than forcing everyone to write their own data structures for this constantly).
I can do that :) I think it's the right call too; I just didn't want to dive right in before I'd gotten some initial feedback.
IMO these will almost always be used as direct substitutes of the existing |
This link describes the
I disagree, real time timers will always be needed, if only for any kind of animation or sound |
My mistake, what I am looking for is a FixedUpdate, found here: https://docs.unity3d.com/ScriptReference/MonoBehaviour.FixedUpdate.html This is a tick timer.
They may be necessary for display and sound given the way your update loop is structured (although I believe http://gameprogrammingpatterns.com/game-loop.html shows that you can do it in one place, and then have a fixed conversion between ticks and real time), however it's not very good to use system timers for gameplay. If you have a fixed time step, then tick timers are absolutely a direct substitute for system timers. You're never going to update faster than a tick anywhere, so you don't get higher resolution without them. |
I wouldn't say (edit)
Also just wanted to say that a fixed timestep is not a timer. They're technically opposites. (I suppose this means that there could also be an integer variant of
|
Sorry, my sentence structure was not clear there. The point I was trying to make is that "users will often want to swap back and forth between these types directly", not "one is strictly superior": they both have their niches but fundamentally fill a similar role which their API should reflect. |
So @mockersf I've now refactored this PR to use traits :) I'm not thrilled with the end result, so I'd appreciate some mentorship. Here's my thought process:
I've also had to rename Upon writing this up this morning, I'm tempted to:
Allowing end users to be able to extend the trait and refer to it in their code is nice, but it comes at a high cost. |
Closing out for now. The whole Timer API needs a cohesive redesign. |
As mentioned in #2926, it's better to have an explicit type that clearly communicates the intent of the timer mode rather than an opaque boolean, which can be only understood when knowing the signature or having to look up the documentation. This also opens up a way to merge different timers, such as `Stopwatch`, and possibly future ones, such as `DiscreteStopwatch` and `DiscreteTimer` from #2683, into one struct. Signed-off-by: Lena Milizé <me@lvmn.org> # Objective Fixes #2926. ## Solution Introduce `TimerMode` which replaces the `bool` argument of `Timer` constructors. A `Default` value for `TimerMode` is `Once`. --- ## Changelog ### Added - `TimerMode` enum, along with variants `TimerMode::Once` and `TimerMode::Repeating` ### Changed - Replace `bool` argument of `Timer::new` and `Timer::from_seconds` with `TimerMode` - Change `repeating: bool` field of `Timer` with `mode: TimerMode` ## Migration Guide - Replace `Timer::new(duration, false)` with `Timer::new(duration, TimerMode::Once)`. - Replace `Timer::new(duration, true)` with `Timer::new(duration, TimerMode::Repeating)`. - Replace `Timer::from_seconds(seconds, false)` with `Timer::from_seconds(seconds, TimerMode::Once)`. - Replace `Timer::from_seconds(seconds, true)` with `Timer::from_seconds(seconds, TimerMode::Repeating)`. - Change `timer.repeating()` to `timer.mode() == TimerMode::Repeating`.
) As mentioned in bevyengine#2926, it's better to have an explicit type that clearly communicates the intent of the timer mode rather than an opaque boolean, which can be only understood when knowing the signature or having to look up the documentation. This also opens up a way to merge different timers, such as `Stopwatch`, and possibly future ones, such as `DiscreteStopwatch` and `DiscreteTimer` from bevyengine#2683, into one struct. Signed-off-by: Lena Milizé <me@lvmn.org> # Objective Fixes bevyengine#2926. ## Solution Introduce `TimerMode` which replaces the `bool` argument of `Timer` constructors. A `Default` value for `TimerMode` is `Once`. --- ## Changelog ### Added - `TimerMode` enum, along with variants `TimerMode::Once` and `TimerMode::Repeating` ### Changed - Replace `bool` argument of `Timer::new` and `Timer::from_seconds` with `TimerMode` - Change `repeating: bool` field of `Timer` with `mode: TimerMode` ## Migration Guide - Replace `Timer::new(duration, false)` with `Timer::new(duration, TimerMode::Once)`. - Replace `Timer::new(duration, true)` with `Timer::new(duration, TimerMode::Repeating)`. - Replace `Timer::from_seconds(seconds, false)` with `Timer::from_seconds(seconds, TimerMode::Once)`. - Replace `Timer::from_seconds(seconds, true)` with `Timer::from_seconds(seconds, TimerMode::Repeating)`. - Change `timer.repeating()` to `timer.mode() == TimerMode::Repeating`.
) As mentioned in bevyengine#2926, it's better to have an explicit type that clearly communicates the intent of the timer mode rather than an opaque boolean, which can be only understood when knowing the signature or having to look up the documentation. This also opens up a way to merge different timers, such as `Stopwatch`, and possibly future ones, such as `DiscreteStopwatch` and `DiscreteTimer` from bevyengine#2683, into one struct. Signed-off-by: Lena Milizé <me@lvmn.org> # Objective Fixes bevyengine#2926. ## Solution Introduce `TimerMode` which replaces the `bool` argument of `Timer` constructors. A `Default` value for `TimerMode` is `Once`. --- ## Changelog ### Added - `TimerMode` enum, along with variants `TimerMode::Once` and `TimerMode::Repeating` ### Changed - Replace `bool` argument of `Timer::new` and `Timer::from_seconds` with `TimerMode` - Change `repeating: bool` field of `Timer` with `mode: TimerMode` ## Migration Guide - Replace `Timer::new(duration, false)` with `Timer::new(duration, TimerMode::Once)`. - Replace `Timer::new(duration, true)` with `Timer::new(duration, TimerMode::Repeating)`. - Replace `Timer::from_seconds(seconds, false)` with `Timer::from_seconds(seconds, TimerMode::Once)`. - Replace `Timer::from_seconds(seconds, true)` with `Timer::from_seconds(seconds, TimerMode::Repeating)`. - Change `timer.repeating()` to `timer.mode() == TimerMode::Repeating`.
) As mentioned in bevyengine#2926, it's better to have an explicit type that clearly communicates the intent of the timer mode rather than an opaque boolean, which can be only understood when knowing the signature or having to look up the documentation. This also opens up a way to merge different timers, such as `Stopwatch`, and possibly future ones, such as `DiscreteStopwatch` and `DiscreteTimer` from bevyengine#2683, into one struct. Signed-off-by: Lena Milizé <me@lvmn.org> # Objective Fixes bevyengine#2926. ## Solution Introduce `TimerMode` which replaces the `bool` argument of `Timer` constructors. A `Default` value for `TimerMode` is `Once`. --- ## Changelog ### Added - `TimerMode` enum, along with variants `TimerMode::Once` and `TimerMode::Repeating` ### Changed - Replace `bool` argument of `Timer::new` and `Timer::from_seconds` with `TimerMode` - Change `repeating: bool` field of `Timer` with `mode: TimerMode` ## Migration Guide - Replace `Timer::new(duration, false)` with `Timer::new(duration, TimerMode::Once)`. - Replace `Timer::new(duration, true)` with `Timer::new(duration, TimerMode::Repeating)`. - Replace `Timer::from_seconds(seconds, false)` with `Timer::from_seconds(seconds, TimerMode::Once)`. - Replace `Timer::from_seconds(seconds, true)` with `Timer::from_seconds(seconds, TimerMode::Repeating)`. - Change `timer.repeating()` to `timer.mode() == TimerMode::Repeating`.
) As mentioned in bevyengine#2926, it's better to have an explicit type that clearly communicates the intent of the timer mode rather than an opaque boolean, which can be only understood when knowing the signature or having to look up the documentation. This also opens up a way to merge different timers, such as `Stopwatch`, and possibly future ones, such as `DiscreteStopwatch` and `DiscreteTimer` from bevyengine#2683, into one struct. Signed-off-by: Lena Milizé <me@lvmn.org> # Objective Fixes bevyengine#2926. ## Solution Introduce `TimerMode` which replaces the `bool` argument of `Timer` constructors. A `Default` value for `TimerMode` is `Once`. --- ## Changelog ### Added - `TimerMode` enum, along with variants `TimerMode::Once` and `TimerMode::Repeating` ### Changed - Replace `bool` argument of `Timer::new` and `Timer::from_seconds` with `TimerMode` - Change `repeating: bool` field of `Timer` with `mode: TimerMode` ## Migration Guide - Replace `Timer::new(duration, false)` with `Timer::new(duration, TimerMode::Once)`. - Replace `Timer::new(duration, true)` with `Timer::new(duration, TimerMode::Repeating)`. - Replace `Timer::from_seconds(seconds, false)` with `Timer::from_seconds(seconds, TimerMode::Once)`. - Replace `Timer::from_seconds(seconds, true)` with `Timer::from_seconds(seconds, TimerMode::Repeating)`. - Change `timer.repeating()` to `timer.mode() == TimerMode::Repeating`.
Objective
Solution
DiscreteStopwatch
andDiscreteTimer
structs to closely mirror the existingTimer
andStopwatch
API.