Our focus in this part of the tutorial is to refactor the code in a way that allows us to include a good looking start up screen to our game.
The notions explained in this tutorial:
- Bevy's States
- Bevy's System Sets
Refactor to Add a Main Menu Screen
Since we wish to add a main menu screen, we need a way to:
- Split our game in 2: the main menu and the game
- Allow our user to control this state.
- Register and remove resources as we go from one game state to the other.
Game State
If we translate our need to code, the game state is an enum like this one:
// main.rs
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
enum AppState {
MainMenu,
InGame,
}
Bevy allows us to register a state as follow:
// main.rs
.add_state(AppState::MainMenu)
Controlling the State
Our user could control the game state with the keyboard, as we learned in part 4. The state can be updated by modifying the state resource using Bevy's API.
// main.rs
// main function
.add_system(main_menu_controls.system())
// system
fn main_menu_controls(mut keys: ResMut<Input<KeyCode>>, mut app_state: ResMut<State<AppState>>) {
if *app_state.current() == AppState::MainMenu {
if keys.just_pressed(KeyCode::Return) {
app_state.set(AppState::InGame).unwrap();
keys.reset(KeyCode::Return);
}
} else {
if keys.just_pressed(KeyCode::Escape) {
app_state.set(AppState::MainMenu).unwrap();
keys.reset(KeyCode::Escape);
}
}
}
The state of our game can now be controlled with the Return
and Esc
keys. The .reset
call is because of this current Bevy issue.
Register and Remove Resources
The final step is to register and remove resources when the state of our game changes. Bevy's system sets allows us do just that. If you take a look at our player.rs
file:
app.add_system_set(
SystemSet::on_enter(AppState::InGame).with_system(spawn_player.system()),
)
.add_system_set(
SystemSet::on_update(AppState::InGame)
.with_system(player_jumps.system())
.with_system(player_movement.system())
.with_system(jump_reset.system()),
)
.add_system_set(SystemSet::on_enter(AppState::MainMenu).with_system(cleanup.system()))
.add_system_set(SystemSet::on_exit(AppState::MainMenu).with_system(cleanup.system()));
A set of system can be run for a given state. Sets of systems can also run once when exiting or entering a state. The code above registers a system set that spawns the player when the app enters the AppState::InGame
state.
It also registers a cleanup
system when the app enters and exists the AppState::MainMenu
state.
Finally, the code adds systems to run on update when the AppState::InGame
state is active.
The cleanup systems code is the following:
fn cleanup(mut commands: Commands, query: Query<Entity>) {
for entity in query.iter() {
commands.entity(entity).despawn_recursive();
}
}
Final Code
My final code is available here. I am not taking the time to go over the details here. Mostly, I moved the code to end up with a game
and a main_menu
module.
Top comments (0)