-
-
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
Add an example for doing movement in fixed timesteps #14223
Add an example for doing movement in fixed timesteps #14223
Conversation
As a follow-up (or in this PR), we should stop using fixed timestep in the breakout example, and use delta time instead. |
@alice-i-cecile I'll leave that for a follow-up if that's alright :) |
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 think this example is fine to be merged as it currently is, but it would be nice to see some future improvements:
- maybe have a toggle where we can turn on the interpolation and turn it off to see the difference (or even a split-screen view)
- maybe have an option to set or update the FixedTimeStep (so that we can see this helps the visuals in lower timestep than framerate, and higher timestep than framerate)
- in general i've noticed that this kind of interpolation becomes extremely important when the camera is set on the moving entity. In those cases the issue becomes every obvious because suddenly everything else (other entities) seems to be jittering. I might try to add this in a future PR. I've seen tons of questions on discord related to jittery cameras that could boil down to this
Why would we want to switch to delta-time? To be able to do 'partial-timesteps' using |
I generally agree with your suggestions and have also thought about that. Here are my thoughts:
All of this is follow-up work. |
Looks fine to me. From a quick read through the PR, I didn't see anything wrong with it. I don't want to give an opinionated review (about how the concept should be taught), because I like it when different people teach the same concepts in their own way. I have already taught this topic in Bevy Cheatbook the way I like to teach it (incl. with a discussion and comparison of interpolation vs. extrapolation). So I limit my review to checking for correctness. And correct it seems to be :) |
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.
lgtm
copy-pasted from my doc comment in the code
Objective
This example shows how to properly handle player input, advance a physics simulation in a fixed timestep, and display the results.
The classic source for how and why this is done is Glenn Fiedler's article Fix Your Timestep!.
Motivation
The naive way of moving a player is to just update their position like so:
The issue here is that the player's movement speed will be tied to the frame rate.
Faster machines will move the player faster, and slower machines will move the player slower.
In fact, you can observe this today when running some old games that did it this way on modern hardware!
The player will move at a breakneck pace.
The more sophisticated way is to update the player's position based on the time that has passed:
This way, velocity represents a speed in units per second, and the player will move at the same speed regardless of the frame rate.
However, this can still be problematic if the frame rate is very low or very high. If the frame rate is very low, the player will move in large jumps. This may lead to a player moving in such large jumps that they pass through walls or other obstacles. In general, you cannot expect a physics simulation to behave nicely with any delta time. Ideally, we want to have some stability in what kinds of delta times we feed into our physics simulation.
The solution is using a fixed timestep. This means that we advance the physics simulation by a fixed amount at a time. If the real time that passed between two frames is less than the fixed timestep, we simply don't advance the physics simulation at all.
If it is more, we advance the physics simulation multiple times until we catch up. You can read more about how Bevy implements this in the documentation for
bevy::time::Fixed
.This leaves us with a last problem, however. If our physics simulation may advance zero or multiple times per frame, there may be frames in which the player's position did not need to be updated at all, and some where it is updated by a large amount that resulted from running the physics simulation multiple times. This is physically correct, but visually jarring. Imagine a player moving in a straight line, but depending on the frame rate, they may sometimes advance by a large amount and sometimes not at all. Visually, we want the player to move smoothly. This is why we need to separate the player's position in the physics simulation from the player's position in the visual representation. The visual representation can then be interpolated smoothly based on the last and current actual player position in the physics simulation.
This is a tradeoff: every visual frame is now slightly lagging behind the actual physical frame, but in return, the player's movement will appear smooth. There are other ways to compute the visual representation of the player, such as extrapolation. See the documentation of the lightyear crate for a nice overview of the different methods and their tradeoffs.
Implementation
Velocity
component. This is the speed in units per second.PhysicalTranslation
component.PreviousPhysicalTranslation
component.Transform
component.advance_physics
system.This is run in the
FixedUpdate
schedule, which runs before theUpdate
schedule.update_displayed_transform
system.This interpolates between the player's previous and current position in the physics simulation.
handle_input
system.Relevant Issues
Related to #1259.
I'm also fairly sure I've seen an issue somewhere made by @alice-i-cecile about showing how to move a character correctly in a fixed timestep, but I cannot find it.