Snake game: final assembly
The code in our src/main.rs file brings all the previously-discussed machinery together to make
our final game.
#![no_main]
#![no_std]
mod controls;
mod display;
pub mod game;
use controls::{get_turn, init_buttons};
use display::{clear_display, display_image, init_display};
use game::{Game, GameStatus};
use cortex_m_rt::entry;
use embedded_hal::delay::DelayNs;
use microbit::{
display::nonblocking::{BitImage, GreyscaleImage},
hal::{Rng, Timer},
Board,
};
use panic_rtt_target as _;
use rtt_target::rtt_init_print;
#[entry]
fn main() -> ! {
rtt_init_print!();
let board = Board::take().unwrap();
let mut timer = Timer::new(board.TIMER0).into_periodic();
let mut rng = Rng::new(board.RNG);
let mut game = Game::new(&mut rng);
init_buttons(board.GPIOTE, board.buttons);
init_display(board.TIMER1, board.display_pins);
loop {
loop {
// Game loop
let image = GreyscaleImage::new(&game.game_matrix(6, 3, 9));
display_image(&image);
timer.delay_ms(game.step_len_ms());
match game.status {
GameStatus::Ongoing => game.step(get_turn(true)),
_ => {
for _ in 0..3 {
clear_display();
timer.delay_ms(200u32);
display_image(&image);
timer.delay_ms(200u32);
}
clear_display();
display_image(&BitImage::new(&game.score_matrix()));
timer.delay_ms(2000u32);
break;
}
}
}
game.reset();
}
}
After initializing the board and its timer and RNG peripherals, we initialize a Game struct and a
Display from the microbit::display::blocking module.
In our “game loop” (which runs inside of the “main loop” we place in our main function), we
repeatedly perform the following steps:
-
Get a 5×5 array of bytes representing the grid. The
Game::get_matrixmethod takes three integer arguments (which should be between 0 and 9, inclusive) which will, eventually, represent how brightly the head, tail and food should be displayed. -
Display the matrix, for an amount of time determined by the
Game::step_len_msmethod. As currently implemented, this method basically provides for 1 second between steps, reducing by 200ms every time the player scores 5 points (eating 1 piece of food = 1 point), subject to a floor of 200ms. -
Check the game status. If it is
Ongoing(which is its initial value), run a step of the game and update the game state (including itsstatusproperty). Otherwise, the game is over, so flash the current image three times, then show the player’s score (represented as a number of illuminated LEDs corresponding to the score), and exit the game loop.
Our main loop just runs the game loop repeatedly, resetting the game’s state after each iteration.