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 initialising the board and its timer and RNG peripherals, we initialise 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_matrix
method 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_ms
method. 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 itsstatus
property). 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.