-
-
Notifications
You must be signed in to change notification settings - Fork 120
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
Use FixedPostUpdate
by default and simplify scheduling
#457
Conversation
I think <Fixed> is missing. app.insert_resource(Time::<Fixed>::from_hz(60.0))); |
That's optional since it's inferred, but I added it to the description for clarity. |
Wouldn't this insert the resource |
No, If you did have multiple different clocks with |
ooo okay. I had assumed |
If you haven't merged this by then, I'll review it after the jam :) |
Why FixedUpdate instead of FixedPostUpdate for physics? |
FixedUpdate
by default and simplify schedulingFixedPostUpdate
by default and simplify scheduling
I responded on Discord already, but we discussed this briefly a few days ago, and came to the conclusion that |
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
Objective
Closes #263 (the removal detection issue should also already be fixed thanks to hooks and observers)
So far, Avian has run in
PostUpdate
by default, but with a custom fixed timestep solution. This has given us more control over scheduling and allowed working around some historical issues with Bevy's ownFixedUpdate
, but nowadays Bevy's fixed timestep schedules are much more usable.Having two different fixed timesteps is confusing, annoying to maintain, and duplicates a lot of API surface area. The scheduling in Avian 0.1 also has other serious issues:
PostUpdate
, even with the built-in fixed timestep.For a native experience, Avian should be using Bevy's own fixed timestep and scheduling.
Solution
Physics now runs in
FixedPostUpdate
by default.TimestepMode
has been removed, andTime<Physics>
no longer has a custom timestep. Instead, it follows the clock of the schedule where physics is run in. InFixedPostUpdate
, physics usesTime<Fixed>
, but if physics is instead configured to run in a schedule likePostUpdate
, it will useTime<Virtual>
.Previously, the physics timestep could be configured like this:
In schedules with a fixed timestep, you even needed to use
fixed_once_hz
, which was rather confusing and footgunny:Now, if you are running physics in
FixedPostUpdate
, you should simply configureTime<Fixed>
directly:Time<Physics>
still exists to allow people to configure the simulation speed, pause and unpause the simulation independently of the schedule's default clock, and set up their own custom scheduling for physics.Running physics with Bevy's fixed timestep has also fixed the other issues mentioned earlier: physics no longer runs slower at lower frame rates, and behavior seems a lot more deterministic (at least without the
parallel
feature). More testing is required to determine if we have full cross-platform determinism though.Why
FixedPostUpdate
instead ofFixedUpdate
?FixedUpdate
is very often used for gameplay logic and various kinds of simulations. It is also commonly used for applying physics logic, like character movement, explosions, moving platforms, effects that apply forces/impulses, custom gravity, and so on.For a lot of these use cases, it is important to run logic before physics, and if physics was run in
FixedUpdate
, systems would need to be ordered explicitly, which would not be a good experience. And if you didn't do that, you could get determinism issues caused by system ordering ambiguities, along with frame delay issues.And as for
FixedPreUpdate
: if we ran physics before gameplay logic inFixedUpdate
, movement and anything else that affects physics could have an additional delay of one or more frames.I believe that using
FixedPostUpdate
is the sensible default, and it is also in line with engines like Unity and Godot, where internal physics is run near the end of the fixed update/process step. People can also always configure the ordering in their own applications if needed.Caveats
Bevy's fixed timestep is 64 Hz by default, unlike our old default of 60 Hz. This can lead to noticeable jitter on 60 Hz displays, as physics is sometimes run twice within a single frame. This can be partially worked around by configuring
Time<Fixed>
, but I am also implementing transform interpolation and extrapolation, which should make it possible to fix the issue properly by smoothing out the visual result.Another change to the old scheduling is that physics no longer runs during the first frame. This is because Bevy's
FixedUpdate
and other fixed timestep schedules don't seem to run until the second update.Migration Guide
Previously, physics was run in
PostUpdate
with a custom fixed timestep by default. The primary purpose of the fixed timestep is to make behavior consistent and frame rate independent.This custom scheduling logic has been removed, and physics now runs in Bevy's
FixedFixedUpdate
by default. This further unifies physics with Bevy's own APIs and simplifies scheduling. However, it also means that physics now runs beforeUpdate
, unlike before.For most users, no changes should be necessary, and systems that were running in
Update
can remain there. If you want to run systems at the same fixed timestep as physics, consider usingFixedUpdate
.The
Time<Physics>
clock now automatically follows the clock used by the schedule that physics is run in. InFixedPostUpdate
and other schedules with a fixed timestep,Time<Fixed>
is used, but if physics is instead configured to run in a schedule likePostUpdate
, it will useTime<Virtual>
.Previously, the physics timestep could be configured like this:
Now, if you are running physics in
FixedPostUpdate
, you should simply configureTime<Fixed>
directly:The following types and methods have also been removed as a part of this rework:
TimestepMode
Physics::from_timestep
Physics::fixed_hz
Physics::fixed_once_hz
Physics::variable
Time::<Physics>::from_timestep
Time::<Physics>::timestep_mode
Time::<Physics>::timestep_mode_mut
Time::<Physics>::set_timestep_mode