Ideally when we click the “New Game” button it will start a new game.
Inside of ui.rs
in our event handler, we don’t have access to Commands
so we can use the context argument to get a mutable reference to the world instead, which will let us insert_resource
with the state we want to move to.
In this case, we want to move into the Playing
state to start the game.
let on_click_new_game =
OnEvent::new(|ctx, event| match event.event_type {
EventType::Click(..) => {
let mut world =
ctx.get_global_mut::<World>().unwrap();
world.insert_resource(NextState(
GameState::Playing,
));
}
_ => {}
});
This works, at least for getting into the Playing
state. There’s still a bug where when we hit “New Game” a second time, it throws us into the old game.
We need a way to reset the game when we transition into the Playing state.
In lib.rs
we can create a game_reset
system.
pub fn reset_game(
mut commands: Commands,
mut snake: ResMut<Snake>,
positions: Query<Entity, With<Position>>,
mut last_pressed: ResMut<controls::Direction>,
mut food_events: EventWriter<NewFoodEvent>,
) {
for entity in positions.iter() {
commands.entity(entity).despawn_recursive();
}
food_events.send(NewFoodEvent);
*snake = Default::default();
*last_pressed = Default::default();
}
The game reset system removes the snake and the apples from the board, sends a new food event, resets the snake, and resets the last user input entered.
Removing any Entity
that has a Position
component will remove all snake segments and all apples. We can do this with the entity id and calling despawn_recursive
to make sure we remove everything.
The snake
and last_pressed
variables already know what type they contain, so we can use Default::default
to trigger the default trait implementation for each type.
After setting up the system, we need to trigger it when we enter the GameState::Playing
state. iyes_loopless helps us out here with a add_enter_system
function on our Bevy App.
.add_enter_system(&GameState::Playing, reset_game)
We can also now remove the spawning logic in board.rs
for the snake and the apples, because the game_reset system is handling the apple spawn trigger while tick
is handling rendering the snake itself as it starts moving.
for segment in snake.segments.iter() {
commands.add({
SpawnSnakeSegment { position: *segment }
});
}
commands.add(SpawnApple {
position: Position { x: 15, y: 15 },
})
We can also remove the snake
reference in the arguments for the spawn_board
system since we aren’t using it anymore.
pub fn spawn_board(mut commands: Commands) {
We can now restart the game as much as we want!