Создаём собственную игру

В этом уроке

  • Создание игры
  • Работа с массивами

Видео версия урока

Принцип работы игры

Мы научились выводить на светодиодную матрицу изображения и даже делать несложную анимацию. Давайте пойдём дальше и создадим небольшую игру, в которой нужно будет уклоняться от летящих пикселей. Они, разумеется, будут появляться случайным образом, а скорость игры будет меняться в зависимости от успешности её прохождения — замедляться с каждой ошибкой и расти после нескольких успешных действий. 

А что же насчёт управления? Можно сделать управление игроком через ИК-пульт, но почему бы не использовать бампер в качестве датчика, который будет реагировать на перемещающийся под ним палец!

Скетч проекта

Давайте загрузим скетч. Мы постарались сделать его как можно более простым, чтобы в нём было несложно разобраться. Комментарии помогут Вам.

#include <Wire.h>                             //  Подключаем библиотеку для работы с шиной I2C
#include <iarduino_I2C_Bumper.h>              //  Подключаем библиотеку для работы с бампером I2C-flash
#include <iarduino_I2C_Matrix_8x8.h>          //  Подключаем библиотеку для работы с LED матрицей 8x8
iarduino_I2C_Bumper  bum (0x0C);              //  Объявляем объект bum для работы с бампером I2C-flash
iarduino_I2C_Matrix_8x8 disp(0x0D);           //  Объявляем объект disp для работы с LED матрицей 8x8

uint8_t sensNum;                              //  Номер сработавшего датчика бампера
uint32_t timeFrame = 400;                     //  Начальное время задержки смены кадров (скорость летящих пикселей)
uint32_t timeUpdate;                          //  Время, когда картинка на матрице была обновлена
uint32_t soundTime;                           //  Время, когда прозвучал первый сигнал зуммера
uint8_t score = 0;                            //  Число "победных" строчек подряд
uint8_t par = 0;                              //  Число, показывающее чётность строк
bool soundBad = false;                        //  Флаг — указывает, что нужно включить звук ошибки
bool secondTimeFlag = false;                  //  Флаг — показывает, что нужно повторно включить звук ошибки

byte matrix[8] = {0b10000000,                 //  Начальное изображение на матрице
                  0b00000000,                 
                  0b00100000,              
                  0b00000000,                  
                  0b10000000,                 
                  0b00000000,                 
                  0b00100000,                
                  0b00000000}; 
void setup(){                    
  delay(500);
  bum.begin();                                //  Инициируем работу с бампером (датчиком линии)
  disp.begin();                               //  Инициируем работу с дисплеем
  randomSeed(analogRead(A2));                 //  Выбираем случайную точку в последовательности чисел
}
void loop() { 
  uint16_t sensMax = 0;                       //  Максимальное из считанных значений с бампера
  for (uint8_t i = 2; i <= 7; i++){           //  Проходим по всем датчикам бампера с 2 по 7
    if (sensMax < bum.getLineAnalog(i)){      //  Ищем большее значение 
      sensMax = bum.getLineAnalog(i);         
      sensNum = i;                            //  Записываем номер датчика, который регистрирует максимальное значение
    }
  }
  switch (sensNum){                           // В зависимости от номера максимума (там, где находится палец), выбираем рисунок нижней строки
    case 2: matrix[7] = 0b00000111; break;                                                                                                                                                     
    case 3: matrix[7] = 0b00001110; break;
    case 4: matrix[7] = 0b00011100; break;
    case 5: matrix[7] = 0b00111000; break;
    case 6: matrix[7] = 0b01110000; break;
    case 7: matrix[7] = 0b11100000; break;
  }
if (timeUpdate + timeFrame <= millis()){      //  Если пришло время обновить матрицу
  timeUpdate = millis();                      //  Записываем время обновления
  for (uint8_t i = 7; i >= 1; i--){           //  Проходимся по строкам массива с пикселями снизу вверх (от 7 до 1)
    if (i==7) matrix[7] |= matrix[6];         //  Если 7 строка (там, где находится игрок), "накладываем" изображение строки игрока на строку  с летящим пикселем (операция "Логическое ИЛИ")
    else matrix[i] = matrix[i-1];             //  Для всех остальных строк: сдвигаем все вниз на 1
  }
  par = par + 1;                              //  Увеличиваем число, обозначающее чётность на 1 
  if (par > 1){                               //  Если строка четная
    par = 0;                                  //  Обнуляем значение
    uint8_t rnd = random(1,9);                //  Генерируем случайное число от 1 до 8
    switch (rnd){                             //  В зависимости от числа отрисовываем пиксель на первой строке 
      case 1: matrix[0] = 0b00000001; break;
      case 2: matrix[0] = 0b00000010; break;
      case 3: matrix[0] = 0b00000100; break;
      case 4: matrix[0] = 0b00001000; break;
      case 5: matrix[0] = 0b00010000; break;
      case 6: matrix[0] = 0b00100000; break;
      case 7: matrix[0] = 0b01000000; break;
      case 8: matrix[0] = 0b10000000; break;
    }
  }
  else matrix[0] = 0b00000000;                //  Если строка нечётная, рисуем пустую строку
                                              //  Если на строке должен быть пиксель и на последней строке находится только игрок (значит, пиксель "упал" на игрока)
  if (par == 1 && (matrix[7] == 0b00000111 || matrix[7] == 0b00001110 || matrix[7] == 0b00011100 || matrix[7] == 0b00111000 || matrix[7] == 0b01110000 || matrix[7] == 0b11100000)){
    soundBad = true;                          //  Флаг звука проигрыша
    if (timeFrame < 800) timeFrame = timeFrame + 40;  // Увеличиваем время (уменьшаем скорость), если оно меньше максимального
    score = 0;                                //  Сбрасываем заработанные очки
  }
  else {                                      //  Иначе, если пиксель не попал в игрока
    score = score + 1;                        //  Увеличиваем очки
    if (score >= 20 && timeFrame >= 100){     //  Если 20 раз подряд попаданий в игрока не было
      score = 0;                              //  Обнуляем очки
      timeFrame = timeFrame - 20;             //  Уменьшаем время (увеличиваем скорость игры)
      tone (6, 400, 200);                     //  Издаём звук "Новый уровень"
    }}}
  disp.drawImage(matrix);                     //  Обновляем картинку на матрице
  if (soundBad){                              //  Если флаг звука проигрыша равен true
    tone(6, 150, 100);                        //  Издаём звук
    soundBad = false;                         //  Меняем флаг
    soundTime = millis();                     //  Записываем время звука
    secondTimeFlag = true;                    //  Записываем флаг, обозначающий, что нужен повторный звук
  }
  if (secondTimeFlag && soundTime + 150 <= millis()){ // Если secondTimeFlag = true и прошло 150мс тишины после первого звука
    secondTimeFlag = false;                   //  Флаг secondTimeFlag = false
    tone(6, 150, 100);                        //  Издаём звук
  }
delay(20);                                    //  Задержка для стабильности работы (если её не ставить, игрок будет заметно мерцать из-за частого обновления матрицы
}
Поздравляю с изучением данного урока!
Следующий урок:
№19. Что такое ПИД-регулятор.
приступить к изучению

Продукт в магазине

«ROBORACE» — Образовательный набор на базе Arduino

В магазин

Обсуждение

Гарантии и возврат. Используя сайт, Вы соглашаетесь с условиями.