В этом уроке мы создадим игру «Лабиринт». Это классическая игра для телефонов и планшетов на Android и Ios, суть которой заключается в том, что вам требуется провести шарик через лабиринт. Управление шариком производится посредством акселерометра, поэтому каждое ваше неосторожное движение может привести к завершению игры.
Правила игры «Лабиринт»:
На игровом поле появляется шарик и лабиринт, представленный сетью разных ходов. В начальный момент игры шарик стоит на месте в точке равновесия, игрок посредством наклона всего устройства вверх, вниз, вправо, влево двигает шарик в соответствующую сторону. Чем больше угол наклона, тем быстрее катится шарик. Задача игрока заключается в том, что бы загнать шарик из начальной точки в лузу, пройдя непосредственно лабиринт. Если шарик дотронется до стенок лабиринта шарик, то происходит завершение игры. Как только игрок загонят шар в лунку, данный уровень считается пройденным происходит переход на следующий уровень. Всего уровней пять. Но желающие совершенствовать игру могут добавить новые локации (Лабиринт), посредством вмешательства добавления новых лабиринтов.
Управление:
Как и в предыдущем уроке игрок управляет шариком используя не кнопки или джойстик, а акселерометр, присутствующий в Trema-модуле IMU 9 DOF (Inertial Measurement Unit 9 Degrees Of Freedom). Таким образом управление шариком совершается наклоном всего устройства влево, вправо, вперёд или назад.
Нам понадобится:
- Arduino Uno х 1шт.
- Trema OLED-дисплей 128x64 х 1шт.
- Trema-модуль IMU 9 DOF х 1шт.
- Trema Set Shield х 1шт.
И никаких проводов (кроме USB для загрузки скетча).
Для реализации проекта нам необходимо установить следующие библиотеки:
- iarduino_OLED - графическая библиотека для работы с Trema OLED дисплеями.
- iarduino_Position_BMX055 - библиотека для работы с датчиком Trema IMU 9 DOF.
О том как устанавливать библиотеки, Вы можете ознакомиться на странице Wiki - Установка библиотек в Arduino IDE.
Видео:
Схема подключения:
Перед подключением модулей, закрепите винтами нейлоновые стойки в отверстиях секций 3 и 4 Trema Set Shield.- Установите Trema Set Shield на Arduino Uno.
- Установите Trema OLED-дисплей 128x64 в 3 посадочную площадку, в верхнюю I2C колодку.
- Установите Trema-модуль IMU 9 DOF в 4 посадочную площадку, в верхнюю I2C колодку.
- Полученный результат представлен на рисунке ниже.
Рисунок 1
Наличие всего двух колодок в секциях Trema Set Shield, не позволит Вам неправильно установить модули, т.к. при неправильном подключении модули будут смещены относительно разметки своей секции и Вы не сможете закрепить их винтами.
Модули необязательно устанавливать в секции 3 или 4. Trema Set Shield распознает модули в любой из секций.
Код программы:
#include <iarduino_Position_BMX055.h> // Подключаем библиотеку iarduino_Position_BMX055 для работы с Trema-модулем IMU 9 DOF. iarduino_Position_BMX055 sensor(BMA); // Создаём объект sensor указывая что ему требуется работать только с акселерометром. #define BMX055_DISABLE_BMG // Не использовать гироскоп. #define BMX055_DISABLE_BMM // Не использовать магнитометр. // #include <iarduino_OLED.h> // Подключаем библиотеку iarduino_OLED. iarduino_OLED myOLED(0x3C); // Объявляем объект myOLED, указывая адрес дисплея на шине I2C: 0x3C. extern uint8_t MediumFontRus[]; // Подключаем шрифт MediumFontRus. // /* Объявляем массивы и переменные: */ // const int startLevel = 1; // Константа определяющая с какого уровня загрузить игру. const int quantityLevel = 5; // Константа определяющая количество уровней массива. const uint32_t tableArray[quantityLevel][68] PROGMEM = { // Двумерный массив для локаций, содержащий в себе 5 уровней. Каждый массив содержит в себе 64 элемента по 32 бита. Каждый бит соответствует квадрату на экране размером 2 на два пикселя. { // 0b00000000000000000000000000000000, // 1 // 0b00000000000000000000000000000000, // 2 // 0b00000000000000000000000000000000, // 3 // 0b00000000000000000000000000000000, // 4 // 0b00000000000000000000000000000000, // 5 // 0b00000000000000000000000000000000, // 6 // 0b00000011111111111111111111111111, // 7 // 0b00000000000000000000000000000000, // 8 // 0b00000000000000000000000000000000, // 9 // 0b00000000000000000000000000000000, // 10 // 0b00000000000000000000000000000000, // 11 // 0b00000000000000000000000000000000, // 12 // 0b00000000000000000000000000000000, // 13 // 0b11111111111111111111111111000000, // 14 // 0b00000000000000000000000000000000, // 15 // 0b00000000000000000000000000000000, // 16 // 0b00000000000000000000000000000000, // 17 // 0b00000000000000000000000000000000, // 18 // 0b00000000000000000000000000000000, // 19 // 0b00000000000000000000000000000000, // 20 // 0b00000011111111111111111111111111, // 21 // 0b00000000000000000000000000000000, // 22 // 0b00000000000000000000000000000000, // 23 // 0b00000000000000000000000000000000, // 24 // 0b00000000000000000000000000000000, // 25 // 0b00000000000000000000000000000000, // 26 // 0b00000000000000000000000000000000, // 27 // 0b11111111111111111111111111000000, // 28 // 0b00000000000000000000000000000000, // 29 // 0b00000000000000000000000000000000, // 30 // 0b00000000000000000000000000000000, // 31 // 0b00000000000000000000000000000000, // 32 // 0b00000000000000000000000000000000, // 33 // 0b00000000000000000000000000000000, // 34 // 0b00000011111111111111111111111111, // 35 // 0b00000000000000000000000000000000, // 36 // 0b00000000000000000000000000000000, // 37 // 0b00000000000000000000000000000000, // 38 // 0b00000000000000000000000000000000, // 39 // 0b00000000000000000000000000000000, // 40 // 0b00000000000000000000000000000000, // 41 // 0b11111111111111111111111111000000, // 42 // 0b00000000000000000000000000000000, // 43 // 0b00000000000000000000000000000000, // 44 // 0b00000000000000000000000000000000, // 45 // 0b00000000000000000000000000000000, // 46 // 0b00000000000000000000000000000000, // 47 // 0b00000000000000000000000000000000, // 48 // 0b00000011111111111111111111111111, // 49 // 0b00000000000000000000000000000000, // 50 // 0b00000000000000000000000000000000, // 51 // 0b00000000000000000000000000000000, // 52 // 0b00000000000000000000000000000000, // 53 // 0b00000000000000000000000000000000, // 54 // 0b00000000000000000000000000000000, // 55 // 0b11111111111111111111111111000000, // 56 // 0b00000000000000000000000000000000, // 57 // 0b00000000000000000000000000000000, // 58 // 0b00000000000000000000000000000000, // 59 // 0b00000000000000000000000000000000, // 60 // 0b00000000000000000000000000000000, // 61 // 0b00000000000000000000000000000000, // 62 // 0b00000000000000000000000000000000, // 63 // 0b00000000000000000000000000000000, // 64 // 6, // X - координата положения шарика. 7, // Y - координата положения шарика. 119, // X - координата положения лунки. 55, // Y - координата положения лунки. }, // // { // 0b00000000000000000000000000000000, // 1 // 0b00000000000000000000000000000000, // 2 // 0b00000000000000000000000000000000, // 3 // 0b00000000000000000000000000000000, // 4 // 0b00000000000000000000000000000000, // 5 // 0b00000000000000000000000000000000, // 6 // 0b00000011111111111111111111000000, // 7 // 0b00000010000000000000000001000000, // 8 // 0b00000010000000000000000001000000, // 9 // 0b00000010000000000000000001000000, // 10 // 0b00000010000000000000000001000000, // 11 // 0b00000010000000000000000001000000, // 12 // 0b00000010000000000000000001000000, // 13 // 0b00000010000001111110000001000000, // 14 // 0b00000010000001000000000001000000, // 15 // 0b00000010000001000000000001000000, // 16 // 0b00000010000001000000000001000000, // 17 // 0b00000010000001000000000001000000, // 18 // 0b00000010000001000000000001000000, // 19 // 0b00000010000001000000000001000000, // 20 // 0b00000010000001000000111111000000, // 21 // 0b00000010000001000000000001000000, // 22 // 0b00000010000001000000000001000000, // 23 // 0b00000010000001000000000001000000, // 24 // 0b00000010000001000000000001000000, // 25 // 0b00000010000001000000000001000000, // 26 // 0b00000010000001000000000001000000, // 27 // 0b00000010000001111110000001000000, // 28 // 0b00000010000001000000000001000000, // 29 // 0b00000010000001000000000001000000, // 30 // 0b00000010000001000000000001000000, // 31 // 0b00000010000001000000000001000000, // 32 // 0b00000010000001000000000001000000, // 33 // 0b00000010000001000000000001000000, // 34 // 0b00000010000001000000111111000000, // 35 // 0b00000010000001000000000001000000, // 36 // 0b00000010000001000000000001000000, // 37 // 0b00000010000001000000000001000000, // 38 // 0b00000010000001000000000001000000, // 39 // 0b00000010000001000000000001000000, // 40 // 0b00000010000001000000000001000000, // 41 // 0b00000010000001111111000001000000, // 42 // 0b00000010000001000000000001000000, // 43 // 0b00000010000001000000000001000000, // 44 // 0b00000010000001000000000001000000, // 45 // 0b00000010000001000000000001000000, // 46 // 0b00000010000001000000000001000000, // 47 // 0b00000010000001000000000001000000, // 48 // 0b00000010000001000000000001000000, // 49 // 0b00000010000001000000000001000000, // 50 // 0b00000010000001111111111111000000, // 51 // 0b00000010000000000000000000000000, // 52 // 0b00000010000000000000000000000000, // 53 // 0b00000010000000000000000000000000, // 54 // 0b00000010000000000000000000000000, // 55 // 0b00000010000000000000000000000000, // 56 // 0b00000010000000000000000000000000, // 57 // 0b00000011111111111111111111111111, // 58 // 0b00000000000000000000000000000000, // 59 // 0b00000000000000000000000000000000, // 60 // 0b00000000000000000000000000000000, // 61 // 0b00000000000000000000000000000000, // 62 // 0b00000000000000000000000000000000, // 63 // 0b00000000000000000000000000000000, // 64 // 121, // X - координата положения шарика. 7, // Y - координата положения шарика. 92, // X - координата положения лунки. 24, // Y - координата положения лунки. }, // // { // 0b00000000000000000000000000000000, // 1 // 0b00000000000000000000000000000000, // 2 // 0b00000000000000000000000000000000, // 3 // 0b00000000000000000000000000000000, // 4 // 0b00000000000000000000000000000000, // 5 // 0b00000000000000000000000000000000, // 6 // 0b00000000000000000000000000000000, // 7 // 0b00000001111111111111111100000000, // 8 // 0b00000000000000010000000000000000, // 9 // 0b00000000000000010000000000000000, // 10 // 0b00000000000000010000000000000000, // 11 // 0b00000000000000010000000000000000, // 12 // 0b00000000000000010000000000000000, // 13 // 0b00000000000000010000000000000000, // 14 // 0b11111111111111110000000111111111, // 15 // 0b00000000000000010000000000000000, // 16 // 0b00000000000000010000000000000000, // 17 // 0b00000000000000010000000000000000, // 18 // 0b00000000000000010000000000000000, // 19 // 0b00000000000000010000000000000000, // 20 // 0b00000000000000010000000000000000, // 21 // 0b00000001000000011111111100000000, // 22 // 0b00000001000000000000000000000000, // 23 // 0b00000001000000000000000000000000, // 24 // 0b00000001000000000000000000000000, // 25 // 0b00000001000000000000000000000000, // 26 // 0b00000001000000000000000000000000, // 27 // 0b00000001000000000000000000000000, // 28 // 0b00000001111111111111111111111111, // 29 // 0b00000000000000000000000000000000, // 30 // 0b00000000000000000000000000000000, // 31 // 0b00000000000000000000000000000000, // 32 // 0b00000000000000000000000000000000, // 33 // 0b00000000000000000000000000000000, // 34 // 0b00000000000000000000000000000000, // 35 // 0b11111111111111111111111100000000, // 36 // 0b00000000000000000000000000000000, // 37 // 0b00000000000000000000000000000000, // 38 // 0b00000000000000000000000000000000, // 39 // 0b00000000000000000000000000000000, // 40 // 0b00000000000000000000000000000000, // 41 // 0b00000000000000000000000000000000, // 42 // 0b00000001111111111111111111111111, // 43 // 0b00000001000000000000000000000000, // 44 // 0b00000001000000000000000000000000, // 45 // 0b00000001000000000000000000000000, // 46 // 0b00000001000000000000000000000000, // 47 // 0b00000001000000000000000000000000, // 48 // 0b00000001000000000000000000000000, // 49 // 0b00000001000000011111111100000000, // 50 // 0b00000000000000010000000000000000, // 51 // 0b00000000000000010000000000000000, // 52 // 0b00000000000000010000000000000000, // 53 // 0b00000000000000010000000000000000, // 54 // 0b00000000000000010000000000000000, // 55 // 0b00000000000000010000000000000000, // 56 // 0b11111111111111110000000111111111, // 57 // 0b00000000000000000000000000000000, // 58 // 0b00000000000000000000000000000000, // 59 // 0b00000000000000000000000000000000, // 60 // 0b00000000000000000000000000000000, // 61 // 0b00000000000000000000000000000000, // 62 // 0b00000000000000000000000000000000, // 63 // 0b00000000000000000000000000000000, // 64 // 120, // X - координата положения шарика. 55, // Y - координата положения шарика. 22, // X - координата положения лунки. 40, // Y - координата положения лунки. }, // // { // 0b00000000100000000000010000000000, // 1 // 0b00000000100000000000001000000000, // 2 // 0b00000000100000000000000100000000, // 3 // 0b00000000100000000000000010000000, // 4 // 0b00000000100000000000000001000000, // 5 // 0b00000000100000000000000000100000, // 6 // 0b00000000100000000100000000010000, // 7 // 0b00000000010000000010000000001000, // 8 // 0b10000000001000000001000000000100, // 9 // 0b01000000000100000000100000000010, // 10 // 0b00100000000010000000010000000001, // 11 // 0b00010000000001000000001000000000, // 12 // 0b00001000000001000000001000000000, // 13 // 0b00000100000000100000000100000000, // 14 // 0b00000100000000100000000100000000, // 15 // 0b00001000000001000000001000000000, // 16 // 0b00010000000001000000001000000001, // 17 // 0b00100000000010000000010000000010, // 18 // 0b01000000000100000000100000000100, // 19 // 0b10000000001000000001000000001000, // 20 // 0b00000000010000000010000000010000, // 21 // 0b00000000100000000100000000100000, // 22 // 0b00000000100000000100000000100000, // 23 // 0b00000000100000000100000000100000, // 24 // 0b00000000100000000100000000100000, // 25 // 0b00000000010000000010000000010000, // 26 // 0b10000000001000000001000000001000, // 27 // 0b01000000000100000000100000000100, // 28 // 0b00100000000010000000010000000010, // 29 // 0b00010000000001000000001000000001, // 30 // 0b00001000000001000000001000000000, // 31 // 0b00000100000000100000000100000000, // 32 // 0b00000100000000100000000100000000, // 33 // 0b00001000000001000000001000000000, // 34 // 0b00010000000001000000001000000001, // 35 // 0b00100000000010000000010000000010, // 36 // 0b01000000000100000000100000000100, // 37 // 0b10000000001000000001000000001000, // 38 // 0b00000000010000000010000000010000, // 39 // 0b00000000100000000100000000100000, // 40 // 0b00000000100000000100000000100000, // 41 // 0b00000000100000000100000000100000, // 42 // 0b00000000100000000100000000100000, // 43 // 0b00000000010000000010000000010000, // 44 // 0b10000000001000000001000000001000, // 45 // 0b01000000000100000000100000000100, // 46 // 0b00100000000010000000010000000010, // 47 // 0b00010000000001000000001000000001, // 48 // 0b00001000000001000000001000000000, // 49 // 0b00000100000000100000000100000000, // 50 // 0b00000100000000100000000100000000, // 51 // 0b00001000000001000000001000000000, // 52 // 0b00010000000001000000001000000001, // 53 // 0b00100000000010000000010000000010, // 54 // 0b01000000000100000000100000000100, // 55 // 0b10000000001000000001000000001000, // 56 // 0b00000000010000000010000000010000, // 57 // 0b00000000100000000100000000100000, // 58 // 0b00000000000000001000000001000000, // 59 // 0b00000000000000010000000010000000, // 60 // 0b00000000000000010000000010000000, // 61 // 0b00000000000000010000000010000000, // 62 // 0b00000000000000010000000010000000, // 63 // 0b00000000000000010000000010000000, // 64 // 7, // X - координата положения шарика. 56, // Y - координата положения шарика. 122, // X - координата положения лунки. 23, // Y - координата положения лунки. }, // // { // 0b00000000000000000000001000000000, // 1 // 0b00000000000000000000000100000000, // 2 // 0b00000000000000000000000010000000, // 3 // 0b00000000000000000000000001000000, // 4 // 0b00000000000000000000000000100000, // 5 // 0b00000000000000000000000000010000, // 6 // 0b11111111111111111111100000001000, // 7 // 0b00000000000000000000010000000100, // 8 // 0b00000000000000000000001000000010, // 9 // 0b00000000000000000000000100000001, // 10 // 0b00000000000000000000000010000000, // 11 // 0b00000000000000000000000010000000, // 12 // 0b10000000100000000000000010000000, // 13 // 0b01000000010000000000000010000000, // 14 // 0b00100000001000000000000010000000, // 15 // 0b00010000000100000000000010000000, // 16 // 0b00001000000011111111111110000000, // 17 // 0b00010000000100000000000010000000, // 18 // 0b00100000001000000000000010000000, // 19 // 0b01000000010000000000000010000000, // 20 // 0b10000000100000000000000010000000, // 21 // 0b00000001000000000000000010000000, // 22 // 0b00000000000000001000000010000000, // 23 // 0b00000000000000010000000100000001, // 24 // 0b00000000000000100000001000000010, // 25 // 0b00000000000001000000010000000100, // 26 // 0b00000000000010000000100000001000, // 27 // 0b00000000000100000001000000010000, // 28 // 0b00000000001100000001000000010000, // 29 // 0b00000000010010000000100000001000, // 30 // 0b11111111100001000000010000000100, // 31 // 0b00000000000000100000001000000010, // 32 // 0b00000000000000010000000100000001, // 33 // 0b00000000000000001000000010000000, // 34 // 0b00000000000000000100000010000000, // 35 // 0b00000000000000000100000010000000, // 36 // 0b00000000000000000100000010000000, // 37 // 0b00000011110000000000000010000000, // 38 // 0b00000000001000000000000010000000, // 39 // 0b00000000000100000000000010000000, // 40 // 0b00000000000010000000000010000000, // 41 // 0b00000000000001000000000010000000, // 42 // 0b00000000000000100000000010000000, // 43 // 0b11111110000000010000000010000000, // 44 // 0b00000001000000001000000010000000, // 45 // 0b00000000100000000100000010000000, // 46 // 0b00000000010000000010000010000000, // 47 // 0b00000000001000000001000010000000, // 48 // 0b00000000000100000000100100000001, // 49 // 0b00000000000010000000011000000010, // 50 // 0b00000000000000000000010000000100, // 51 // 0b00000000000000000000100000001000, // 52 // 0b00000010000000000001000000010000, // 53 // 0b00000001000000000011000000010000, // 54 // 0b00000000100000000100100000001000, // 55 // 0b00000000010000001000010000000100, // 56 // 0b00000000001000010000001000000010, // 57 // 0b00000000000100100000000100000001, // 58 // 0b00000000000011000000000010000000, // 59 // 0b00000000000000000000000000000000, // 60 // 0b00000000000000000000000000000000, // 61 // 0b00000000000000000011000000000000, // 62 // 0b00000000000000000100100000000000, // 63 // 0b00000000000000001000010000000000, // 64 // 6, // X - координата положения шарика. 55, // Y - координата положения шарика. 25, // X - координата положения лунки. 25, // Y - координата положения лунки. }, // //************************************************************************************// // Место для нового массива нового уровня. // //************************************************************************************// }; // // int y, x; // Переменные положения движения. int yh, xh; // Переменные положения лунки. int ys, xs; // Вспомогательные переменные для запоминания последних координат. int limited; // Переменная регулирования скорости. int Level; // Переменная выбора уровня. // /* Объявляем функции: */ // // void Draw(); // Функция прорисовки шарик. void Logic(); // Функция движения шарика. void GameOver(); // Функция завершения игры. void CheckBlock(); // Функция проверки столкновения шарика с препятствиями. void Location(); // Функция прорисовки локации. void LevelWin(); // Функция прохождения уровня. void GameWin(); // Функция прохождения игры. void Position(); // Функция для задания начального положения шарика и лунки. void ShowLevel(); // Функция вывода заставки уровня. void StartScreen(); // Функция вывода заставки игры. // void setup() // { // myOLED.begin(); // Инициируем работу с дисплеем. myOLED.autoUpdate(false); // Запрещаем автоматический вывод данных. Информация на дисплее будет обновляться только после обращения к функции update(). // while(!Serial){} // Ждём готовность Serial к передаче данных в монитор последовательного порта. sensor.begin(true); // Инициируем работу с датчиками объекта sensor. // StartScreen(); // Выводим заставку игры. Level = startLevel - 1; // Присваиваем переменной выбора уровня первый уровень. Цифра ноль соответствует первому элементу двумерного массива. ShowLevel(); // Показываем заставку уровня. Position(); // Определяем начальные координаты шарика и координаты лунки. Location(); // Прорисовываем локацию. } // // void loop() // { // xs = x; ys = y; // Каждый цикл присваиваем вспомогательным переменным предыдущие координаты шарика. Logic(); // Двигаем шарик в зависимости от направления. От угла наклона акселерометра. Draw(); // Рисуем шарик на новых координатах. CheckBlock(); // Проверяем не столкнулся ли шарик с преградой. LevelWin(); // Проверяем выигрышную позицию. myOLED.update(); // Разрешаем автоматический вывод данных. } // // void StartScreen(){ // Функция вывода заставки игры. myOLED.drawRect (0, 0, 127, 63, false, 1); // Прорисовываем рамку игрового поля. myOLED.setFont(MediumFontRus); // Указываем шрифт который требуется использовать для вывода цифр и текста. myOLED.print("ЛАБИРИНТ", OLED_C, 60); // Выводим текст по центру 50 строки. // for (int i = 35; i >= 3; i = i - 8) { // Цикл формирования картинки. // myOLED.drawRect (30, i, 36, i + 6, true , 1);} // Выводим картинку на экран. // for (int i = 30; i <= 94; i = i + 8){ // Цикл формирования картинки. // # # # # # # # # # myOLED.drawRect (i, 3, i + 6, 9, true , 1);} // Выводим картинку на экран. // # # for (int i = 3; i <= 35; i = i + 8) { // Цикл формирования картинки. // # # # # # # # myOLED.drawRect (94, i, 100, i + 6, true , 1);} // Выводим картинку на экран. // # # for (int i = 94; i >= 30; i = i - 8){ // Цикл формирования картинки. // # # # # # # # # # myOLED.drawRect (i, 35, i + 6, 41, true , 1);} // Выводим картинку на экран. // for (int i = 46; i <= 78; i = i + 8){ // Цикл формирования картинки. // myOLED.drawRect (i, 19, i + 6, 25, true , 1);} // Выводим картинку на экран. // // x = 89; y = 29; xh = 41; yh = 29; // Координаты начального положения шарика и лунки для анимации заставки // for (int i = 1; i <= 48; i++){ // Цикл формирования анимацию. xs = x; ys = y; // Каждый цикл присваиваем вспомогательным переменным предыдущие координаты шарика. x--; // Двигаем шарик влево. myOLED.drawCircle (xs, ys, 2, true, 0); // Очищаем последнее положения шарика. myOLED.drawCircle ( x, y, 2, true, 1); // Рисуем шарик в указанных координатах радиусом 2. myOLED.drawCircle (xh, yh, 3, false, 1); // Рисуем лунку в указанных координатах радиусом 3. myOLED.update();} // Разрешаем автоматический вывод данных. delay(2000); // Задержка 2 секунды. // myOLED.clrScr(); // Чистим экран. myOLED.drawRect (0, 0, 127, 63, false, 1); // Прорисовываем рамку игрового поля. myOLED.print("От", OLED_C, 25); // Выводим текст по центру 20 строки. myOLED.print("IARDUINO", OLED_C, 50); // Выводим текст по центру 20 строки. myOLED.update(); // Разрешаем автоматический вывод данных. delay (2000); // Задержка 2 секунды. } // // void ShowLevel(){ // Функция показа заставки уровня. myOLED.clrScr(); // Очищаем дисплей. myOLED.drawRect (0, 0, 127, 63, false, 1); // Прорисовываем рамку игрового поля. myOLED.setFont(MediumFontRus); // Указываем шрифт который требуется использовать для вывода цифр и текста. myOLED.print("Уровень", 12, OLED_C); // Выводим текст по центру 5 столбца. myOLED.print(Level+1, 101, OLED_C); // Выводим текст по центру 100 столбца. myOLED.update(); // Разрешаем автоматический вывод данных. delay(3000); // Задержка 3 секунды. } // // void GameWin(){ // Функция прохождения игры. if (Level == quantityLevel){ // Сравниваем переменную выбора уровня с числом 5. Если она равна пяти, то игра пройдена. myOLED.clrScr(); // Очищаем дисплей. myOLED.setFont(MediumFontRus); // Указываем шрифт который требуется использовать для вывода цифр и текста. myOLED.print("ВЫИГРЫШ!", 20, OLED_C); // Выводим текст по центру 20 столбца. myOLED.update(); // Разрешаем автоматический вывод данных. delay(3000); // Задержка 3 секунды. return setup(); // Возвращаемся в начало игры. } // } // void LevelWin(){ // функция прохождения игры. if ( y == yh && x == xh || y == yh + 1 && x == xh || y == yh - 1 && x == xh || y == yh && x == xh + 1 || y == yh && x == xh - 1){ // Если координаты лунки совпадают с координатами шарика, то уровень пройден. Level++; // Увеличиваем переменную выбора уровней на один. Будет отрисовываться следующий уровень. GameWin(); // Проверяем, мы прошли все уровни. ShowLevel(); // Показываем заставку следующего уровня. Position(); // Определяем начальные координаты шарика и координаты лунки следующего уровня. Location(); // Отрисовываем уровень. return loop(); // Возвращаемся в цикл игры. } // } // // void Location(){ // Функция прорисовки уровня. for (int j = 0; j < 64; j++){ // Прорисовываем массив с помощью циклов. Цикл по j соответствует X-координате. for (int i = 0; i < 32; i++){ // Цикл по i соответствует Y-координате. myOLED.drawRect (j*2, i*2, j*2+2, i*2+2, true, bitRead(pgm_read_dword(&tableArray[Level][j]),i));}} // Заполняем поле квадратиками размером 2 на 2 пикселя в соответствии с выбранным массивом. Если бит элемента массива равен 1, то на экране отрисуется квадрат. myOLED.drawRect (0, 0, 127, 63, false, 1); // Прорисовываем рамку игрового поля. } // // void CheckBlock(){ // Функция проверки столкновения шарика с препятствием. if (x > 124 || x < 3 || y > 60 || y < 3){GameOver();} // Проверка выхода шарика за пределы игрового поля. Если координаты движения больше, чем игровое поле, то игра заканчивается. bool f = 0; // Вспомогательная переменная для проверки совершения события. for(int i=x-2; i<=x+2; i++){ // Проходим по колонкам шарика. for(int j=y-2; j<=y+2; j++){ // Проходим по строкам шарика. Соответствуют координаты шарика с координатами препятствий. if(bitRead(pgm_read_dword(&tableArray[Level][i/2]),j/2)){f =1;}}} // Проверка на соответствие координат шарика с координатами препятствий. Если соответствуют, то присваиваем переменной события значение true. if(f){GameOver();} // Если переменная события равна 1, то игра заканчивается. } // // void Draw(){ // Функция отрисовки шарика и лунки. myOLED.drawCircle (xs, ys, 2, true, 0); // Очищаем последнее положения шарика. myOLED.drawCircle ( x, y, 2, true, 1); // Рисуем шарик в указанных координатах радиусом 2. myOLED.drawCircle (xh, yh, 3, false, 1); // Рисуем лунку в указанных координатах радиусом 3. } // // void Logic(){ // Функция движения шарика. sensor.read(); // Читаем данные датчика (акселерометра). // Движение влево. if (sensor.axisX <= -2.5){for (limited=3;limited >= 1;limited--){x--;}} // Движение влево осуществляется при уменьшении Х-координаты в отрицательную сторону. if (sensor.axisX <= -1.5){for (limited=2;limited >= 1;limited--){x--;}} // При уменьшении X-координаты, то есть увеличении наклона акселерометра влево, скорость передвижения шарика увеличивается. if (sensor.axisX <= -0.3){x--;} // Это реализовано с помощью цикла, который ограничивает прорисовку шарика. Шарик при большой скорости рисуется не в каждой следующей координате, а через определенное количество шагов в зависимости от скорости. // Движение вправо. if (sensor.axisX >= 2.5){for (limited=3;limited >= 1;limited--){x++;}} // Движение вправо осуществляется при увеличении Х-координаты в положительную сторону. if (sensor.axisX >= 1.5){for (limited=2;limited >= 1;limited--){x++;}} // При увеличении X-координаты, то есть увеличении наклона акселерометра вправо, скорость передвижения шарика увеличивается. if (sensor.axisX >= 0.3){x++;} // Это реализовано с помощью цикла, который ограничивает прорисовку шарика. Шарик при большой скорости рисуется не в каждой следующей координате, а через определенное количество шагов в зависимости от скорости. // Движение вниз. if (sensor.axisY <= -2.5){for (limited=3;limited >= 1;limited--){y++;}} // Движение вниз осуществляется при уменьшении Y-координаты в отрицательную сторону. if (sensor.axisY <= -1.5){for (limited=2;limited >= 1;limited--){y++;}} // При уменьшении Y-координаты, то есть увеличении наклона акселерометра вниз, скорость передвижения шарика увеличивается. if (sensor.axisY <= -0.3){y++;} // Это реализовано с помощью цикла, который ограничивает прорисовку шарика. Шарик при большой скорости рисуется не в каждой следующей координате, а через определенное количество шагов в зависимости от скорости. // Движение вверх. if (sensor.axisY >= 2.5){for(limited=3;limited >= 1;limited--){y--;}} // Движение вверх осуществляется при увеличении Y-координаты в положительную сторону. if (sensor.axisY >= 1.5){for(limited=2;limited >= 1;limited--){y--;}} // При увеличении Y-координаты, то есть увеличении наклона акселерометра вверх, скорость передвижения шарика увеличивается. if (sensor.axisY >= 0.3){y--;} // Это реализовано с помощью цикла, который ограничивает прорисовку шарика. Шарик при большой скорости рисуется не в каждой следующей координате, а через определенное количество шагов в зависимости от скорости. } // // void GameOver(){ // Функция завершения игры. myOLED.drawPixel (x+6, y, 1); // Прорисовываем картинку проигрышного положения. myOLED.drawPixel (x+5, y, 1); // myOLED.drawPixel (x+4, y, 1); // myOLED.drawPixel (x-6, y, 1); // myOLED.drawPixel (x-5, y, 1); // # myOLED.drawPixel (x-4, y, 1); // # # # myOLED.drawPixel (x, y+6, 1); // # # # myOLED.drawPixel (x, y+5, 1); // # # myOLED.drawPixel (x, y+4, 1); // ### myOLED.drawPixel (x, y-6, 1); // ##### myOLED.drawPixel (x, y-5, 1); // ### ##### ### myOLED.drawPixel (x, y-4, 1); // ##### myOLED.drawPixel (x+5, y+5, 1); // ### myOLED.drawPixel (x+4, y+4, 1); // # # myOLED.drawPixel (x+3, y+3, 1); // # # # myOLED.drawPixel (x-5, y-5, 1); // # # # myOLED.drawPixel (x-4, y-4, 1); // # myOLED.drawPixel (x-3, y-3, 1); // myOLED.drawPixel (x-5, y+5, 1); // myOLED.drawPixel (x-4, y+4, 1); // myOLED.drawPixel (x-3, y+3, 1); // myOLED.drawPixel (x+5, y-5, 1); // myOLED.drawPixel (x+4, y-4, 1); // myOLED.drawPixel (x+3, y-3, 1); // myOLED.update(); // Разрешаем автоматический вывод данных. delay(500); // Задержка 500 мс. myOLED.clrScr(); // Очищаем экран. Position(); // Определяем начальные координаты шарика и координаты лунки следующего уровня. Location(); // Отрисовываем уровень. return loop(); // Возвращаемся в цикл игры. } // // void Position() // Функция для задания начального положения шарика и лунки. { // x = pgm_read_dword(&tableArray[Level][64]); // Координаты начального положения шарика в зависимости от уровня. y = pgm_read_dword(&tableArray[Level][65]); // // xh = pgm_read_dword(&tableArray[Level][66]); // Координаты начального положения шарика и лунки второго уровня. yh = pgm_read_dword(&tableArray[Level][67]); // } //
Алгоритм работы:
- В начале скетча (до кода setup) выполняются следующие действия:
- Подключаем библиотеку iarduino_Position_BMX055 для работы с датчиком Trema IMU 9 DOF.
- Объявляем объект sensor, указывая работу только с акселерометром.
- Подключаем графическую библиотеку iarduino_OLED для работы с Trema OLED дисплеем.
- Объявляем объект myOLED указывая адрес дисплея на шине I2C, он должен совпадать с адресом установленным переключателем на обратной стороне платы OLED дисплея.
- Подключаем шрифты предустановленные в библиотеке myOLED.
- Объявляем двумерный массив для локаций (лабиринта) и переменные участвующие в работе скетча.
- Объявляем функции используемые в скетче.
- В коде setup выполняются следующие действия:
- Инициируем работу с Trema OLED дисплеем и запрещаем автоматический вывод данных.
- Выводим заставку игры (текст «Лабиринт» на фоне картинки, функция "StartScreen()" и очищаем экран.
- Инициируем работу с датчиком Trema IMU 9 DOF.
- Определяем начальные параметры игры (Задаем уровень первый, показываем его заставку (функция" ShowLevel()"); задаем начальные координаты шарика и координаты лунки (функция "Position()"), прорисовываем локацию (лабиринт) первого уровня (функция "Location()").
- В коде loop выполняются следующие действия:
- Запоминаем предыдущие координаты шарика, чтобы потом очищать след от шарика.
- Функция "Logic()", функция логики движения шарика. В ней происходит считывание данных акселерометра и в зависимости от наклона акселерометра, шарик двигается в заданном направлении. При увеличении наклона акселерометра, увеличивается скорость передвижения шарика.
- Функция "Draw()", функция прорисовки шарика и лунки. А так же очищаем след от шарика.
- Функция "CheckBlock()", функция проверки столкновения шарика с препятствием. В ней происходит проверка выхода шарика за пределы игрового поля, а так проверка столкновения шарика с препятствием по средством проверки координат самого шарика с координатами препятствия локации (лабиринта) в заданном массиве уровня. Если произошло столкновение, то игра заканчивается (функция "GameOver()"). При этом, пройденные уровни сохраняются до отключения питания.
- Функция "LevelWin()", функция проверки выигрыша игроком уровня. В ней, если игрок загонят шарик в лунку, то уровень пройден. Если пройдены все уровни то игра закончится с вашим выигрышем (функция "GameWin()").
- Разрешаем автоматический вывод данных.
Все строки скетча (кода программы) прокомментированы, так что Вы можете подробнее ознакомиться с кодом прочитав комментарии строк.
Виды уровней:
В игре присутствуют пять видов уровней. Они показаны на рисунках 2 ниже:
Уровень 1 | Уровень 2 | Уровень 3 | Уровень 4 | Уровень 5 |
![]() |
![]() |
![]() |
![]() |
![]() |
Рисунок 2
Добавление уровней:
Существует возможность создать свой уровень и добавить его в программу. Для этого нам понадобиться:
- Открыть код программы в начале скетча.
- Указать количество уровней. Для этого переменную "quantityLevel" присваиваем новое значение. По умолчанию указана цифра "5", что соответствует пяти уровням. Если нам необходимо добавить шестой уровень, указываем цифру "6".
- Создать новый массив, как очередной элемент двумерного массива" tableArray[]". Для этого можно скопировать уже имеющийся массив и вставить его в поле, где указано "Место для нового массива нового уровня." Не забудьте обязательно скопировать скобки, ограничивающий новый массив, вместе с запятой после второй скобки. Либо составить массив вручную в указанном поле.
- Задать новые координаты начального положения шарика и лунки. Для этого в конце массива необходимо указать 4 переменные. Первая переменная - это X - координата положения шарика. Вторая переменная - Y - координата положения шарика. Третья координата - это X - координата положения лунки. Четвертая переменная - это Y - координата положения лунки.
- После проделанных операций обязательно убедитесь что шарик расположен правильно и он не заходит за пределы препятствий, иначе новый уровень не запустится.
- Для быстрого перехода к созданному уровню, необходимо в начале программы переменной "startLevel" присвоить номер уровня. То есть, если необходимо загрузить шестой уровень, указываем цифру "6".
Ссылки:
- Код программы;
- Библиотека iarduino_OLED;
- Wiki - Установка библиотек в Arduino IDE;
- Wiki - OLED экран 128×64 / 0,96”;
- Wiki - Trema-модуль IMU 9 DOF.
Обсуждение