Игра на LCD Keypad Shield D1robot и Arduino UNO , делаем простую игру на ардуино

Приехал мне из китая вот такой удобный ЛСД шилд для ардуино Уно , но так же он подходит и для версии MEGA .

Шил по сути удобная платформа с дисплеем 1602 и 6ю кнопками для подключения к ардуино - Бутербродом . 

Все это легко монтируется , как я раньше без него то жил ? 

Купить платы можно на Алиэкспресс :

Шилд с дисплем 1602 http://ali.pub/27eri3  

Альтернативная ссылка http://ali.pub/27erju  

Arduino UNO http://ali.pub/27ernq  

Альтернативная ссылка http://ali.pub/27erls  

 Для начала нужно залить скетч игры в вашу плату ардуино и настроить контрастность дисплея , а для игры необходимо нажать кнопку SELECT.

 


Функционал кнопок:

• UP - движение вверх

• DOWN - движение вниз

• RIGHT - ускорение

• LEFT - пауза

• SELECT - продолжить игру (пауза), старт новой игры

 


Для динамики игры, помимо ручного ускорения, каждые 5 секунд происходит программное увеличение скорости звездолета. На 25 секунде включается максимальная сложность "UNREAL" и скорость больше не растет.

После каждой игры на дисплее высвечивается время текущей игры, а также время лучшей попытки.

Сам код , работает на любой версии Ардуино ИДЕ 

#include <Wire.h> 
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7 );

// Количество позиций в ширину дисплея
const int FIELD_WIDTH = 16;
// Вероятность возникновения препятствия (5 из 10) 50%
const float BAR_PROBABILITY = 5; 

// Нажатая клавиша
int button;
const int BUTTON_NONE   = 0;
const int BUTTON_RIGHT  = 1;
const int BUTTON_UP     = 2;
const int BUTTON_DOWN   = 3;
const int BUTTON_LEFT   = 4;
const int BUTTON_SELECT = 5;

// Состояния игры
int gameStatus;
const int MAIN_MENU = 0; // Главное меню
const int IN_GAME   = 1; // Игра
const int PAUSE     = 2; // Пауза
const int ENDING    = 3; // Конец

// Отображаемые символы
char gameFields[32];     // Игровое поле
const char SPACE = ' ';  // Пустая клетка
const char BAR = '|';    // Препятствие
const char PLAYER = '>'; // Игрок

// Игровая скорость, чем меньше параметры тем выше скорость
int gameSpeed;
int SPEED_HIGH = 70;     // Скорость ускорения
int SPEED_NORMAL = 300;  // Изначальная скорость
int changeSpeed = 5000;  // Интервал изменения скорость (5 сек.)

long startGameTime;      // Время начала игры
long lastMovementTime;   // Последнее время обновления дисплея
long lastChangeSpeedTime;// Последнее время изменения скорости
long endGameTime;        // Время окончания игры
long bestGameTime;       // Лучшее время
int topQueue = true;     // Параметр для алгоритма расстановки препятствий

// Функция возвращает какая кнопка была нажата
int getPressedButton()
{
  int buttonValue = analogRead(0);
  if (buttonValue < 100) {
    return BUTTON_RIGHT;
  }
  else if (buttonValue < 200) {
    return BUTTON_UP;
  }
  else if (buttonValue < 400){
    return BUTTON_DOWN;
  }
  else if (buttonValue < 600){
    return BUTTON_LEFT;
  }
  else if (buttonValue < 800){
    return BUTTON_SELECT;
  }
  return BUTTON_NONE;
}

// Функция начинает новую игру
void startGame()
{
  SPEED_NORMAL = 250; // Устанавливаем скорость
  // Сбрасываем таймеры
  startGameTime = millis();
  lastMovementTime = millis();
  lastChangeSpeedTime = millis();
  endGameTime = 0;
  // Очищаем игровое поле
  for (int i = 0; i < 2*FIELD_WIDTH; i++)
  {
     gameFields[i] = SPACE;
  }
  // Устанавливаем игрока в 1 позицию
  gameFields[0] = PLAYER;
  // Начинаем игру
  gameStatus = IN_GAME;
  // Выводим игровое поле
  printGameField();
}

// Функция выполняет движение игрового поля
void moveGameField()
{
  // Если врезались в препятствие, заканчиваем игру
  if (gameFields[0] == PLAYER && gameFields[1] == BAR ||
      gameFields[FIELD_WIDTH] == PLAYER && gameFields[FIELD_WIDTH+1] == BAR)
  {
    gameOver();
    return;
  } 
  // Вычисляем игровую позицию
  int playerPos = 0;
  if (gameFields[FIELD_WIDTH] == PLAYER)
  {
    playerPos = FIELD_WIDTH;
  }
  // Смещаем позиции
  for (int i = 0; i < FIELD_WIDTH*2; i++)
  {
    if (i != FIELD_WIDTH-1)
    {
      gameFields[i] = gameFields[i+1]; 
    }  
  } 
  gameFields[playerPos] = PLAYER;
  // Вычисляем количество препятствий на строках
  int topBarsCount = 0;
  int bottomBarsCount = 0;
  for (int i = 0; i < FIELD_WIDTH; i++)
  {
    if (gameFields[i] == BAR)
    {
       topBarsCount++; 
    }
  } 
  for (int i = FIELD_WIDTH; i < FIELD_WIDTH*2; i++)
  {
    if (gameFields[i] == BAR)
    {
       bottomBarsCount++; 
    }
  } 
  // Алгоритм установки препятствий в последних клетках дисплея
  // Нельзя допустить заведомо проигрышной ситуации
  // т.е. два препятствия без промежутка для маневра  
  // Также учитываем отсутствие длинных последовательностей препятствий
  if (topQueue)
  {
    // Принимаем решение об установке препятствия в нижней строке
    if (gameFields[FIELD_WIDTH-1] != BAR &&
      gameFields[FIELD_WIDTH-2] != BAR && 
      gameFields[FIELD_WIDTH-3] != BAR &&
      bottomBarsCount < FIELD_WIDTH/2 &&
      random(9) < BAR_PROBABILITY) 
    {
        gameFields[2*FIELD_WIDTH-1] = BAR;
    } else
    {
        gameFields[2*FIELD_WIDTH-1] = SPACE;
    }
    // Принимаем решение об установке препятствия в верхней строке
    if (gameFields[2*FIELD_WIDTH-1] != BAR && 
        gameFields[2*FIELD_WIDTH-2] != BAR && 
        gameFields[2*FIELD_WIDTH-3] != BAR && 
        topBarsCount < FIELD_WIDTH/2 &&
        random(9) < BAR_PROBABILITY) 
    {
        gameFields[FIELD_WIDTH-1] = BAR;
    } else
    {
        gameFields[FIELD_WIDTH-1] = SPACE;
    }
    topQueue = false;
  } else
  {
    // Принимаем решение об установке препятствия в верхней строке
    if (gameFields[2*FIELD_WIDTH-1] != BAR && 
        gameFields[2*FIELD_WIDTH-2] != BAR && 
        gameFields[2*FIELD_WIDTH-3] != BAR && 
        topBarsCount < FIELD_WIDTH/2 &&
        random(9) < BAR_PROBABILITY) 
    {
        gameFields[FIELD_WIDTH-1] = BAR;
    } else
    {
        gameFields[FIELD_WIDTH-1] = SPACE;
    }
    // Принимаем решение об установке препятствия в нижней строке
    if (gameFields[FIELD_WIDTH-1] != BAR &&
      gameFields[FIELD_WIDTH-2] != BAR && 
      gameFields[FIELD_WIDTH-3] != BAR &&
      bottomBarsCount < FIELD_WIDTH/2 &&
      random(9) < BAR_PROBABILITY) 
    {
        gameFields[2*FIELD_WIDTH-1] = BAR;
    } else
    {
        gameFields[2*FIELD_WIDTH-1] = SPACE;
    }
    topQueue = true; 
  }
  
}

// Функция завершения игры
void gameOver()
{
  gameStatus = ENDING;
  // Рассчитываем время игры
  endGameTime += (millis() - startGameTime);
  // Сравниваем с лучшим
  if (endGameTime > bestGameTime)
  {
     bestGameTime = endGameTime; 
  }
  // Вычисляем позицию игрока
  int playerPos = 0;
  if (gameFields[FIELD_WIDTH] == PLAYER)
  {
    playerPos = FIELD_WIDTH;
  }  
  // Анимация проигрыша
  lcd.setCursor(playerPos%FIELD_WIDTH, playerPos/FIELD_WIDTH);
  lcd.print('x');
  delay(300); 
  lcd.setCursor(playerPos%FIELD_WIDTH, playerPos/FIELD_WIDTH);
  lcd.print('X');
  delay(300); 
  lcd.setCursor(playerPos%FIELD_WIDTH, playerPos/FIELD_WIDTH);
  lcd.print('x');
  delay(300); 
  lcd.setCursor(playerPos%FIELD_WIDTH, playerPos/FIELD_WIDTH);
  lcd.print('X');
  delay(300);
  lcd.setCursor(playerPos%FIELD_WIDTH, playerPos/FIELD_WIDTH);
  lcd.print('x');
  delay(300); 
  lcd.setCursor(playerPos%FIELD_WIDTH, playerPos/FIELD_WIDTH);
  lcd.print('X');
  delay(300);
  // Очищаем дисплей
  lcd.setCursor(0, 0);  
  lcd.print("                ");
  lcd.setCursor(0, 1);   
  lcd.print("                ");
  lcd.setCursor(0, 0);        
  // Выводим статистику
  lcd.print("Last time:");
  lcd.print(endGameTime/1000);   
  lcd.print(" sec");     
  lcd.setCursor(0, 1);              
  lcd.print("Best time:");  
  lcd.print(bestGameTime/1000);  
  lcd.print(" sec"); 
}

// Функция печати игрового поля
void printGameField()
{
  for (int i = 0; i < FIELD_WIDTH*2; i++)
  {
     lcd.setCursor(i%FIELD_WIDTH, i/FIELD_WIDTH);
     lcd.print(gameFields[i]);    
  }
}

// Функция паузы
void pause()
{
  // Очищаем дисплей
  lcd.setCursor(0, 0);  
  lcd.print("                ");
  lcd.setCursor(0, 1);   
  lcd.print("                ");
  lcd.setCursor(0, 0);        
  // Выводим служебное сообщение 
  lcd.print("Paused");       
  lcd.setCursor(0, 1);              
  lcd.print("press SELECT"); 
  gameStatus = PAUSE;
  // Во время паузы не считаем игровое время
  endGameTime += (millis()-startGameTime);
}

void setup()
{
  gameStatus = MAIN_MENU;
  button = BUTTON_NONE;
  bestGameTime = 0;
  
  // Анимация первой загрузки
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("GEEK Game ");
  lcd.setCursor(0, 1);   
  lcd.print("          >  | ");
  delay(600);
  lcd.setCursor(0, 0);
  lcd.print("                ");
  lcd.setCursor(0, 1);   
  lcd.print("                ");
  delay(400);
  lcd.setCursor(0, 0);
  lcd.print("GEEK Game ");
  lcd.setCursor(0, 1);   lcd.print(" > | ");   delay(600);   lcd.setCursor(0, 0);   lcd.print(" ");   lcd.setCursor(0, 1);   lcd.print(" ");   delay(400);   lcd.setCursor(0, 0);   lcd.print("GEEK Game ");
  lcd.setCursor(0, 1);   lcd.print(" > | ");   delay(600);   lcd.setCursor(0, 0);   lcd.print(" ");   lcd.setCursor(0, 1);   lcd.print(" ");   delay(600);   // Служебное сообщение   lcd.setCursor(0, 0);   lcd.print("press SELECT");   lcd.setCursor(0, 1);   lcd.print("and start game "); } void loop() {   // Вычисляем нажатую клавишу   button = getPressedButton();   switch (gameStatus)   {      case MAIN_MENU:        // Из меню возможен переход на начало игры        // по нажатию на SELECT        if (button == BUTTON_SELECT)        {           startGame();        }        break;      case IN_GAME:        // Устанавливаем стандартную скорость        gameSpeed = SPEED_NORMAL;        switch (button)        {           // Ускорение           case BUTTON_RIGHT:             gameSpeed = SPEED_HIGH;             break;           // Пауза           case BUTTON_LEFT:             pause();             break;           // Перемещение в верхнюю строку           case BUTTON_UP:             if (gameFields[0] == BAR)             {                gameOver();              } else             {               gameFields[0] = PLAYER;               if (gameFields[FIELD_WIDTH] == PLAYER)               {                 gameFields[FIELD_WIDTH] = SPACE;               }             }             break;           // Перемещение в нижнюю строку           case BUTTON_DOWN:             if (gameFields[FIELD_WIDTH] == BAR)             {                gameOver();              } else             {               gameFields[FIELD_WIDTH] = PLAYER;               if (gameFields[0] == PLAYER)               {                 gameFields[0] = SPACE;               }             }             break;        }        // Если прошло время отрисовки, рисуем поле        if (millis() - lastMovementTime > gameSpeed)        {           lastMovementTime = millis();           moveGameField();          }        // Если прошло время изменения скорости, изменяем        if (millis() - lastChangeSpeedTime > changeSpeed)        {           lastChangeSpeedTime = millis();           SPEED_NORMAL -= 40;           // Предельная скорость           if (SPEED_NORMAL < 50)           {             SPEED_NORMAL = 50;             SPEED_HIGH = 50;            }        }        // Печатаем игровое поле, если не перешли в другой режим        if (gameStatus == IN_GAME)          printGameField();        break;      case PAUSE:        // Продолжаем игру по нажатию на SELECT        if (button == BUTTON_SELECT)        {          gameStatus = IN_GAME;          startGameTime = millis();        }          break;      case ENDING:        // По любому нажатию переходим в главное меню        if (button != BUTTON_NONE)        {          lcd.setCursor(0, 0);          lcd.print(" ");          lcd.setCursor(0, 1);          lcd.print(" ");          lcd.setCursor(0, 0);          lcd.print("To start game");          lcd.setCursor(0, 1);          lcd.print("press SELECT");          gameStatus = MAIN_MENU;        }          break;   }

}


Подписывайся на Geek каналы :

➤ VK - https://vk.com/denis_geek

➤ VK - https://vk.com/club_arduino

➤ VK - https://vk.com/chinagreat

➤ VK - https://vk.com/solar_pover

➤ VK - https://vk.com/my_vedroid

➤ VK - https://vk.com/3dprintsumy

➤ Youtube - http://www.youtube.com/c/Danterayne



★ Моя партнёрка с Aliexpress ★

http://ali.pub/1j9ks1 

★ Получай 10.5% скидку с любой покупки на Aliexpress! ★

http://ali.pub/1lx67o

★ Полезное браузерное приложение для кэшбэка  ★

Похожие статьи

Сенсорная кнопка и Arduino

Сенсорная кнопка и Arduino

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

Вероятно, многим может показаться, что использовать подобный модуль непросто и периодически придется иметь дело с неожиданным результатом. Что ж, оказывается, что все не так. Сенсорная кнопка отлично справляется с поставленными задачами и не преподносит никаких сюрпризов, хотя стоимость и настораживает.

 Подключение OLED I2C дисплея с размером экрана 0,96″ и разрешением 128*64 точек к плате Arduino UNO.

Подключение OLED I2C дисплея с размером экрана 0,96″ и разрешением 128*64 точек к плате Arduino UNO.

Сегодня мы рассмотрим подключение OLED I2C дисплея с размером экрана 0,96″ и разрешением 128*64 точек к плате Arduino UNO.

Делаем весы на ардуино  Arduino  , работа с тензонометрическим датчиком и платой  HX711

Делаем весы на ардуино Arduino , работа с тензонометрическим датчиком и платой HX711

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

Рекомендуемые товары

Набор полный для обучения Arduino RFID Starter Kit в пластиковом боксе

Набор полный для обучения Arduino RFID Starter Kit в пластиковом боксе

Обучающий набор с модулями радиочастотной идентификации 39 предметов. на базе Arduino Uno R3.Arduino..

900грн.

Arduino nano 328 на базе конвертера ch340

Arduino nano 328 на базе конвертера ch340

Arduino Nano V3.0 - маленькая, самодостаточная, разъемо-совместимая с макетками плата на микрок..

90грн.

Arduino Mega 2560 Ардуино мега Mega2560 R3 ch340 atmel atmega2560  (разъем MICRO USB )

Arduino Mega 2560 Ардуино мега Mega2560 R3 ch340 atmel atmega2560 (разъем MICRO USB )

Arduino Mega построена на микроконтроллере ATmega2560 (техническое описание). Плата имеет 54 ци..

300грн.

Arduino UNO R3 Atmega328  ATmega328P smd AVR Ардуино Уно Р3 с кабелем для подключения USB

Arduino UNO R3 Atmega328 ATmega328P smd AVR Ардуино Уно Р3 с кабелем для подключения USB

На этой платформе стоит точно такой же процессор как и на классической версии, отличие формфактор(ти..

140грн.

Теги: Игра на ардуино, LCD Keypad Shield, D1robot, Arduino UNO, делаем простую игру на ардуино, схема, ардуино, проекты, сделай сам, ардуино игра, arduino game, DIY