Skip to content

State changes appear to have system order ambiguities #13947

@jonathandw743

Description

@jonathandw743

System Info

bevy 0.14.0-rc.2
Ubuntu 22.04

Program

use bevy::{
    input::{keyboard::KeyboardInput, mouse::MouseButtonInput, ButtonState},
    prelude::*,
};

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .insert_state(S1::A)
        .add_sub_state::<S2>()
        .add_systems(Update, transition_to_s1_b_on_click.run_if(in_state(S1::A)))
        .add_systems(Update, transition_to_s2_d_on_click.run_if(in_state(S2::C)))
        .add_systems(Update, info_states)
        .add_systems(Update, reset)
        .run();
}

fn transition_to_s1_b_on_click(
    mut mouse_events: EventReader<MouseButtonInput>,
    mut ns_s1: ResMut<NextState<S1>>,
) {
    for e in mouse_events.read() {
        match e {
            MouseButtonInput {
                button: MouseButton::Left,
                state: ButtonState::Pressed,
                ..
            } => ns_s1.set(S1::B),
            _ => {}
        }
    }
}

fn transition_to_s2_d_on_click(
    mut mouse_events: EventReader<MouseButtonInput>,
    mut ns_s2: ResMut<NextState<S2>>,
) {
    for e in mouse_events.read() {
        match e {
            MouseButtonInput {
                button: MouseButton::Left,
                state: ButtonState::Pressed,
                ..
            } => ns_s2.set(S2::D),
            _ => {}
        }
    }
}

fn info_states(s1: Res<State<S1>>, s2: Option<Res<State<S2>>>) {
    info!("{:?}, {:?}", s1, s2);
}

fn reset(keyboard_input: Res<ButtonInput<KeyCode>>, mut ns_s1: ResMut<NextState<S1>>) {
    if keyboard_input.just_pressed(KeyCode::Escape) {
        ns_s1.set(S1::A);
    }
}

#[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
enum S1 {
    A,
    B,
}

#[derive(SubStates, Debug, Clone, PartialEq, Eq, Hash, Default)]
#[source(S1 = S1::B)]
enum S2 {
    #[default]
    C,
    D,
}

Program summary:

state S1 is set to A
state S2 is a sub state of S1 and has a default value of C
when the mouse is pressed, S1 transitions to B

then sometimes, S2 also transitions to D

Output

I would expect the output to be:

2024-06-20T15:02:47.198639Z  INFO gam: Res(State(A)), None
2024-06-20T15:02:47.213971Z  INFO gam: Res(State(A)), None
2024-06-20T15:02:47.227818Z  INFO gam: Res(State(A)), None
<mouse pressed>
2024-06-20T15:02:47.254104Z  INFO gam: Res(State(B)), Some(Res(State(C)))
2024-06-20T15:02:47.267907Z  INFO gam: Res(State(B)), Some(Res(State(C)))
2024-06-20T15:02:47.280845Z  INFO gam: Res(State(B)), Some(Res(State(C)))

but occasionally (apparently at random) the output is:

2024-06-20T15:10:34.521087Z  INFO gam: Res(State(A)), None
2024-06-20T15:10:34.534237Z  INFO gam: Res(State(A)), None
2024-06-20T15:10:34.547726Z  INFO gam: Res(State(A)), None
<mouse pressed>
2024-06-20T15:10:34.560954Z  INFO gam: Res(State(B)), Some(Res(State(C)))
2024-06-20T15:10:34.587293Z  INFO gam: Res(State(B)), Some(Res(State(D)))
2024-06-20T15:10:34.601005Z  INFO gam: Res(State(B)), Some(Res(State(D)))
2024-06-20T15:10:34.613692Z  INFO gam: Res(State(B)), Some(Res(State(D)))

("" is not logged)

(this is not a double press or anything like that, it happens consistently)

My guess about what is happening in the expected output and why

The mouse click event happens and is in the first EventReader.
The state then changes to S1::B
The mouse click event leaves the EventReader
The transition_to_s2_d_on_click system runs
The mouse click event is no longer in the EventReader
The state does not change

My guess about what is happening in the unexpected output and why

The mouse click event happens and is in the first EventReader.
The state then changes to S1::B
The transition_to_s2_d_on_click system runs
The mouse click event is still in the EventReader
The state changes to S2::D

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ECSEntities, components, systems, and eventsA-StatesApp-level states machinesC-BugAn unexpected or incorrect behaviorD-ComplexQuite challenging from either a design or technical perspective. Ask for help!S-Needs-DesignThis issue requires design work to think about how it would best be accomplished

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions