bevy
bevy copied to clipboard
FixedTimeStep systems do not honor their associated app state
Bevy version
0.10
What you did
Consider the following Bevy app:
use bevy::prelude::*;
#[derive(States, PartialEq, Eq, Debug, Default, Hash, Clone, Copy)]
enum AppState {
#[default]
First,
Second,
}
fn main() {
App::new()
.add_plugins(MinimalPlugins)
.insert_resource(FixedTime::new_from_secs(1.0))
.add_state::<AppState>()
.add_system(transition_state.in_set(OnUpdate(AppState::First)))
.add_system(
print_hello
.in_schedule(CoreSchedule::FixedUpdate)
.in_set(OnUpdate(AppState::Second)),
)
.run();
}
fn transition_state(time: Res<Time>, mut next_state: ResMut<NextState<AppState>>) {
if time.elapsed_seconds() > 3.0 {
println!("Transition state!");
next_state.set(AppState::Second);
}
}
fn print_hello() {
println!("Hello!");
}
What went wrong
The print_hello system runs regardless of the application state. It should only run in the AppState::Second state but it runs also in the AppState::First state.
The following output is generated:
Hello!
Hello!
Transition state!
Hello!
Hello!
If line the line with .in_schedule(CoreSchedule::FixedUpdate) is commented out, the output is:
Transition state!
Hello!
Hello!
Hello!
It's as expected. But of course the system is now run every frame.
Does this work if you use a .run_if(in_state(AppState::Second)) instead? OnUpdate was really only ever intended for the main schedule.
Does this work if you use a
.run_if(in_state(AppState::Second))instead?
Yes, then it works. Thanks!
@alice-i-cecile I'm trying to run a set of systems only when the game is in a certain state, and with a fixed timestep.
First I tried this:
app.add_systems(
(
system_a,
system_b,
system_c,
)
.in_set(labels::Lobby)
.after(labels::Network)
.in_set(OnUpdate(GameState::Lobby))
.in_schedule(CoreSchedule::FixedUpdate)
)
which led me to this issue.
Then I tried
app.add_systems(
(
system_a,
system_b,
system_c,
)
.in_set(labels::Lobby)
.after(labels::Network)
.run_if(in_state(GameState::Lobby))
.in_schedule(CoreSchedule::FixedUpdate)
)
Which gave me some unsatisfied trait bounds:
358 | pub struct SystemConfigs {
| ------------------------
| |
| doesn't satisfy `SystemConfigs: IntoSystem<(), (), _>`
| doesn't satisfy `SystemConfigs: IntoSystemConfig<_>`
|
= note: the following trait bounds were not satisfied:
`SystemConfigs: IntoSystem<(), (), _>`
which is required by `SystemConfigs: IntoSystemConfig<_>`
`&SystemConfigs: IntoSystem<(), (), _>`
which is required by `&SystemConfigs: IntoSystemConfig<_>`
`&mut SystemConfigs: IntoSystem<(), (), _>`
which is required by `&mut SystemConfigs: IntoSystemConfig<_>`
I found distributive_run_if() and tried that:
app.add_systems(
(
system_a,
system_b,
system_c,
)
.in_set(labels::Lobby)
.after(labels::Network)
.distributive_run_if(in_state(GameState::Lobby))
.in_schedule(CoreSchedule::FixedUpdate)
)
which gave:
error[E0277]: the trait bound `impl for<'a> FnMut(Res<'a, State<GameState>>) -> bool: Clone` is not satisfied
--> server/src/systems/lobby.rs:59:38
|
59 | .distributive_run_if(in_state(GameState::Lobby))
| ------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `impl for<'a> FnMut(Res<'a, State<GameState>>) -> bool`
| |
| required by a bound introduced by this call
|
note: required by a bound in `distributive_run_if`
--> /Users/brian/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.10.0/src/schedule/config.rs:425:68
|
425 | fn distributive_run_if<M>(self, condition: impl Condition<M> + Clone) -> SystemConfigs {
| ^^^^^ required by this bound in `distributive_run_if`
help: use parentheses to call this opaque type
|
59 | .distributive_run_if(in_state(GameState::Lobby)(/* Res<'_, State<GameState>> */))
| +++++++++++++++++++++++++++++++++
For more information about this error, try `rustc --explain E0277`.
error: could not compile `sus-server` due to previous error
At this point I'm not sure of the best way to specify that a set of systems should run on a fixed timestep, and only while in a certain state.
If the answer is currently "add the run_if condition on every system in the set", that's totally fine. Just wanted to make sure I wasn't missing something else that'll solve the problem.
Thanks so much for your work on the new stageless API, it's been really cool to see my bevy code shrink in size while remaining functionally the same (along with gaining new ergonomics!)
@bschwind There is an issue about that https://github.com/bevyengine/bevy/issues/8058. Before it fixed, you can use:
distributive_run_if(|state: Res<State<GameState>>>| *state == GameState::Lobby)
@st0rmbtw nice! I changed *state to state.0 and it worked perfectly.
@alice-i-cecile can this be closed now that https://github.com/bevyengine/bevy/pull/8260 has been merged?