Делаем собственный Space Shooter на Arduino

Делаем собственный Space Shooter на Arduino

Практическая Инженерия


Привет всем инженерам нашей группы! В данной статье мы создадим игру по типу «Space Invaders» на Arduino. Суть игры проста: необходимо уничтожать вражеские космические корабли, стреляя в них снарядами, и параллельно уклоняться от вражеских снарядов. За каждое меткое попадание игрок получает очки (в нашей игре это будет 10 очков за попадание, но их количество легко можно поменять в исходном коде).

Дизайн космических кораблей был взят из популярной игры «Blastar», созданной Илоном Маском. Поскольку у вас уже наверняка есть опыт в создании девайсов на Arduino, благодаря предыдущим статьям из цикла, составление hardware-части проекта для вас не будет проблемой. Основная его задача – написание программы с помощью специальных графических библиотек, предоставленных компанией Adafruit, которая разработала графический дисплей в проекте. Этот проект будет хорошей практикой для понимания всех основных процессов в играх и написания игровой механики полностью с нуля без всяких игровых движков и прочего. Ну что ж, приступим к созданию игры!


Компоненты и макет


Необходимые для проекта компоненты:

- Плата Arduino Uno R3;

- Монохромный дисплей OLED 128x64 0.96" от Adafruit;

- 3 тактовых кнопки;

- Немного проводов m-m;


Макет проекта был создан в популярном Open-Source конструкторе макетов и печатных плат Fritzing, очень удобный в разработке и имеет все популярные компоненты в базе. Как вы можете заметить, схема проекта достаточно тривиальная (благодаря стараниям наших братьев инженеров из Adafruit) и схожа с той, что была в предыдущих статьях. Кнопки управления подключены к управляющим входам 12, 8 и 4, которые предварительно задаются в коде и их можно легко сменить при необходимости. Плата связана с дисплеем по шине I2c (IIC - Inter-Integrated Circuit) и передает данные на отображение по двум проводам, один из которых задает частоту передачи, а другой передает все необходимые данные. Такой интерфейс, в сравнении с SPI, занимает меньше выводов МК (на I2c всего 2, а на SPI от 4 до 8), но значительно медленнее в передаче данных. Интерфейс в модели Arduino Uno реализуется по-умолчанию через аналоговые выходы A4 и A5, но на других платах он реализуется по-разному (например, в модели Arduino Pro Micro он реализуется через 2-й и 3-й цифровые выходы).


Макет

Код игры


Полный код игры находится здесь. Для прошивки платы вам необходимо установить на свой компьютер среду разработки Arduino IDE. Также не забудьте скачать необходимые графические библиотеки для работы с дисплеями Adafruit GFX и Color OLED library. Скачав нужные архивы добавьте библиотеки через Меню-Скетч-Подключить библиотеку-Добавить ZIP архив. И в конце выберите в меню Инструменты-Плата модель своей платы и порт и прошейте ее. Если кнопки управления у вас подключены к другим портам, поменяйте номера рядом с LEFT_BUTTON, RIGHT_BUTTON, FIRE_BUTTON на ваши значения. Также вы можете поменять количество очков за каждое попадание рядом с SHOT_POINTS, смещение врагов относительно верхнего края в ENEMIES_Y_OFFSET, и положение вражеских кораблей относительно левого края дисплея в массиве enemiesPositionsX. Остальные параметры и переменные без детального разбора кода лучше не менять, ведь как говорит IT-мудрость: "Работает - не трогай!" ;)



Разбор некоторых компонентов игровой механики

  1. Прорисовка моделей

Все модели космических кораблей прорисованы через bitmap-массивы, где каждый элемент - прорисовка каждой строки. Пиксель будет закрашен если в элементе стоит 1, и не будет если 0. Для каждой модели размерность одинаковая: 8х8. Поскольку рисунок не будет меняться во время игры, объявляем его константой. Для самой прорисовке на экране используется метод display.drawBitmap(x, y, bullet_sprite, 8, 8, 1);

BITMAP для корабля игрока


2. Движение моделей

После каждой прорисовки экран очищается, обновляются позиции всех объектов и рисуются заново. Игрок может двигаться влево и вправо, если он не зашел за пределы размеров экрана:

if (!digitalRead(LEFT_BUTTON) && players_position > 0) players_position--;
 else if (!digitalRead(RIGHT_BUTTON) && players_position < 120) players_position++;

У врагов движение довольно примитивное: пока первый не столкнулся со стенкой слева или последний со стенкой справа - сохранять направление:

void MoveEnemies(int enemies_positions[])
{
 if (enemies_positions[FindFirstNonNull(enemies_positions)] < 4)
  enemies_direction = 1;
 else if (enemies_positions[FindLastNonNull(enemies_positions)] > 116)
  enemies_direction = -1;
 for (int i = 0; i < 5; i++)
 {
  if (enemies_positions[i] > 0)
   enemies_positions[i] += enemies_direction;
 }
}

Все эти данные обновляются в методе прорисовки, показанный выше.


3. Движение снарядов

Поскольку вся игра построена на функциональном программировании, а не на ООП, все данные о снарядах записаны в массив, и если координаты одного из снарядов находятся в пределах координат вражеского корабля, то его данные удаляются с массива и игроку начисляются очки:


if (is_bullets_spawned)  
  {
   if (bullet_position_y > 0)
    bullet_position_y--;
    else
    is_bullets_spawned = false;

   if (IsHittingEnemy(enemiesPositionsX, bullet_position_x) != -1 && (bullet_position_y <= ENEMIES_Y_OFFSET + 8 && bullet_position_y >= ENEMIES_Y_OFFSET))
   {
    enemiesPositionsX[IsHittingEnemy(enemiesPositionsX, bullet_position_x)] = -24;
    is_bullets_spawned = false;
    players_score += SHOT_POINTS;
   }
    
   DrawPlayersBullet(bullet_position_x, bullet_position_y);
   DrawPlayersBullet(bullet_position_x + 5, bullet_position_y);
  }


Если на поле врагов не осталось, массив будет перезаписан в начальное состояние:

if (AllEnemiesAreDead(enemiesPositionsX))
 {RespawnEnemies();}


void RespawnEnemies()
{
  enemiesPositionsX[0] = 24;
  enemiesPositionsX[1] = 40;
  enemiesPositionsX[2] = 56;
  enemiesPositionsX[3] = 72;
  enemiesPositionsX[4] = 88;
}



Готовый результат


Вот так выглядит готовая игра. Увы, из-за ограничения 5МБ на изображения показаны лишь пару секунд игрового процесса, тем не менее вы сможете собрать игру самостоятельно и оценить ее! Также можно собрать все эти детали в красивый корпус или добавить звуковое сопровождение с помощью пьезодинамика, но это мы уже оставляем на вас, как дополнительное задание. Приятной вам игры! Если желаете поделиться впечатлениями или дополнениями к проекту:@izengineer_bot


Report Page