-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
Make Time update_with_instant pub #2549
Conversation
bors try |
Welcome! I agree with the need for this, and think this is an excellent, simple solution. As updating the time step manually is typically going to be a mistake in end user code outside of tests, we should add careful doc strings to both this method and the Time type to explain the correct usage :) This would also be a nice addition to testing_systems.rs, found in the root tests folder. |
Actually, this may also be useful for running simulations at faster than real time too. I've seen that requested before too; we should try to document that use case too. A full example might be better for that (you'll need to mess with one of the default plugins), but that work could be saved for a later PR. |
Perhaps only make this pub under #[test] to remove that footgun? |
That is not possible. |
It's probably a bad idea to manually update with an instant in this case, as it would break all deltas exposed by To make this useful outside of test, one would need to disable the bevy/crates/bevy_core/src/time/time.rs Lines 87 to 89 in f71f93c
I don't think that's a good idea, so I would prefer clear doc comments explaining this is only useful for tests. Could a feature to enable test helpers work? |
This was what I had in mind; it's much more useful in scientific settings but I could see it being useful for accelerated simulation in ordinary games (e.g. for machine learning or automated integration tests). Out of scope for this though, and I'd want to try testing that strategy on a full game to see if anything breaks before recommending it. |
In the case of non-linear or scaled time as a feature in games, it might be recommended to keep track of simulated time as a separate resource. In such a case it would be nice to be able to wrap or alias Time, and modify it as needed for your usecase. It's something that should be made possible by this change. I'll add the doc strings discussed. |
I'm not sure if it's feasible, or a good idea, but one way to prevent breaking the default Time resource would be to somehow declare the built-in resource as read-only (outside the bevy crate). |
Sorry about that; rebased from 0.5.0 release.. should I open a new PR? |
Yup, if you can't clean this PR, it would probably be best to open a new one |
06e312f
to
5583f9a
Compare
Sorry about the fuzz, I think it's cleaned up now. Open to input on the doc string and test. |
This change would be very useful to me as well, so I would like to help. What needs to be done to get this ready to be merged? |
@@ -31,7 +31,8 @@ impl Time { | |||
self.update_with_instant(now); | |||
} | |||
|
|||
pub(crate) fn update_with_instant(&mut self, instant: Instant) { | |||
/// Update time with a specified [`Instant`], for use in tests. Should never be called on the default Time resource. |
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.
/// Update time with a specified [`Instant`], for use in tests. Should never be called on the default Time resource. | |
/// Update time with a specified [`Instant`] | |
/// | |
/// This method is for use in tests, and should generally not be called on the [`Time`] resource as part of your app. | |
/// Doing so will conflict with the `time_system` called by [`CorePlugin`], and result in inaccurate performance measurements. |
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.
Just inaccurate timekeeping in general. I would keep the recommendation to only use this to write tests.
So to get this merged, the next step is that we need at least two approvals, including from community members, and all blocking concerns addressed. On my end, I want to see:
|
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'm cool with making update_with_instant
pub
since update
already is.
I will say tho that the featured test seems a little misleading.
At the end it highlights the results between 30 FPS and 60 FPS being similar after a single frame as if that would be the case forever (which is false, would diverge pretty quickly). Integrating by time.delta_seconds()
does decouple motion from the framerate but not in a way that is repeatable or consistent between different FPS.
You only get real framerate independence if you have a constant step size (and then FixedTimestep
or a dedicated thread).
something something running simulations faster than real-time
Is what #3002 is for.
I believe most people understand framerate-independence to mean that motion is separate from the framerate. i.e. the game does not appear to move in slow-motion when the framerate dips, or vise versa. Rather than separating simulation-time from real-time in a fixed timestep setting. With that in mind, I don't think the test is pretending to be more accurate than it is. |
let result_30fps = test_fps(30); | ||
let result_60fps = test_fps(60); |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
In my experience, time-related things confuse users a lot. I understand this is the kind of test OP wanted to mock, but I'd prefer that we didn't feature a test with this premise on the off-chance someone interprets it as an "officially-endorsed" way of handling physics. This is all fine for UI, etc, but if users want stable game physics, they should use a fixed timestep (with interpolation to make it look smooth) because that's the standard and correct way to do it.
I was more pointing out that the test—checking that the motion didn't desync by more than an arbitrary amount under arbitrary FPS values after an arbitrarily small duration—seems pretty convoluted if the point is just to confirm that we didn't forget to multiply by (Edit: But yeah, IMO we shouldn't have a test whose premise is checking the "consistency" of variable timestep motion.) |
Sorry, I probably got too preoccupied with your comment. I agree with you here. what's being tested is basically how much float addition drifts over 30 iterations compared to 60 iterations. I'm in favor of removing the test. |
I'm not the OP, so I cannot update the OP's branch. Should I open a new PR?
I would like to rework the test into an example demonstrating how the function can be used in a test. What do you think? |
Yep sounds great: just link this PR in the description and we can close this one out.
Yes please! I think a doc test on |
I don't currently have the environment set up to assist on this, I'm glad it's being looked into. Feel free to rework it in a new PR. |
I opened #4469 as a follow-up/replacement PR to this one. |
Closed in favor of #4469 |
# Objective To test systems that implement frame rate-independent update logic, one needs to be able to mock `Time`. By mocking time, it's possible to write tests that confirm systems are frame rate-independent. This is a follow-up PR to #2549 by @ostwilkens and based on his work. ## Solution To mock `Time`, one needs to be able to manually update the Time resource with an `Instant` defined by the developer. This can be achieved by making the existing `Time::update_with_instant` method public for use in tests. ## Changelog - Make `Time::update_with_instant` public - Add doc to `Time::update_with_instant` clarifying that the method should not be called outside of tests. - Add doc test to `Time` demonstrating how to use `update_with_instant` in tests. Co-authored-by: Martin Dickopp <[email protected]>
# Objective To test systems that implement frame rate-independent update logic, one needs to be able to mock `Time`. By mocking time, it's possible to write tests that confirm systems are frame rate-independent. This is a follow-up PR to #2549 by @ostwilkens and based on his work. ## Solution To mock `Time`, one needs to be able to manually update the Time resource with an `Instant` defined by the developer. This can be achieved by making the existing `Time::update_with_instant` method public for use in tests. ## Changelog - Make `Time::update_with_instant` public - Add doc to `Time::update_with_instant` clarifying that the method should not be called outside of tests. - Add doc test to `Time` demonstrating how to use `update_with_instant` in tests. Co-authored-by: Martin Dickopp <[email protected]>
# Objective To test systems that implement frame rate-independent update logic, one needs to be able to mock `Time`. By mocking time, it's possible to write tests that confirm systems are frame rate-independent. This is a follow-up PR to #2549 by @ostwilkens and based on his work. ## Solution To mock `Time`, one needs to be able to manually update the Time resource with an `Instant` defined by the developer. This can be achieved by making the existing `Time::update_with_instant` method public for use in tests. ## Changelog - Make `Time::update_with_instant` public - Add doc to `Time::update_with_instant` clarifying that the method should not be called outside of tests. - Add doc test to `Time` demonstrating how to use `update_with_instant` in tests. Co-authored-by: Martin Dickopp <[email protected]>
# Objective To test systems that implement frame rate-independent update logic, one needs to be able to mock `Time`. By mocking time, it's possible to write tests that confirm systems are frame rate-independent. This is a follow-up PR to #2549 by @ostwilkens and based on his work. ## Solution To mock `Time`, one needs to be able to manually update the Time resource with an `Instant` defined by the developer. This can be achieved by making the existing `Time::update_with_instant` method public for use in tests. ## Changelog - Make `Time::update_with_instant` public - Add doc to `Time::update_with_instant` clarifying that the method should not be called outside of tests. - Add doc test to `Time` demonstrating how to use `update_with_instant` in tests. Co-authored-by: Martin Dickopp <[email protected]>
# Objective To test systems that implement frame rate-independent update logic, one needs to be able to mock `Time`. By mocking time, it's possible to write tests that confirm systems are frame rate-independent. This is a follow-up PR to #2549 by @ostwilkens and based on his work. ## Solution To mock `Time`, one needs to be able to manually update the Time resource with an `Instant` defined by the developer. This can be achieved by making the existing `Time::update_with_instant` method public for use in tests. ## Changelog - Make `Time::update_with_instant` public - Add doc to `Time::update_with_instant` clarifying that the method should not be called outside of tests. - Add doc test to `Time` demonstrating how to use `update_with_instant` in tests. Co-authored-by: Martin Dickopp <[email protected]>
…4469) # Objective To test systems that implement frame rate-independent update logic, one needs to be able to mock `Time`. By mocking time, it's possible to write tests that confirm systems are frame rate-independent. This is a follow-up PR to bevyengine#2549 by @ostwilkens and based on his work. ## Solution To mock `Time`, one needs to be able to manually update the Time resource with an `Instant` defined by the developer. This can be achieved by making the existing `Time::update_with_instant` method public for use in tests. ## Changelog - Make `Time::update_with_instant` public - Add doc to `Time::update_with_instant` clarifying that the method should not be called outside of tests. - Add doc test to `Time` demonstrating how to use `update_with_instant` in tests. Co-authored-by: Martin Dickopp <[email protected]>
…4469) # Objective To test systems that implement frame rate-independent update logic, one needs to be able to mock `Time`. By mocking time, it's possible to write tests that confirm systems are frame rate-independent. This is a follow-up PR to bevyengine#2549 by @ostwilkens and based on his work. ## Solution To mock `Time`, one needs to be able to manually update the Time resource with an `Instant` defined by the developer. This can be achieved by making the existing `Time::update_with_instant` method public for use in tests. ## Changelog - Make `Time::update_with_instant` public - Add doc to `Time::update_with_instant` clarifying that the method should not be called outside of tests. - Add doc test to `Time` demonstrating how to use `update_with_instant` in tests. Co-authored-by: Martin Dickopp <[email protected]> (cherry picked from commit 93cee3b)
…4469) # Objective To test systems that implement frame rate-independent update logic, one needs to be able to mock `Time`. By mocking time, it's possible to write tests that confirm systems are frame rate-independent. This is a follow-up PR to bevyengine#2549 by @ostwilkens and based on his work. ## Solution To mock `Time`, one needs to be able to manually update the Time resource with an `Instant` defined by the developer. This can be achieved by making the existing `Time::update_with_instant` method public for use in tests. ## Changelog - Make `Time::update_with_instant` public - Add doc to `Time::update_with_instant` clarifying that the method should not be called outside of tests. - Add doc test to `Time` demonstrating how to use `update_with_instant` in tests. Co-authored-by: Martin Dickopp <[email protected]>
Objective
A lot of systems depend on Time to implement frame-independent logic.
To be able to write tests for these systems, one needs to be able to mock Time. By mocking time, it's possible to write tests that confirm systems are frame-independent.
Solution
To mock Time, one needs to be able to manually update the Time resource with an Instant defined by the developer.
There is a function for this, but it's currently only public within the crate. I propose this function is exposed to the developer, to make it easy to write tests for systems utilizing the Time resource.