bevyengine / bevyengine/bevy

Unexpected behavior using `States` and `Event`s

Open
#18,428 1 comment 0 reactions 0 assignees View on GitHub
A-ECS A-States C-Bug S-Needs-Investigation
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 16h
Merged PRs (30d)
171

Description

## Bevy version

0.15.3

## What you did

```
use bevy::prelude::*;

#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash, States)]
pub enum Phases {
#[default]
None,
Phase1,
Phase2,
}

#[derive(Event, Debug, Default)]
pub struct AnEvent;

#[derive(Resource, Debug)]
struct ChangeDirectionTimer {
timer: Timer,
}

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.init_state::()
.add_event::()
.insert_resource(ChangeDirectionTimer {
timer: Timer::from_seconds(1., TimerMode::Once),
})
.add_systems(Startup, start)
.add_systems(OnEnter(Phases::Phase1), send_event1)
.add_systems(Update, end_phase1
.run_if(in_state(Phases::Phase1).and(on_event::)))
.add_systems(OnEnter(Phases::Phase2), send_event2)
.add_systems(Update, end_phase2
.run_if(in_state(Phases::Phase2).and(on_event::)))
.run();
}

fn start(mut next_state: ResMut>) {
next_state.set(Phases::Phase1);
}

fn send_event1(
mut event: EventWriter,
) {
println!("Sending event 1");
event.send_default();
}

fn end_phase1(
mut event: EventReader,
mut next_state: ResMut>,
) {
for _ in event.read() {
println!("Ending phase 1");
next_state.set(Phases::Phase2);
}
}

fn send_event2(
mut event: EventWriter,
time: Res

fn end_phase2(
mut event: EventReader,
mut next_state: ResMut>,
) {
for _ in event.read() {
println!("Ending phase 2");
next_state.set(Phases::None);
}
}
```

## What went wrong

The output of this code is:
```
Sending event 1
Ending phase 1
Ending phase 2
```
As the system `end_phase2` only runs in the `Phase2` state, it should be triggered by the delayed event 2, but it's like it is triggered still by the first event.

This is confirmed by commenting out the `if` statement in `send_event2`, which results in:
```
Sending event 1
Ending phase 1
Sending event 2
Ending phase 2
Ending phase 2
```
So `end_phase2` is actually triggered twice despite the first event is triggered in another state with respect to the one during which `end_phase2` should be running.

## Additional information

Am I missing something or is it a bug?

Thanks!

Contributor guide

Open the contributing guide

Research direction

Start by running the complete Rust reproduction from the issue and compare the scheduling of send_event1, end_phase1, send_event2, and end_phase2 across the Phases states. Trace how on_event:: and EventReader handle events during state transitions; done means determining whether the observed Phase2 runs are expected and adding a focused regression test or documenting the cause.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
game-dev
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.