Replace fixed timestep in alien_cake_addict example with timer (#5760)

# Objective

Examples should use the correct tools for the job.

## Solution

A fixed timestep, by design, can step multiple times consecutively in a single update.

That property used to crash the `alien_cake_addict` example (#2525), which was "fixed" in #3411 (by just not panicking). The proper fix is to use a timer instead, since the system is supposed to spawn a cake every 5 seconds. 

---

A timer guarantees a minimum duration. A fixed timestep guarantees a fixed number of steps per second.
Each one works by essentially sacrificing the other's guarantee.

You can use them together, but no other systems are timestep-based in this example, so the timer is enough.
This commit is contained in:
Cameron 2022-09-30 11:37:33 +00:00
parent 6b8cc2652a
commit 6929d95f7f

View File

@ -2,7 +2,7 @@
use std::f32::consts::PI; use std::f32::consts::PI;
use bevy::{ecs::schedule::SystemSet, prelude::*, time::FixedTimestep}; use bevy::{ecs::schedule::SystemSet, prelude::*};
use rand::Rng; use rand::Rng;
#[derive(Clone, Eq, PartialEq, Debug, Hash)] #[derive(Clone, Eq, PartialEq, Debug, Hash)]
@ -11,9 +11,13 @@ enum GameState {
GameOver, GameOver,
} }
#[derive(Resource)]
struct BonusSpawnTimer(Timer);
fn main() { fn main() {
App::new() App::new()
.init_resource::<Game>() .init_resource::<Game>()
.insert_resource(BonusSpawnTimer(Timer::from_seconds(5.0, true)))
.add_plugins(DefaultPlugins) .add_plugins(DefaultPlugins)
.add_state(GameState::Playing) .add_state(GameState::Playing)
.add_startup_system(setup_cameras) .add_startup_system(setup_cameras)
@ -23,17 +27,13 @@ fn main() {
.with_system(move_player) .with_system(move_player)
.with_system(focus_camera) .with_system(focus_camera)
.with_system(rotate_bonus) .with_system(rotate_bonus)
.with_system(scoreboard_system), .with_system(scoreboard_system)
.with_system(spawn_bonus),
) )
.add_system_set(SystemSet::on_exit(GameState::Playing).with_system(teardown)) .add_system_set(SystemSet::on_exit(GameState::Playing).with_system(teardown))
.add_system_set(SystemSet::on_enter(GameState::GameOver).with_system(display_score)) .add_system_set(SystemSet::on_enter(GameState::GameOver).with_system(display_score))
.add_system_set(SystemSet::on_update(GameState::GameOver).with_system(gameover_keyboard)) .add_system_set(SystemSet::on_update(GameState::GameOver).with_system(gameover_keyboard))
.add_system_set(SystemSet::on_exit(GameState::GameOver).with_system(teardown)) .add_system_set(SystemSet::on_exit(GameState::GameOver).with_system(teardown))
.add_system_set(
SystemSet::new()
.with_run_criteria(FixedTimestep::step(5.0))
.with_system(spawn_bonus),
)
.add_system(bevy::window::close_on_esc) .add_system(bevy::window::close_on_esc)
.run(); .run();
} }
@ -291,13 +291,17 @@ fn focus_camera(
// despawn the bonus if there is one, then spawn a new one at a random location // despawn the bonus if there is one, then spawn a new one at a random location
fn spawn_bonus( fn spawn_bonus(
time: Res<Time>,
mut timer: ResMut<BonusSpawnTimer>,
mut state: ResMut<State<GameState>>, mut state: ResMut<State<GameState>>,
mut commands: Commands, mut commands: Commands,
mut game: ResMut<Game>, mut game: ResMut<Game>,
) { ) {
if *state.current() != GameState::Playing { // make sure we wait enough time before spawning the next cake
if !timer.0.tick(time.delta()).finished() {
return; return;
} }
if let Some(entity) = game.bonus.entity { if let Some(entity) = game.bonus.entity {
game.score -= 3; game.score -= 3;
commands.entity(entity).despawn_recursive(); commands.entity(entity).despawn_recursive();