Skip to content

Update/FixedUpdate are not clear in what systems should go in what schedule. #24494

@andriyDev

Description

@andriyDev

Background

Update and FixedUpdate are both common methods for updating games: Update runs once per frame, sometimes even as fast as possible, whereas FixedUpdate runs at a consistent tick rate (say 60Hz). Both of these have their pros and cons.

Update

Pros: Always in sync with rendering. Reacts to input as quickly as possible.
Cons: Your game may be framerate dependent - a particularly long frame can increase the delta time, even potentially allowing objects to clip through walls! Networking!

FixedUpdate

Pros: Consistent delta times. Physics will always be the same, so no going through walls no matter how long a frame is.
Cons: Delta-time-death-spiral (a fixed frame takes so long that the game perpetually has to catch up). You need to somehow sync up the rendering with the fixed intervals (otherwise your game will look low FPS even if you have 8000 FPS).

Why use a FixedUpdate?

A very common reason is for networking. Networking often needs determinism to allow the clients to correctly predict what will happen on the server, and part of that includes knowing how long to simulate a given frame for. Since each client has a different computer, it's infeasible to just handle all of these independently. Using a fixed frame allows all clients to agree on what "tick" of the game world they are simulating, allowing for agreement (or reconciliation when there's a desync).

Another example is for replays (e.g., for demos). In order to replay the state of a world after a set of inputs you need to know how long each input needs to be applied for. This is in parallel with the delta times that the replay client is receiving. By using a fixed update, you just need to replay the inputs for tick N and everything will run exactly the same (assuming your simulation is deterministic).

Ideally users should be writing their games by default to make it easy to adopt these features.

What's wrong with Update/FixedUpdate?

TL;DR Unity.

We're borrowing this terminology from Unity, and Unity has taught users "when you're doing physics stuff, use FixedUpdate". That is not wrong, but what is wrong is following that up with "everything else goes in Update". That is absolutely not true. Even if people don't follow it up that way, saying "physics in FixedUpdate" does suggest "not physics in Update". This leads to users putting the wrong things in Update that should be in FixedUpdate, resulting in less reliable game simulations.

Obviously, Unity is also much larger than Bevy, so when people search "update vs fixed update", they're going to stumble upon a lot of Unity answers talking about "physics in FixedUpdate". IMO this has "poisoned the well" in terms of details on the subject, making any Bevy authoritative sources on the topic difficult to find. This also means that Unity devs switching to Bevy may bring their wrong understandings over to Bevy directly. To some degree this will happen regardless, but giving it a different name may help users get a better understanding of what FixedUpdate is useful/important for.

To be clear, this is not just a Unity problem: Godot has the exact same problem, but even worse. _process vs _physics_process really drills in that only physics stuff should go into _physics_process - even though I would argue this is wrong. And for me, the top search results for Unity and Godot's update loops are all forum answers rather than their authoritative docs, which don't even say much on the topic.

So what should go in FixedUpdate?

"Physics in FixedUpdate" is correct advice, but it's also incomplete. There's so much more that should go into FixedUpdate.

In my opinion, the game world should be thought of as a simulation. Anything that affects the simulation should go into FixedUpdate. This obviously includes physics stuff, since obviously physics affect where certain objects move to. However this also includes other things. For example, if a player can cast spells, then casting that spell should take effect in FixedUpdate. Similarly the cooldown for that spell should be ticked inside FixedUpdate. This ensures that in networking situations, these values can be simulated correctly on clients to remain in sync, since they don't rely on your frame rate, only the individual ticks (in fact you can just say "I cast this spell on tick 1337" since ticks are equally spaced).

Conversely, what should go in Update? Anything to do with IO: e.g., reading network messages, handling user input (sorta), and most importantly updating the visuals (rendering is a kind of O). Handling user input is sorta in a grey area: user input should be "accepted" in Update, but its effects should be applied in FixedUpdate since most user input affects the game simulation. Of course even this has exceptions: the camera in an RTS doesn't affect the simulation, and neither does clicking on the UI to select a building to place and moving around that "ghost" (transparent outline of your new building).

Do I have to use FixedUpdate?

No. It can be totally valid to just use Update, but this should be a conscious choice with an understanding that this may affect how easy it is to implement multiplayer features. Users should also be aware of the frame-rate dependence they may be susceptible to.

What do we do?

We rename Update and/or FixedUpdate! This would get us away from Unity's naming, which provides a pathway for users to learn the difference. So rather than users searching "update vs fixed update" and getting a bunch of Unity results, they search "??? vs ???" and get our results which hopefully better covers the nuance.

Some proposals to rename Update: RenderUpdate, FrameUpdate, Frame, VisualUpdate. VariableUpdate, IoUpdate.
Some proposals to rename FixedUpdate: SimulationUpdate, SimUpdate, Simulate.

Proposal

After some discussion, the result we landed on was to keep Update, but rename FixedUpdate to Simulate.

Pros:

  • Both names have the same "weight". With Update vs FixedUpdate, Update seems like the "default" option, with FixedUpdate being the "specialized" option for special cases. Renaming the latter to Simulate makes it sound more even and less like one is the default.
  • Simulate gives a good intuition that updates should be treated as steps of a simulation. This framing makes it much more intuitive (at least to me) to decide which schedule systems should go into.
  • Our docs on this (once we write some) are much more likely to come up in a search for "update vs simulate".

Cons/Arguments against (many of these were distilled from a length Discord discussion:

  • We are breaking the mold here. Unity and Godot already have a "update vs physics" split.
    • ECS itself breaks the mold! Let's not restrict ourselves to the status quo, especially since the status quo is actively unhelpful.
  • FixedUpdate is accurate, so we shouldn't change it.
    • Again, Unity has poisoned the well here. That's unfortunate, but that's the reality we live in. Sticking with Unity's naming is just likely to add to the confusion.
  • Bevy is naturally modular and runs in many modes. Naming FixedUpdate might result in situations where this name makes less sense (e.g., headless, non-game app).
    • Sure, but our primary use case is certainly games. I don't think we should optimize for these other use cases if that distinction hurts our ability to communicate the intent to users.
  • Can't we just write a doc in the Bevy Book to explain this?
    • As evidenced by searching "update vs fixed update" or "_process vs _physics_process", the top results are from forums with users talking about it saying "physics in fixed update". Part of this problem is bad docs from Unity/Godot on the topic, but also it's clear that these search terms are already saturated (and with engines that are more popular frankly). So I don't think a doc is sufficient - but it is necessary.
  • This is too "prescriptive". Doing simulation in Update isn't "wrong" necessarily, and for some games that can be desirable.
    • Personally I think we should be prescriptive (to a degree). Telling users how to make a stable, performant, reliable game should be our goal, and we should design our tools to make that easy and intuitive. I do agree that doing simulation stuff in Update can make sense for some games, but again A) this should be a conscious decision to not use FixedUpdate, B) I am skeptical of a game that does core simulation and also mixes in some FixedUpdate, it should probably be either all in Update or follow the description above, and C) we should write our doc on this topic with enough softness to tell users "hey you don't have to do this, but here's why we don't recommend it - break that at your own peril".

Finally, just to really clarify: we should write a doc on this. Getting users to think about determinism/framerate-independence, explaining why it's important, and most importantly please oh goodness, stop saying physics in FixedUpdate.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ECSEntities, components, systems, and eventsC-DocsAn addition or correction to our documentationC-RefinementImproves output quality, without fixing a clear bug or adding new functionality.D-ModestA "normal" level of difficulty; suitable for simple features or challenging fixesS-Needs-ReviewNeeds reviewer attention (from anyone!) to move forwardX-ContentiousThere are nontrivial implications that should be thought through

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status

    Needs SME Triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions