Вторая часть урока по написанию увлекательной игры на Ардуино
Сегодня у нас, вторая (заключительная) часть пятого урока. Напоминаю, что пятый урок посвящен написанию игры Пинг-понг на Arduino. Первая часть урока находится здесь . Повторить этот урок могут владельцы любого из наборов серии «Дерзай» («Базовый», «Изучаем Arduino« и «Умный дом»).
Напоминаем список деталей :
- Arduino Uno;
- Кабель USB;
- Плата прототипирования;
- Провода «папа-папа» — 20 шт;
- Резисторы 220 Ом – 8 шт;
- Светодиоды – 8 шт;
- Кнопка – 2 шт;
- Резисторы 10 кОм – 2 шт;
- Потенциометр.
И схему (показана на рисунке 1).
Рисунок 1. Схема соединений
Еще раз о самой игре. В игре участвует 2 игрока. На поле (8 светодиодов) движется «шарик» (горящий светодиод) от одного края к другому. По достижению «стены» (крайнего положения поля (1 и 8 светодиод )) шарик отражается от «стены» и движется в противоположном направлении. «Шарик» меняет направление движения также при попаданию в «ракетку» игрока («ракетка» появляется на поле (2 и 7 светодиод) при нажатии игроком своей кнопки (при нажатии загорается светодиод) и исчезает при отжатии кнопки). Кнопка может быть нажата не более определенного времени, по прошествии которого «ракетка» исчезает с поля, для установки «ракетки» на поле снова требуется нажатие игроком кнопки. Если шарик не отбит «ракеткой» игрока, он попадает в одно из крайних положений и фиксируется гол.
Цель игры – забить больше голов. Игра продолжается до достижения определенного счета. Скорость движения «шарика» будем устанавливать в соответствии с показаниями потенциометра.
В программе 4 режима:
0 — ожидание начала игры.
1 — движение мячика;
2 — индикация ГОЛ — мигание 2 сек;
3 — индикация победителя;
В первой части урока мы написали скетч движения шарика и индикации гола.
В этой части урока мы допишем остальной функционал скетча.
Добавим действия игроков – нажатие на клавиши. Здесь необходимо реализовать функционал для трех ситуаций для двух кнопок:
for(int i=0;i<COUNT_BUTTONS;i++) { currentbuttons[i] = debounce(lastbuttons[i],pinbuttons[i]); // проверка нажатие ………………….. // проверка удерживание нажатой клавиши ………………….. // проверка отжатие клавиши ………………….. lastbuttons[i] = currentbuttons[i]; } нажатие кнопки – флаг установки ракетки и визуализация ракетки: светодиод 1 для 1 игрока, светодиод 6 для второго игрока (напоминаем, что нумерация светодиодов от 0 до 7); // проверка нажатие currentbuttons[i] = debounce(lastbuttons[i],pinbuttons[i]); if (lastbuttons[i] == 0 && currentbuttons[i] == 1) // если нажатие... { // реакция на нажатие if((millis()-alltimepressing[i]>=TIME_UNPRESSING) && pressing[i]==false)
{
alltimepressing[i]=millis();
pressing[i]=true;
}
}
отжатие кнопки – флаг сброса ракетки:
// проверка отжатие клавиши
if (lastbuttons[i] == 1 && currentbuttons[i] == 0) // если отжатие...
{
// реакция на отжатие
alltimepressing[i]=millis();
pressing[i]=false;
}
контроль времени нажатия кнопки – при превышении времени нажатия TIME_PRESSING флаг установки ракетки сбрасывается и для установки ракетки требуется повторное нажатие кнопки, но не раньше времени TIME_UNPRESSING:
// проверка удерживание нажатой клавиши
if (lastbuttons[i] == 1 && currentbuttons[i] == 1) // если нажатие...
{
if((millis()-alltimepressing[i]>=TIME_PRESSING) && pressing[i]==true)
{
alltimepressing[i]=millis();
pressing[i]=false;
}
}
Необходимо запрограммировать результат столкновения ракетки с шариком, при котором шарик меняет направление движения на противоположное:
if(res==1)
{
if((millis()-millisgoball)>=speedball)
{
posball=posball+dirball;
// гол
……….
// гол
……….
// столкновение
else if(posball==1 && pressing[0]==true)
{dirball=1;}
// столкновение
else if(posball==6 && pressing[1]==true)
{dirball=-1;}
millisgoball=millis();
// определение скорости движения мячика
speedball=map(analogRead(POT),0,1023,MAX_SPEEDBALL,MIN_SPEEDBALL);
}
setleds(posball); //установка светодиодов
}
При событии ГОЛ подсчитываем голы для каждого игрока, как только один из игроков забьет COUNTS_END голов, наступает конец игры (программа переходит в режим 3, а после индикации победителя – в режим 0 (ожидание начала игры – нажатие любой кнопки)).
Создадим в Arduino IDE новый скетч, занесем в него код из листинга 1 и загрузим скетч на на плату Arduino. Напоминаем, что в настройках Arduino IDE необходимо выбрать тип платы (Arduino UNO) и порт подключения платы.
Листинг 1
// количество кнопок #define COUNT_BUTTONS 2 // количество светодиодов #define COUNT_LEDS 8 // Аналоговый вход A0 для подключения потенциометра const int POT=0; // переменная для хранения значения потенциометра int valpot = 0; // условная единица мсек/1 шкалы int valscale=1000;
// Выводы Arduino для подключения
// список светодиодов
int pinleds[8]={4,5,6,7,8,9,10,11};
// переменная для хранения времени нажатия мсек
unsigned long alltimepressing[2]={0,0};
// переменная для хранения позиции, мячика
int posball=0;
// направление движения мячика
int dirball=1;
// список кнопок
int pinbuttons[2]={2,3};
// список сохранения предыдущих состояний кнопок
int lastbuttons[2]={0,0};
// список сохранения текущих состояний кнопок
int currentbuttons[2]={0,0};
// состояние кнопки
boolean pressing[2]={false,false};
#define TIME_PRESSING 1000
#define TIME_UNPRESSING 500
// режим программы
// 0 - ожидание начала игры
// 1 - движение мячика
// 2 - индикация ГОЛ - мигание 3 сек
// 3 - индикация ПОБЕДА - мигание половины победителя
int res=1;
// скорость движения мячика
unsigned long speedball=0;
unsigned long millisgoball=0;
#define MIN_SPEEDBALL 1000
#define MAX_SPEEDBALL 250
// служебная для мигания гола
unsigned long millisres2=0;
#define TIME_RES2 2000
unsigned long millisblinkres2=0;
boolean blinkres2=true;
#define TIME_BLINK_RES2 200
// счет
int counts[2]={0,0};
#define COUNTS_END 5
void setup()
{
Serial.begin(9600);
// настроить выводы Arduino для светодиодов как выходы
for(int i=0;i<COUNT_LEDS;i++)
{
pinMode(pinleds[i], OUTPUT);
digitalWrite(pinleds[i],LOW);
}
Serial.println("start");
setleds(posball);
}
void loop()
{
// проверка нажатия/отжатия/удерживания кнопок
for(int i=0;i<COUNT_BUTTONS;i++) { // проверка нажатие currentbuttons[i] = debounce(lastbuttons[i],pinbuttons[i]); if (lastbuttons[i] == 0 && currentbuttons[i] == 1) // если нажатие... { // реакция на нажатие Serial.print("press=");Serial.println(i); if(res==0) {res=1;posball=0;dirball=1; pressing[0]=false;pressing[1]=false; } if((millis()-alltimepressing[i]>=TIME_UNPRESSING) && pressing[i]==false)
{
alltimepressing[i]=millis();
pressing[i]=true;
}
}
// проверка удерживание нажатой клавиши
if (lastbuttons[i] == 1 && currentbuttons[i] == 1) // если нажатие...
{
if((millis()-alltimepressing[i]>=TIME_PRESSING) && pressing[i]==true)
{
alltimepressing[i]=millis();
pressing[i]=false;
}
}
// проверка отжатие клавиши
if (lastbuttons[i] == 1 && currentbuttons[i] == 0) // если отжатие...
{
// реакция на отжатие
Serial.print("un_press=");Serial.println(i);
alltimepressing[i]=millis();
pressing[i]=false;
}
lastbuttons[i] = currentbuttons[i];
}
// движение мячика
if(res==1)
{
if((millis()-millisgoball)>=speedball)
{
posball=posball+dirball;
// гол
if(posball6 && pressing[1]==false)
{
res=2;
posball=7;dirball=-1;
millisres2=millis();millisblinkres2=millis();
blinkres2=true;
counts[0]++;
if(counts[0]==COUNTS_END)
res=3;
}
// столкновение
else if(posball==1 && pressing[0]==true)
{dirball=1;}
// столкновение
else if(posball==6 && pressing[1]==true)
{dirball=-1;}
millisgoball=millis();
// определение скорости движения мячика
speedball=map(analogRead(POT),0,1023,MAX_SPEEDBALL,MIN_SPEEDBALL);
}
setleds(posball);
}
// ГОЛ !!! - blink
if(res==2)
{
if(millis()-millisblinkres2>=TIME_BLINK_RES2)
{
blinkres2=!blinkres2;
digitalWrite(pinleds[posball],blinkres2);
millisblinkres2=millis();
}
if(millis()-millisres2>=TIME_RES2)
{
digitalWrite(pinleds[posball],HIGH);
res=1;
}
}
// ПОБЕДА - конец игры
if(res==3)
{
setledsvictory();
delay(5000);
counts[0]=0;counts[1]=0;
// выключение светодиодов всех
for(int i=0;i<8;i++)
digitalWrite(pinleds[i],LOW);
res=0;
}
//Serial.print("res=");Serial.println(res);
//Serial.print("posball=");Serial.println(posball);
}
// (включение-выключение светодиодов)
void setleds(int pos)
{
// выключение светодиодов всех
for(int i=0;i<8;i++)
digitalWrite(pinleds[i],LOW);
// включение светодиода позиции мячика
digitalWrite(pinleds[pos],HIGH);
if(pressing[0]==true)
digitalWrite(pinleds[1],HIGH);
if(pressing[1]==true)
digitalWrite(pinleds[6],HIGH);
}
// ПОБЕДА (включение-выключение светодиодов 0-3 или 4-7)
void setledsvictory()
{
// выключение светодиодов всех
for(int i=0;i<8;i++) digitalWrite(pinleds[i],LOW); if(counts[0]>counts[1])
{
// победитель - игрок 1
for(int i=0;i<4;i++)
digitalWrite(pinleds[i],HIGH);
}
else
{
// победитель - игрок 2
for(int i=4;i<8;i++)
digitalWrite(pinleds[i],HIGH);
}
}
/* Функция сглаживания дребезга
* Принимает в качестве аргумента предыдущее состояние кнопки,
* и выдает фактическое.
*/
int debounce(int last,int pin1)
{
int current = digitalRead(pin1); // Считать состояние кнопки
if (last != current) // если изменилось...
{
delay(5); // ждем 5мс
current = digitalRead(pin1); // считываем состояние кнопки
return current; // возвращаем состояние кнопки
}
}
После загрузки скетча можем приступить к игре(см. рисунок 2,3,4).


Рисунок 2,3,4. Играем

Книга Джереми Блума Изучаем Arduino: инструменты и методы технического волшебства.
25 крутых проектов с Arduino
Мобильные роботы на базе Arduino книга М. Момота
Добавить комментарий
Для отправки комментария вам необходимо авторизоваться.