Skip to content

Commit

Permalink
Introducing Game State with iyes_loopless
Browse files Browse the repository at this point in the history
The Snake game is fairly playable now. It’s recognizable as Snake in any case.

We still don’t have any way to end the game or restart the game once it ends.

To do that we’re going to introduce game states.

In `lib.rs` we can create a new enum to represent the states we could be in. We’ll have one for the main menu and one for playing the game.

```rust
enum GameState {
    Menu,
    Playing,
}
```

Then in `main.rs` we’ll insert the `Playing` state.

```rust
.add_loopless_state(GameState::Playing)
```

To show off how game states can help us, we’ll update the `tick` system to only run in the `Playing` state.

The `run_in_state` function comes from iyes_loopless and is called on the system function itself.

```rust
.add_stage_before(
    CoreStage::Update,
    "snake_tick",
    FixedTimestepStage::new(Duration::from_millis(
        100,
    ))
    .with_stage(
        SystemStage::parallel().with_system(
            tick.run_in_state(GameState::Playing),
        ),
    ),
)
```

Now, if we run the game the snake should still respond to our movement and eat apples, etc.

If we change the `add_loopless_state` function to insert `GameState::Menu` instead, our snake won’t move because the `tick` system won’t be running!

This is how we’ll switch back and forth between the game running and the menu system after a game over.

We can also apply this to any of the other systems we have running. In our `FoodPlugin`, bring `use iyes_loopless::prelude::*;` and `crate::GameState` into scope, then apply `run_in_state` to `food_event_listener`.

```rust
impl Plugin for FoodPlugin {
    fn build(&self, app: &mut App) {
        app.add_event::<NewFoodEvent>().add_system(
            food_event_listener
                .run_in_state(GameState::Playing),
        );
    }
}
```

and `ControlsPlugin`

```rust
impl Plugin for ControlsPlugin {
    fn build(&self, app: &mut App) {
        app.init_resource::<Direction>().add_system(
            user_input.run_in_state(GameState::Playing),
        );
    }
}
```
  • Loading branch information
ChristopherBiscardi committed Apr 22, 2022
1 parent 6075508 commit 5656499
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 6 deletions.
7 changes: 5 additions & 2 deletions src/controls.rs
@@ -1,11 +1,14 @@
use crate::GameState;
use bevy::prelude::*;
use iyes_loopless::prelude::*;

pub struct ControlsPlugin;

impl Plugin for ControlsPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<Direction>()
.add_system(user_input);
app.init_resource::<Direction>().add_system(
user_input.run_in_state(GameState::Playing),
);
}
}

Expand Down
8 changes: 6 additions & 2 deletions src/food.rs
@@ -1,18 +1,22 @@
use bevy::prelude::*;
use itertools::Itertools;
use iyes_loopless::prelude::*;
use rand::prelude::SliceRandom;

use crate::{
board::{Board, Position, SpawnApple},
snake::Snake,
GameState,
};

pub struct FoodPlugin;

impl Plugin for FoodPlugin {
fn build(&self, app: &mut App) {
app.add_event::<NewFoodEvent>()
.add_system(food_event_listener);
app.add_event::<NewFoodEvent>().add_system(
food_event_listener
.run_in_state(GameState::Playing),
);
}
}
pub struct NewFoodEvent;
Expand Down
6 changes: 6 additions & 0 deletions src/lib.rs
Expand Up @@ -9,6 +9,12 @@ pub mod controls;
pub mod food;
pub mod snake;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum GameState {
Menu,
Playing,
}

pub fn tick(
mut commands: Commands,
mut snake: ResMut<Snake>,
Expand Down
7 changes: 5 additions & 2 deletions src/main.rs
Expand Up @@ -2,7 +2,7 @@ use bevy::prelude::*;
use iyes_loopless::prelude::*;
use snake::{
board::spawn_board, controls::ControlsPlugin,
food::FoodPlugin, snake::Snake, tick,
food::FoodPlugin, snake::Snake, tick, GameState,
};
use std::time::Duration;

Expand All @@ -19,6 +19,7 @@ fn main() {
0.52, 0.73, 0.17,
)))
.init_resource::<Snake>()
.add_loopless_state(GameState::Playing)
.add_startup_system(setup)
.add_startup_system(spawn_board)
.add_stage_before(
Expand All @@ -28,7 +29,9 @@ fn main() {
100,
))
.with_stage(
SystemStage::parallel().with_system(tick),
SystemStage::parallel().with_system(
tick.run_in_state(GameState::Playing),
),
),
)
.run();
Expand Down

0 comments on commit 5656499

Please sign in to comment.