Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Игра «Змейка»: финальная сборка

Код в нашем файле src/main.rs объединяет все рассмотренные ранее механизмы и создаёт итоговую игру.

#![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 {
            // Игровой цикл
            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();
    }
}

После инициализации платы, её таймера и генератора случайных чисел мы создаём структуру Game и Display из модуля microbit::display::blocking.

В нашем «игровом цикле» (он выполняется внутри «главного цикла» в функции main) мы многократно выполняем такие шаги:

  1. Получить массив байтов 5×5, представляющий сетку. Метод Game::get_matrix принимает три целочисленных аргумента (от 0 до 9 включительно), которые в итоге задают яркость головы, хвоста и еды.

  2. Вывести матрицу на время, которое определяет метод Game::step_len_ms. В текущей реализации этот метод в основном задаёт 1 секунду между шагами, уменьшая её на 200 мс каждый раз, когда игрок набирает 5 очков (одна съеденная еда = 1 очко), но не менее 200 мс.

  3. Проверить статус игры. Если он Ongoing (его начальное значение), выполнить шаг игры и обновить состояние игры (включая свойство status). Иначе игра окончена: мигнуть текущим изображением три раза, затем показать счёт игрока (в виде количества горящих светодиодов, соответствующего счёту) и выйти из игрового цикла.

Главный цикл просто многократно запускает игровой цикл, сбрасывая состояние игры после каждой итерации.