Skip to content

Setting Run Criteria for State-based System Set Overwrites System Set State Run Critera #1839

@zicklag

Description

@zicklag

Bevy version

97d8e4e

Operating system & version

Pop!_OS ( Ubuntu ) 20.04

What you did

Here's a full example with working and not working:

use bevy::{app::AppExit, core::FixedTimestep, prelude::*};

#[derive(PartialEq, Eq, Hash, Clone, Debug)]
enum GameState {
    Loading,
    Running,
}

fn main() {
    // working();
    not_working()
}

fn working() {
    println!("Working example:");
    App::build()
        .add_plugins(DefaultPlugins)
        .add_state(GameState::Loading)
        .add_system_set(
            SystemSet::on_update(GameState::Loading)
                // Wait for game to load
                .with_system(
                    (|mut counter: Local<usize>, mut state: ResMut<State<GameState>>| {
                        println!("Loading: {}/100", *counter);
                        if *counter == 100 {
                            state.push(GameState::Running).unwrap();
                        }

                        *counter += 1;
                    })
                    .system(),
                ),
        )
        .add_system_set(
            SystemSet::on_update(GameState::Running)
                // Run the game ( which just exits the program )
                .with_system(
                    (|mut exit_events: EventWriter<AppExit>| {
                        println!("running");
                        exit_events.send(AppExit);
                    })
                    .system(),
                ),
        )
        .run();
}

fn not_working() {
    println!("Not working example:");
    App::build()
        .add_plugins(DefaultPlugins)
        .add_state(GameState::Loading)
        .add_system_set(
            SystemSet::on_update(GameState::Loading)
                // Wait for game to load
                .with_system(
                    (|mut counter: Local<usize>, mut state: ResMut<State<GameState>>| {
                        println!("Loading: {}/100", *counter);
                        if *counter == 100 {
                            state.push(GameState::Running).unwrap();
                        }

                        *counter += 1;
                    })
                    .system(),
                ),
        )
        .add_system_set(
            SystemSet::on_update(GameState::Running)
                .with_run_criteria(FixedTimestep::step(0.001))
                // Run the game ( which just exits the program )
                .with_system(
                    (|mut exit_events: EventWriter<AppExit>| {
                        println!("running");
                        exit_events.send(AppExit);
                    })
                    .system(),
                ),
        )
        .run();
}

It appears that the with_run_criteria is overwriting the run criteria of the SystemSet that is supposed to run it only when the GameState::Running state is active.

What you expected to happen

Both the working and the not working examples should run the same, with all the assets being loaded before the program exits.

What actually happened

The working output is as expected, all "assets" are loaded before game goes into running state and send the exit event:

Working example:
Loading: 0/100
Loading: 1/100
Loading: 2/100
Loading: 3/100
Loading: 4/100
...
Loading: 97/100
Loading: 98/100
Loading: 99/100
Loading: 100/100
running

The not working output though will run the game system that exits the program before all the assets have finished loading and the state transition is made:

Not working example:
Loading: 0/100
Loading: 1/100
Loading: 2/100
Loading: 3/100
running

Extra Context

Here's my current workaround to combine the fixed timestep run criteria with the game state run criteria:

.add_system_set(
            SystemSet::new()
                .with_run_criteria(
                    FixedTimestep::step(0.001).chain(
                        (|In(input): In<ShouldRun>, state: Res<State<GameState>>| {
                            if state.current() == &GameState::Running {
                                input
                            } else {
                                ShouldRun::No
                            }
                        })
                        .system(),
                    ),
                )
                // Wait for game to load
                .with_system(
                    (|mut exit_events: EventWriter<AppExit>| {
                        println!("running");
                        exit_events.send(AppExit);
                    })
                    .system(),
                ),
        )

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ECSEntities, components, systems, and eventsC-BugAn unexpected or incorrect behavior

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions