System Order of Execution

Bevy's scheduling algorithm is designed to deliver maximum performance by running as many systems as possible in parallel across the available CPU threads.

This is possible when the systems do not conflict over the data they need to access. However, when a system needs to have mutable (exclusive) access to a piece of data, other systems that need to access the same data cannot be run at the same time. Bevy determines all of this information from the system's function signature (the types of the parameters it takes).

In such situations, the order is nondeterministic by default. Bevy takes no regard for when each system will run, and the order could even change every frame!

Explicit System Ordering

If a specific system must always run before or after some other systems, you can add ordering constraints:

fn main() {
let mut app = App::new();
app.add_systems(Update, (
    enemy_movement,
    input_handling,

    player_movement
        // `player_movement` must always run before `enemy_movement`
        .before(enemy_movement)
        // `player_movement` must always run after `input_handling`
        .after(input_handling),

    // order doesn't matter for some systems:
    particle_effects,
    npc_behaviors,

    // we can apply ordering to multiple systems at once:
    (
        spawn_monsters,
        spawn_zombies,
        spawn_spiders,
    ).before(enemy_movement),

    // to run a sequence of systems in order, use `.chain()`
    // (this is just syntax sugar to automatically add
    // before/after dependencies between the systems in the tuple)
    (
        spawn_particles,
        animate_particles,
        debug_particle_statistics,
    ).chain()
));

When you have a lot of systems that you need to configure, it can start to get unwieldy. Consider using system sets to organize and manage your systems.

Does it even matter?

In many cases, you don't need to worry about this.

However, sometimes you need to rely on specific systems to run in a particular order. For example:

  • Maybe the logic you wrote in one of your systems needs any modifications done to that data by another system to always happen first?
  • One system needs to receive events sent by another system.
  • You are using change detection.

In such situations, systems running in the wrong order typically causes their behavior to be delayed until the next frame. In rare cases, depending on your game logic, it may even result in more serious logic bugs!

It is up to you to decide if this is important.

With many things in typical games, such as juicy visual effects, it probably doesn't matter if they get delayed by a frame. It might not be worthwhile to bother with it. If you don't care, leaving the order ambiguous may also result in better performance.

On the other hand, for things like handling the player input controls, this would result in annoying lag or worse, so you should probably fix it.

Circular Dependencies

If you have multiple systems mutually depending on each other, then it is clearly impossible to resolve the situation completely like that.

You should try to redesign your game to avoid such situations, or just accept the consequences. You can at least make it behave predictably, using explicit ordering to specify the order you prefer.