Для начала в двух словах опишу цель проекта. Хотелось придумать что-нибудь простое и наглядное для демонстрации коммуникации платы Arduino Uno и ПК по serial соединению. Что-нибудь, что бы вписывалось в регламенты проекта «выходного дня», а именно: делалось за пару часов и легко кодилось.
Решено было создать игру со следующими правилами. Действие происходит на рабочей двухмерной плоскости. Шарик «герой», положением которого управляет игрок, пытается уйти от столкновения с шариками «противниками». Шарик герой движется только по оси абсцисс, противники появляются в произвольном месте рабочей плоскости и движутся прямолинейно по оси ординат. В случае ухода шарика «героя» от столкновения с «противником», значение счетчика очков инкрементируется, в противном случае — счетчик сбрасывается и набранные ранее очки «сгорают».
Шаг 1
Выбор языка программирования. Был выбран Processing, так как язык для программирования плат Arduino основан на нем, также Processing — хороший и простой инструмент для создания картинок, эффектов анимации и пр. Да, еще он бесплатный.
Шаг 2
Сборка самодельного «джойстика». Все донельзя тривиально. Роль джойстика выполняет обычный потенциометр, подключенный между питанием +5V и землей GND на плате Arduino Uno. Средний контакт выведен на аналоговый пин «A0».
Естественно, при желании Вы можете использовать аналоговый стик, тачпад и пр. Суть та же.
Шаг 3
Программирование платы Arduino. В данном проекте от платы Arduino требуется непрерывно отправлять данные о положении движка потенциометра. Впоследствии, эти данные на компьютере «подхватывает» Processing для нужд игры (определения координаты шарика «героя»).
int potPin = 0;// устанавливаем номер пина, к которому подключена средняя ножка
//потенциометра
void setup() {
Serial.begin(9600);//открываем serial соединение для приема и передачи данных
}
void loop() {
int val = map (analogRead(potPin), 0, 1023, 0, 640);//напряжение на средней ножке на
// аналоговом пине представляется в Arduino в виде числа от 0 до 1023.
// Функция map меняет диапазон представления с 0 до 640.
//Забегая вперед, последняя цифра должна советовать ширине заданного в программе
// на Processing окна
Serial.println(val);// для вывода сообщения в монитор последовательного порта
delay(50);// задержка в 50 мс
}
Шаг 4
Собственно, написание самой игры. Как уже говорилось ранее, игра пишется на языке Processing. Скачать дистрибутив можно на оф сайте, там же есть примеры использования. В моем случае «движок» состоит из 49 строчек кода из которых половина — это комментарии. Что хочу сказать, разобраться в нем сложности не составит. Вы можете самостоятельно изменить «шкурки» героев, добавить кол-во противников, ввести в игру бонусы, избавить данные с потенциометра от дребезга и пр. Мой код «as is» под спойлером.
import processing.serial.*;//I/O library
Serial port;
PShape bot; //инициализация типа картинки для иллюстрации взрыва при столкновении
PFont font; // инициализация типа шрифта
int radiusOfHero=100, radiusOfEnemy, speedOfEnemy=1, Counter=0;
float positionOfHeroX=100.0, positionOfEnemyY = 0.0 ,positionOfEnemyX=0.0;
void setup()
{
size(640, 400);// задаем размеры окна
port = new Serial(this, "COM4", 9600);// в моем случае эмулятором COM порта присвоен
// номер 4
port.bufferUntil('n');
bot = loadShape("2.svg");// задаем картинку, файл должен лежать в директории Processing
font = loadFont("AgencyFB-Bold-200.vlw");// выбранный шрифт для счетчика
textFont(font,200);
}
void draw() {
background(0);
fill(255);
text(Counter, 30,175);// вывод содержимого счетчика на окно сначальной координатой (30; 175)
//===============definiton of hero position=============
fill(0, 102, 153);
ellipse(positionOfHeroX, height-radiusOfHero/2, radiusOfHero, radiusOfHero);// положение
// шара-героя
//===============definition of enemy===============
fill(255,0,0);
radiusOfEnemy=round(random(60));{
for(int i = 0; i < height; i++)
positionOfEnemyY=positionOfEnemyY+0.02*speedOfEnemy;// скорость падения шаров-противников по оси ординат
ellipse(positionOfEnemyX, positionOfEnemyY, radiusOfEnemy*2, radiusOfEnemy*2); }// отрисовка шаров-противников
if (positionOfEnemyY>height) {
positionOfEnemyY=0.0;
positionOfEnemyX = round(random(width)); // условие для повторения падения шаров-противников
Counter++;}
//==============clash==========================
if (abs(positionOfHeroX-positionOfEnemyX) < (radiusOfHero+radiusOfEnemy)/2 &
(abs(height-radiusOfHero/2)-positionOfEnemyY) < (radiusOfHero+radiusOfEnemy)/2){// условие столкновения шаров-противников
background(255,0,0);
shape(bot, positionOfHeroX-radiusOfHero/2,height-radiusOfHero, 100, 100);
Counter=-1;
fill(255);
textFont(font,150);
text("TURN AWAY!", 0,height/2);
}
}
void serialEvent (Serial port) {
positionOfHeroX=round(float(port.readStringUntil('n')));// считывание координаты положения шара-героя из порта COM4
}
Шаг 5
Демонстрация игры
Автор: eugen_fts