BebyではFixedTimestep::step(timestep)
で実行間隔を調整することができます。
ですが、この動作はある条件下では現在(Version 0.7)機能しなくなるバグがあり、私もかなりの足止めを食らいました。
同じ過ちを犯さないためにも起こっている問題と解決案について掲載します。
環境
Bevy: 0.7
問題のバグ
サンプルコード
use bevy::{core::FixedTimestep, prelude::*};
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
enum GlobalState {
FirstState,
SecondState,
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
// Init state
.add_state(GlobalState::FirstState)
// First state systems
.add_system_set(
SystemSet::on_enter(GlobalState::FirstState)
.with_system(first_state::enter_system)
.with_run_criteria(FixedTimestep::step(1.0)),
)
.add_system_set(
SystemSet::on_update(GlobalState::FirstState)
.with_system(first_state::update_system)
.with_run_criteria(FixedTimestep::step(1.0)),
)
// Second state systems
.add_system_set(
SystemSet::on_enter(GlobalState::SecondState)
.with_system(second_state::enter_system)
.with_run_criteria(FixedTimestep::step(1.0)),
)
.add_system_set(
SystemSet::on_update(GlobalState::SecondState)
.with_system(second_state::update_system)
.with_run_criteria(FixedTimestep::step(1.0)),
)
.run()
}
mod first_state {
pub fn enter_system() {
println!("First state: Enter");
}
pub fn update_system() {
println!("First state: Update");
}
}
mod second_state {
pub fn enter_system() {
println!("Second state: Enter");
}
pub fn update_system() {
println!("Second state: Update");
}
}
結果
> 理想
First state: Enter
First state: Update
...
First state: Update
> 現実
Second state: Update
First state: Enter
First state: Update
Second state: Enter
Second state: Update
First state: Enter
First state: Update
Second state: Enter
Second state: Update
First state: Enter
Second state: Enter
First state: Update
Second state: Update
First state: Enter
Second state: Enter
First state: Update
Issueでは開発者はこのバグを「致命的なバグ」と言っているので、バージョンアップの際に解決されると思います。
0.7では解決されてなかったけど...
解決案
Version 0.7
fn playing_timestep_system_set(timestep: f64) -> SystemSet {
SystemSet::new().with_run_criteria(
FixedTimestep::step(timestep).chain(
(|In(input): In<ShouldRun>, state: Res<State<GameState>>| {
if state.current() == &GameState::Playing {
input
} else {
ShouldRun::No
}
})
.to_owned(),
),
)
}
もしVersion 0.6
を使用するという場合は.to_owned()
を.sysytem()
に変更してください