Вторая часть урока по написанию увлекательной игры на Ардуино
Сегодня у нас, вторая (заключительная) часть пятого урока. Напоминаю, что пятый урок посвящен написанию игры Пинг-понг на 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. Играем
Добавить комментарий
Для отправки комментария вам необходимо авторизоваться.