Cat hungry.png
Здравствуйте! Собираем деньги на перевод материалов по электронике(https://www.allaboutcircuits.com/education/). Реквизиты указаны здесь.

Arduino:Примеры/EsploraPong

Материал из Онлайн справочника
Перейти к: навигация, поиск

Перевод: Максим Кузьмин (Cubewriter)
Перевел 2686 статей для сайта.

Контакты:

Проверка/Оформление/Редактирование: Мякишев Е.А.


Игра в Pong с помощью Esplora[1]

А не хотите ли поиграть с помощью Esplora в Pong? Этот пример покажет как.

Он создан, чтобы работать в паре со скетчем Processing (это язык программирования с открытым кодом). Esplora считывает данных со своих кнопок и слайдера, а затем через последовательный порт отправляет данные скетчу Processing, а он, в свою очередь использует их для перемещения «рокеток» в Pong.

Если Processing на вашем компьютере нет, его можно загрузить с сайта Processing, а затем установить, следуя руководству по инсталляции.

Скетч Processing к этому примеру можно скачать по этой ссылке(также с кодом можно ознакомиться ниже).

Вам нужно лишь распаковать этот фал в папке скетчей Processing, а затем открыть саму Processing и запустить там нужный файл с расширением *.pde.

Необходимое оборудование

  • Плата Arduino Esplora;

Необходимое ПО

Цепь

Для этого примера нужна лишь плата Arduino Esplora.

Esplora Pong.png

Элементы Esplora, необходимые для этого примера – кнопки и линейный потенциометр

Код для Arduino

Этот пример отправляет на компьютер данные о позиции слайдера линейного потенциометра и состоянии трех кнопок. Processing-скетч, связанный с этим Esplora-скетчем, считывает эти данные, чтобы управлять «рокетками» и другими элементами игры Pong.

Данные всегда отправляются в таком порядке: слайдер, 1-ая кнопка, 3-тья кнопка, 4-ая кнопка. Кроме того, эти данные разделены запятыми. Функция Serial.printIn() отправляет данные о последней кнопке, завершая их символом новой строки. Processing-скетчу этот символ нужен для того, чтобы знать, что он получил все необходимые данные от датчиков.

ПРИМЕЧАНИЕ: Одновременно к последовательным портам компьютера может иметь доступ только одна программа. То есть, если у вас открыт Serial Monitor, то скетчу Processing к последовательному порту Esplora доступ будет закрыт. Точно также, при запущенном скетче Processing открыть Serial Monitor и перепрограммировать Esplora будет нельзя.

  1. /*
  2.  
  3. Игра в Pong с помощью Esplora
  4.  
  5. Этот скетч через последовательный порт подключается к скетчу Processing,
  6. чтобы сделать Esplora контроллером для игры в Pong.
  7. Он передает скетчу Processing информацию о позиции слайдера и состояниях трех кнопок Esplora.
  8. Эти данные отделены друг от друга запятыми.
  9. Скетч Processing использует эти данные, чтобы управлять имеющейся в нем графикой.
  10.  
  11. Слайдер отвечает за высоту «рокетки»,
  12. кнопка 1 перезагружает игру,
  13. кнопка 2 ставит мячик в центр,
  14. кнопка 3 меняет игрока.
  15.  
  16. В эту игру можно играть и на одной, и на двух Esplora.
  17.  
  18. Создан 22 декабря 2012 Томом Иго (Tom Igoe).
  19.  
  20. Этот код не защищен авторским правом.
  21.  
  22. */
  23.  
  24. #include <Esplora.h>
  25.  
  26. void setup() {
  27.   Serial.begin(9600);     // инициализируем последовательную передачу данных
  28. }
  29.  
  30. void loop() {
  31.   // Считываем данные от слайдера и трех кнопок
  32.   int slider = Esplora.readSlider();
  33.   int resetButton = Esplora.readButton(SWITCH_1);
  34.   int serveButton = Esplora.readButton(SWITCH_3);
  35.   int switchPlayerButton = Esplora.readButton(SWITCH_4);
  36.  
  37.   Serial.print(slider);                // выводим на Serial Monitor данные от слайдера
  38.   Serial.print(",");                   // добавляем запятую
  39.   Serial.print(resetButton);           // выводим данные от перезагружающей кнопки
  40.   Serial.print(",");                   // добавляем еще запятую
  41.   Serial.print(serveButton);           // выводим данные от кнопки, ставящей мячик в центр экрана
  42.   Serial.print(",");                   // добавляем еще запятую
  43.   Serial.println(switchPlayerButton);  // выводим данные от последней кнопки плюс символ новой строки
  44.   delay(10);                           // делаем задержку перед тем, как отправлять следующую порцию данных
  45. }

Код для Processing

ProcessingPong.pde

  1. /*
  2. Скетч к Processing для игры в Pong
  3.  
  4. Этот скетч принимает через последовательный порт входящие данные
  5. от одной или двух плат Esplora, тем самым позволяя играть в Pong.
  6. «Эсплоры» пересылают скетчу четыре значения, разделенных запятыми
  7. и заканчивающихся переводом строки.
  8.  
  9. Это значения от четырех устройств ввода:
  10. * слайдера (отвечает за ход «ракетки» вверх-вниз),
  11. * кнопки номер 1 (перезагружает игру),
  12. * кнопки номер 2 (ставит мячик в центр),
  13. * кнопки номер 3 (меняет игроков местами).
  14.  
  15. Эти значения отсылаются скетчу Processing при помощи Arduino-скетча
  16. под названием «Игра в Pong с помощью Esplora» (EsploraPong).
  17.  
  18. Чтобы начать игру, выберите номер порта (портов) Esplora.
  19.  
  20. Создан 22 декабря 2012 Томом Иго (Tom Igoe).
  21.  
  22. Этот код не защищен авторским правом.
  23.  */
  24.  
  25.  
  26. import processing.serial.*;              // импортируем библиотеку Serial
  27. import java.awt.Rectangle;               // импортируем Java-класс Rectangle
  28.  
  29. Serial[] EsploraList = new Serial[2];    // список девайсов, коммуникация с которыми будет осуществляться при помощи последовательного порта
  30. int portCount = 0;                       // количество инициализированных последовательных портов
  31. String portNumber = "";                  // строка, обозначающая следующий порт, который будет инициализирован
  32.  
  33. Rectangle leftPaddle, rightPaddle;       // прямоугольники, играющие роль «ракеток»
  34.  
  35. int resetButton = 1;              // значение для кнопки сброса
  36. int serveButton = 1;              // значение для кнопки, которая ставит мячик в центр экрана
  37. int switchSidesButton = 1;        // значение для кнопки, меняющей игроков местами
  38. int paddleHeight = 50;            // вертикальный размер «ракетки»
  39. int paddleWidth = 10;             // горизонтальный размер «ракетки»
  40.  
  41. int ballSize = 10;     // размер мячика
  42. int xDirection = 2;    // для перемещения мячика по горизонтали: влево «-2», вправо «2»
  43. int yDirection = 2;    // для перемещения мячика по вертикали: вверх «-2», вниз «2»
  44. int xPos, yPos;        // вертикальная и горизонтальная позиция мячика
  45.  
  46. boolean ballInMotion = false;  // должен ли мячик двигаться или нет
  47.  
  48. int leftScore = 0;      // счетчик очков для игрока слева
  49. int rightScore = 0;     // счетчик очков для игрока справа
  50.  
  51. int fontSize = 20;      // размер шрифтов на экране
  52. void setup() {
  53.   size(640, 480);       // размер для экрана программы
  54.  
  55.   // Инициализируем «ракетки»:
  56.   leftPaddle = new Rectangle(50, height/2, paddleWidth, paddleHeight);
  57.   rightPaddle = new Rectangle(width-50, height/2, paddleWidth, paddleHeight);
  58.  
  59.   // Делаем так, чтобы у рисуемых нами фигур не было контура:
  60.   noStroke();
  61.  
  62.   // Инициализируем мячик в центре экрана:
  63.   xPos = width/2;
  64.   yPos = height/2;
  65.  
  66.   // Создаем шрифт. Это будет третий шрифт, доступный системе:
  67.   PFont myFont = createFont(PFont.list()[2], fontSize);
  68.   textFont(myFont);
  69. }
  70.  
  71.  
  72. void draw() {
  73.   // Очищаем экран:
  74.   background(0);
  75.   fill(255);
  76.  
  77.   // Если было инициализировано недостаточно портов... :
  78.   if (portCount < 2) {
  79.     // Требуем список последовательных портов:
  80.     String[] portList = Serial.list();
  81.     // Выводим на экране инструкции:
  82.     text("Type the port number of Esplora #" + (portCount+1), 20, 20);  //  "Введите номер порта Esplora #"
  83.     text("(or type enter to finish):", 20, 40);  //  "Или нажмите Enter, чтобы закончить"
  84.  
  85.     // Выводим на экране список портов:
  86.     for (int i = 0; i < portList.length; i++) {
  87.       text("port " + i + ":  " + portList[i], 20, (i+4)*20);
  88.     }
  89.   }
  90.  
  91.   // Если портов достаточно... :
  92.   else {
  93.     // Рисуем первую «ракетку»:
  94.     rect(leftPaddle.x, leftPaddle.y, leftPaddle.width, leftPaddle.height);
  95.     // Рисуем вторую «ракетку»:
  96.     rect(rightPaddle.x, rightPaddle.y, rightPaddle.width, rightPaddle.height);
  97.     // Вычисляем позицию мячика и рисуем его:
  98.     if (ballInMotion == true) {
  99.       animateBall();
  100.     }
  101.  
  102.     // Показываем счетчики очков:
  103.     text(leftScore, fontSize, fontSize);
  104.     text(rightScore, width-fontSize, fontSize);
  105.   }
  106. }
  107.  
  108.  
  109. // Функция serialEvent будет запускаться автоматически всякий раз,
  110. // когда в буфере появятся байты от bufferUntil():
  111. void serialEvent(Serial thisPort) {
  112.   // Считываем значения в буфере последовательного порта:
  113.   String inputString = thisPort.readStringUntil('\n');
  114.  
  115.   // Отрезаем от входящей строки символы возврата строки и перевода строки:
  116.   inputString = trim(inputString);
  117.  
  118.   // Делим входящую строку по запятым и конвертируем результат в целые числа:
  119.   int sensors[] = int(split(inputString, ','));
  120.  
  121.   // Если получили от датчиков все необходимые данные, используем их:
  122.   if (sensors.length == 4) {
  123.     // Если это левая Esplora:
  124.     if (thisPort == EsploraList[0] && EsploraList[0] != null) {
  125.       // подгоняем значения от слайдера к диапазону хода «ракеток»:
  126.       leftPaddle.y = int(map(sensors[0], 0, 1023, 0, height - leftPaddle.height));
  127.     }
  128.     // если это правая Esplora:
  129.     if (thisPort == EsploraList[1] && EsploraList[1] != null) {
  130.       rightPaddle.y = int(map(sensors[0], 0, 1023, 0, height- rightPaddle.height));
  131.     }
  132.     // Если кнопка сброса поменяла свое состояние, сбрасываем очки:
  133.     if (resetButton == 1 && sensors[1] == 0) {
  134.       leftScore = 0;
  135.       rightScore = 0;
  136.       resetBall();
  137.       ballInMotion = true;
  138.     }
  139.     // Сохраняем текущее состояние кнопки сброса для сравнения при следующем считывании:
  140.     resetButton = sensors[1];
  141.  
  142.     // Если кнопка для перемещения мячика в центр экрана поменяла свое состояние,
  143.     // то ставим мячик в центр:
  144.     if (serveButton == 1 && sensors[2] == 0) {
  145.       resetBall();
  146.       ballInMotion = true;
  147.     }
  148.     // сохраняем текущее состояние этой кнопки для сравнения при следующем считывании:
  149.     serveButton = sensors[2];
  150.    
  151.     // Если кнопка смены игроков поменяла свое состояние,
  152.     // то меняем правого и левого игроков местами:
  153.     if (switchSidesButton == 1 && sensors[3] == 0) {
  154.       switchSides();
  155.     }
  156.     // Сохраняем текущее состояние этой кнопки для сравнения при следующем считывании:
  157.     switchSidesButton = sensors[3];
  158.   }
  159. }
  160.  
  161. void animateBall() {
  162.   if (leftPaddle.contains(xPos, yPos) ||    // если позиция мячика внутри левой «ракетки»
  163.   rightPaddle.contains(xPos, yPos)) {       // или если позиция мячика внутри правой «ракетки»
  164.     xDirection = -xDirection;               // реверсируем направление движения мячика по оси X
  165.   }
  166.  
  167.   // Если мячик вышел за пределы экрана слева, засчитываем очки правому игроку:
  168.   if (xPos < 0) {
  169.     rightScore++;
  170.     resetBall();
  171.   }
  172.   // Если мячик вышел за пределы экрана справа, засчитываем очки левому игроку:
  173.   if (xPos > width) {
  174.     leftScore++;
  175.     resetBall();
  176.   }
  177.  
  178.   // Делаем так, чтобы мячик не мог выйти за пределы экрана сверху и снизу:
  179.   if ((yPos <= 0) || (yPos >=height)) {
  180.     // Реверсируем движение мячика по оси Y:
  181.     yDirection = -yDirection;
  182.   }
  183.   // Обновляем позицию мячика:
  184.   xPos = xPos + xDirection;
  185.   yPos = yPos + yDirection;
  186.  
  187.   // Рисуем мячик:
  188.   rect(xPos, yPos, ballSize, ballSize);
  189. }
  190.  
  191. void resetBall() {
  192.   // Ставим мячик в центр:
  193.   xPos = width/2;
  194.   yPos = height/2;
  195. }
  196.  
  197.  
  198.  
  199. void keyReleased() {
  200.   // Если нажат Enter, останавливаем выбор номера порта:
  201.   if (key == ENTER) {
  202.     if (portNumber != "" && portCount < 2) {
  203.       choosePort(int(portNumber));
  204.     }
  205.     portCount++;
  206.   }
  207.  
  208.   // Если пользователь жмет на клавиши от 0 до 9, используем это как выбор номера порта:
  209.   if (key >= '0' && key <= '9') {
  210.     portNumber += key;
  211.   }
  212. }
  213.  
  214. void choosePort(int whichPort) {
  215.   // Получаем название порта из списка последовательных портов:
  216.   String portName = Serial.list()[whichPort];
  217.   // Инициализируем следующую Esplora:
  218.   EsploraList[portCount] = new Serial(this, portName, 9600);
  219.   // Считываем байты в буфер последовательного порта до тех пор,
  220.   // пока не доберемся до символа перевода строки (номер 10 в таблице ASCII):
  221.   EsploraList[portCount].bufferUntil('\n');
  222.   // Очищаем строку с номером порта:
  223.   portNumber = "";
  224. }
  225.  
  226. void switchSides() {
  227.   Serial temp = EsploraList[0];      // на время сохраняем первый элемент
  228.   EsploraList[0] = EsploraList[1];   // перемещаем второй элемент к первому
  229.   EsploraList[1] = temp;             // перемещаем первый элемент ко второму
  230. }

См.также

  1. Esplora Pong

Внешние ссылки

  1. Arduino - Esplora Pong