Arduino:Примеры/Esplora TFT Pong: различия между версиями

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску
м (Замена текста — «<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS">» на «<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS" enclose="div">»)
 
Нет описания правки
 
(не показана 1 промежуточная версия этого же участника)
Строка 26: Строка 26:
Чтобы использовать экран, сначала нужно подключить библиотеки '''TFT''' и '''SPI'''. Кроме того, нам понадобится библиотека '''Esplora'''.
Чтобы использовать экран, сначала нужно подключить библиотеки '''TFT''' и '''SPI'''. Кроме того, нам понадобится библиотека '''Esplora'''.


<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS" enclose="div">
<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS">
#include <Esplora.h>
#include <Esplora.h>
#include <TFT.h>
#include <TFT.h>
Строка 34: Строка 34:
Задаем несколько переменных – координаты ('''X''' и '''Y''') для мячика и платформы, направление мяча, а также предыдущие координаты ('''X''' и '''Y''') мячика и платформы.  
Задаем несколько переменных – координаты ('''X''' и '''Y''') для мячика и платформы, направление мяча, а также предыдущие координаты ('''X''' и '''Y''') мячика и платформы.  


<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS" enclose="div">
<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS">
int paddleX = 0;
int paddleX = 0;
int paddleY = 0;
int paddleY = 0;
Строка 46: Строка 46:
В секции setup() запускаем последовательную передачу данных, инициализируем дисплей и очищаем фон экрана.
В секции setup() запускаем последовательную передачу данных, инициализируем дисплей и очищаем фон экрана.


<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS" enclose="div">
<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS">
void setup() {
void setup() {
   Serial.begin(9600);
   Serial.begin(9600);
Строка 56: Строка 56:
В блоке loop() будет код для считывания данных от джойстика, затем стирание предыдущей позиции платформы и, наконец, прорисовка новой позиции платформы.
В блоке loop() будет код для считывания данных от джойстика, затем стирание предыдущей позиции платформы и, наконец, прорисовка новой позиции платформы.


<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS" enclose="div">
<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS">
void loop() {
void loop() {
   int myWidth = EsploraTFT.width();
   int myWidth = EsploraTFT.width();
Строка 79: Строка 79:
Сохраняем текущие координаты платформы как предыдущие, чтобы в следующий раз можно было проверить, переместилась платформа или нет.
Сохраняем текущие координаты платформы как предыдущие, чтобы в следующий раз можно было проверить, переместилась платформа или нет.


<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS" enclose="div">
<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS">
oldPaddleX = paddleX;
oldPaddleX = paddleX;
   oldPaddleY = paddleY;
   oldPaddleY = paddleY;
Строка 86: Строка 86:
В конце блока loop() считываем позицию слайдера, чтобы определить скорость мяча. Также вызываем пользовательскую функцию под названием moveBall() – с ее помощью мы будем обновлять позицию мяча.
В конце блока loop() считываем позицию слайдера, чтобы определить скорость мяча. Также вызываем пользовательскую функцию под названием moveBall() – с ее помощью мы будем обновлять позицию мяча.


<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS" enclose="div">
<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS">
int ballSpeed = map(Esplora.readSlider(), 0, 1023, 0, 80)+1;
int ballSpeed = map(Esplora.readSlider(), 0, 1023, 0, 80)+1;
   if (millis() % ballSpeed < 2) {
   if (millis() % ballSpeed < 2) {
Строка 96: Строка 96:
Это обновление будет проходить следующим образом – сначала функция moveBall() сотрет старое месторасположение мяча, а затем нарисует его в новом месте. Кроме того, эта же функция будет следить, чтобы мячик не улетел за край экрана, т.е. как только мяча долетит до границ дисплея, она реверсирует его направление.  
Это обновление будет проходить следующим образом – сначала функция moveBall() сотрет старое месторасположение мяча, а затем нарисует его в новом месте. Кроме того, эта же функция будет следить, чтобы мячик не улетел за край экрана, т.е. как только мяча долетит до границ дисплея, она реверсирует его направление.  


<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS" enclose="div">
<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS">
void moveBall() {
void moveBall() {
   if (ballX > EsploraTFT.width() || ballX < 0) {
   if (ballX > EsploraTFT.width() || ballX < 0) {
Строка 127: Строка 127:
Кроме того, нам понадобится еще одна пользовательская функция, которая будет следить за пересечением мяча и платформы – назовем ее inPaddle(). Она будет проверять, не занимают ли мяч и платформа одно и то же место в пространстве. Если да, она вернет значение TRUE, а затем реверсирует направление мяча, как если бы он ударился о границу экрана.
Кроме того, нам понадобится еще одна пользовательская функция, которая будет следить за пересечением мяча и платформы – назовем ее inPaddle(). Она будет проверять, не занимают ли мяч и платформа одно и то же место в пространстве. Если да, она вернет значение TRUE, а затем реверсирует направление мяча, как если бы он ударился о границу экрана.


<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS" enclose="div">
<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS">
boolean inPaddle(int x, int y, int rectX, int rectY, int rectWidth, int rectHeight) {
boolean inPaddle(int x, int y, int rectX, int rectY, int rectWidth, int rectHeight) {
   boolean result = false;
   boolean result = false;
Строка 141: Строка 141:
Весь код полностью – ниже:
Весь код полностью – ниже:


<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS" enclose="div">
<syntaxhighlight lang="c" line="GESHI_NORMAL_LINE_NUMBERS|GESHI_FANCY_LINE_NUMBERS">
/*
/*
Игра в Pong на TFT-экране Esplora
Игра в Pong на TFT-экране Esplora
Строка 270: Строка 270:


<references />
<references />
{{Навигационная таблица/Портал/Arduino}}
[[Категория:Пример]]
[[Категория:Пример]]
[[Категория:Примеры]]
[[Категория:Примеры]]
[[Категория:Пример программирования Arduino]]
[[Категория:Пример программирования Arduino]]
[[Категория:Примеры программирования Arduino]]
[[Категория:Примеры программирования Arduino]]

Текущая версия от 12:34, 8 июля 2023

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


Игра в Pong на TFT-экране Esplora[1]

Этот пример для платы Arduino (и подключенного к ней TFT-экрана Arduino) является упрощенной вариацией на тему игры Pong.

Скетч создает два объекта – прямоугольную платформу, которая может двигаться в двух направлениях, а также мячик, отскакивающий и от краев экрана, и от платформы. Скорость мяча регулируется встроенным слайдером Esplora.

Этот пример демонстрирует использование так называемого «обнаружения столкновений» объектов на экране, а также то, как быстро обновить картинки без необходимости при каждом проходе через loop() стирать весь экран.

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

  • Плата Arduino Esplora;
  • TFT-экран Arduino;

Цепь

Подключите TFT-экран к сокету на Esplora – так, чтобы надпись «SD Card» смотрела вверх.

Код

Чтобы использовать экран, сначала нужно подключить библиотеки TFT и SPI. Кроме того, нам понадобится библиотека Esplora.

#include <Esplora.h>
#include <TFT.h>
#include <SPI.h>

Задаем несколько переменных – координаты (X и Y) для мячика и платформы, направление мяча, а также предыдущие координаты (X и Y) мячика и платформы.

int paddleX = 0;
int paddleY = 0;
int oldPaddleX, oldPaddleY;
int ballDirectionX = 1;
int ballDirectionY = 1;

int ballX, ballY, oldBallX, oldBallY;

В секции setup() запускаем последовательную передачу данных, инициализируем дисплей и очищаем фон экрана.

void setup() {
  Serial.begin(9600);
  EsploraTFT.begin();
  EsploraTFT.background(0,0,0); 
}

В блоке loop() будет код для считывания данных от джойстика, затем стирание предыдущей позиции платформы и, наконец, прорисовка новой позиции платформы.

void loop() {
  int myWidth = EsploraTFT.width();
  int myHeight = EsploraTFT.height();

  paddleX = map(Esplora.readJoystickX(), 512, -512, 0, myWidth) - 20/2; 
  paddleY = map(Esplora.readJoystickY(), -512, 512, 0, myHeight) - 5/2; 
  Serial.print(paddleX);
  Serial.print(" ");
  Serial.println(paddleY);

  EsploraTFT.fill(0,0,0);

  if (oldPaddleX != paddleX || oldPaddleY != paddleY) {
    EsploraTFT.rect(oldPaddleX, oldPaddleY, 20, 5);
  }

  EsploraTFT.fill(255,255,255);
  EsploraTFT.rect(paddleX, paddleY, 20, 5);

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

oldPaddleX = paddleX;
  oldPaddleY = paddleY;

В конце блока loop() считываем позицию слайдера, чтобы определить скорость мяча. Также вызываем пользовательскую функцию под названием moveBall() – с ее помощью мы будем обновлять позицию мяча.

int ballSpeed = map(Esplora.readSlider(), 0, 1023, 0, 80)+1;
  if (millis() % ballSpeed < 2) {
    moveBall();
  }
}

Это обновление будет проходить следующим образом – сначала функция moveBall() сотрет старое месторасположение мяча, а затем нарисует его в новом месте. Кроме того, эта же функция будет следить, чтобы мячик не улетел за край экрана, т.е. как только мяча долетит до границ дисплея, она реверсирует его направление.

void moveBall() {
  if (ballX > EsploraTFT.width() || ballX < 0) {
    ballDirectionX = -ballDirectionX;
  }
  if (ballY > EsploraTFT.height() || ballY < 0) {
    ballDirectionY = -ballDirectionY;
  }  
  if (inPaddle(ballX, ballY, paddleX, paddleY, 20, 5)) {
    ballDirectionY = -ballDirectionY;
  }

  ballX += ballDirectionX;
  ballY += ballDirectionY;

  EsploraLCD.fill(0,0,0);

  if (oldBallX != ballX || oldBallY != ballY) {
    EsploraTFT.rect(oldBallX, oldBallY, 5, 5);
  }

  EsploraLCD.fill(255,255,255);
  EsploraLCD.rect(ballX, ballY, 5, 5);

  oldBallX = ballX;
  oldBallY = ballY;
}

Кроме того, нам понадобится еще одна пользовательская функция, которая будет следить за пересечением мяча и платформы – назовем ее inPaddle(). Она будет проверять, не занимают ли мяч и платформа одно и то же место в пространстве. Если да, она вернет значение TRUE, а затем реверсирует направление мяча, как если бы он ударился о границу экрана.

boolean inPaddle(int x, int y, int rectX, int rectY, int rectWidth, int rectHeight) {
  boolean result = false;

  if ((x >= rectX && x <= (rectX + rectWidth)) && 
    (y >= rectY && y <= (rectY + rectHeight))) {
    result = true; 
  }
  return result;  
}

Весь код полностью – ниже:

/*
Игра в Pong на TFT-экране Esplora

Это пример для платы Esplora и TFT-экрана Arduino.
Он считывает данные, поступающие от джойстика, чтобы перемещать
прямоугольную платформу по осям X и Y. Платформа может
взаимодействовать с мячом – ударившись о нее, он будет отскакивать.
Скорость мяча регулируется линейным потенциометром Esplora.

Этот код не защищен авторским правом.

Создан в декабре 2012 Томом Иго (Tom Igoe),
модифицирован 15 апреля 2013 Скоттом Фитцджеральдом (Scott Fitzgerald).

http://www.arduino.cc/en/Tutorial/EsploraTFTPong
*/

#include <Esplora.h>
#include <TFT.h>            // библиотека для TFT-экрана Arduino
#include <SPI.h>

// переменные для координат мяча и платформы:
int paddleX = 0;
int paddleY = 0;
int oldPaddleX, oldPaddleY;
int ballDirectionX = 1;
int ballDirectionY = 1;

int ballX, ballY, oldBallX, oldBallY;

void setup() {

  Serial.begin(9600);

  // Инициализируем дисплей:
  EsploraTFT.begin();
  // Закрашиваем фон черным цветом:
  EsploraTFT.background(0, 0, 0);
}

void loop() {
  // Сохраняем ширину и высоту экрана:
  int myWidth = EsploraTFT.width();
  int myHeight = EsploraTFT.height();

  // Приспосабливаем диапазон хода джойстика к размерам экрана:
  paddleX = map(Esplora.readJoystickX(), 512, -512, 0, myWidth) - 20 / 2;
  paddleY = map(Esplora.readJoystickY(), -512, 512, 0, myHeight) - 5 / 2;
  Serial.print(paddleX);
  Serial.print(" ");
  Serial.println(paddleY);

  // Делаем цвет заливки черным и стираем предыдущую позицию платформы, 
  // если она отличается от текущей:
  EsploraTFT.fill(0, 0, 0);

  if (oldPaddleX != paddleX || oldPaddleY != paddleY) {
    EsploraTFT.rect(oldPaddleX, oldPaddleY, 20, 5);
  }

  // Рисуем на экране платформу, сохраняем ее текущую позицию как предыдущую:
  EsploraTFT.fill(255, 255, 255);
  EsploraTFT.rect(paddleX, paddleY, 20, 5);
  oldPaddleX = paddleX;
  oldPaddleY = paddleY;

  // Считываем данные от слайдера, чтобы определить скорость мяча:
  int ballSpeed = map(Esplora.readSlider(), 0, 1023, 0, 80) + 1;
  if (millis() % ballSpeed < 2) {
    moveBall();
  }
}

// Функция для определения позиции мяча на экране:
void moveBall() {
  // Если мяч улетел за пределы экрана, реверсируем его направление:
  if (ballX > EsploraTFT.width() || ballX < 0) {
    ballDirectionX = -ballDirectionX;
  }

  if (ballY > EsploraTFT.height() || ballY < 0) {
    ballDirectionY = -ballDirectionY;
  }

  // Проверяем, не занимают ли платформа и мяч одно и то же место в пространстве:
  if (inPaddle(ballX, ballY, paddleX, paddleY, 20, 5)) {
    ballDirectionY = -ballDirectionY;
  }

  // Обновляем позицию мяча:
  ballX += ballDirectionX;
  ballY += ballDirectionY;

  // Стираем предыдущую позицию мяча:
  EsploraTFT.fill(0, 0, 0);

  if (oldBallX != ballX || oldBallY != ballY) {
    EsploraTFT.rect(oldBallX, oldBallY, 5, 5);
  }

  // Рисуем текущую позицию мяча:
  EsploraTFT.fill(255, 255, 255);

  EsploraTFT.rect(ballX, ballY, 5, 5);

  oldBallX = ballX;
  oldBallY = ballY;

}

// Функция для проверки того, не пересекаются ли позиции мяча и платформы:
boolean inPaddle(int x, int y, int rectX, int rectY, int rectWidth, int rectHeight) {
  boolean result = false;

  if ((x >= rectX && x <= (rectX + rectWidth)) &&
      (y >= rectY && y <= (rectY + rectHeight))) {
    result = true;
  }

  return result;
}

См.также

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