// библиотека для работы с RGB-матрицей #include // номер пина, к которому подключена RGB-матрица #define MATRIX_C_PIN 4 // количество светодиодов в матрице #define LED_COUNT 16 // зерно для генератора случайных чисел #define ANALOG_PIN_FOR_RND A3 // максимальная яркость матрицы от 0 до 255 #define BRIGHT 10 // даём разумные имена пинам, к которым подключён джойстик #define X A5 #define Y A4 #define Z 2 // создаём объект класса Adafruit_NeoPixel Adafruit_NeoPixel matrixOnC = Adafruit_NeoPixel(LED_COUNT, MATRIX_C_PIN, NEO_GRB + NEO_KHZ800); // перечисляем названия мишеней, которые будут выводиться на матрицу enum { NOTOUCH, // имя для состояния ожидания RIGHT, // имя для мишени, в виде полосы светодиодов справа LEFT, // имя для мишени, в виде полосы светодиодов слева DOWN, // имя для мишени, в виде полосы светодиодов снизу UP, // имя для мишени, в виде полосы светодиодов сверху CENTER // имя для мишени, в виде квадрата светодиодов в центре }; // создаем массив с мишенями int target[] = {RIGHT, LEFT, DOWN, UP, CENTER}; // задаем цвет мишени в RGB int color [] = {255, 0, 0}; // создаем переменную для хранения состояния мишени int shot = 0; // создаем маркер игрока int player = NOTOUCH; // создаем счетчик очков int score = 0; // создаем объект класса long для хранения времени unsigned long timeOfReaction = 0; // создаем счетчик реакции, который сокращается с каждой победой int reaction = 2000; // создаем флаг для победы bool flag = false; // создаем флаги для джойстика bool stateStickOldX, stateStickOldY, stateStickOldZ = true; void setup() { // открываем последовательный порт Serial.begin(9600); // инициализируем матрицу matrixOnC.begin(); // задаем придельную яркость matrixOnC.setBrightness(BRIGHT); // очищаем матрицу matrixOnC.clear(); matrixOnC.show(); // "Давай сыграем!" Serial.println("Let's play!"); delay(1000); } void loop() { // инициализируем последовательность случайных чисел randomSeed(analogRead(ANALOG_PIN_FOR_RND)); // даём сигнал «пли!», выждав случайное время от 0,5 до 1,5 сек delay(random(500, 1500)); // записываем в мишень одно из состояний shot = target[random(0, sizeof(target) / sizeof(int))]; // выводим картинку на матрицу matrix_show (shot); matrixOnC.show(); // запускаем таймер реакции timeOfReaction = millis(); while (millis() - timeOfReaction < reaction) { // считываем действия игрока player_move (); if (player == shot) { // если успел попасть, то поднимаем флаг победы и выходим flag = 1; break; } else if (player != NOTOUCH) { // если промахнулся просто выходим break; } // если не успел, также просто выходим } if (flag) { // победа, показываем зеленый, опускаем флаг, уменьшаем время на реакцию you_win(); flag = 0; // выводим счет в Serial port // Serial.print("You win! Your score: "); // увеличиваем счет score++; // Serial.println(score); reaction -= (reaction / 10); } else { // поражение, показываем синий, возвращаем время на реакцию к начальному значению game_over(); } // ставим фишку игрока в состояние ожидания player = NOTOUCH; // очищаем матрицу matrixOnC.clear(); matrixOnC.show(); } // функция проигрыша void game_over() { for (int i = 0; i < LED_COUNT; i++) { matrixOnC.setPixelColor(i, 0, 0, 255); } matrixOnC.show(); // выводим счет в Serial port Serial.print("You lose. Your score: "); Serial.println(score); // обнуляем счет score = 0; // возвращаем реакцию к начальному значению reaction = 2000; delay(1000); } // функция победы void you_win() { for (int i = 0; i < LED_COUNT; i++) { matrixOnC.setPixelColor(i, 0, 255, 0); } matrixOnC.show(); delay(1000); } // функция для показа нужной мишени на матрице void matrix_show(int shot) { switch (shot) { case RIGHT: { // рисуем линию от правого нижнего угла к правому верхнему draw_line(0, 0, 0, 3); break; } case LEFT: { // рисуем линию от левого нижнего угла к правому верхнему draw_line(3, 0, 3, 3); break; } case DOWN: { // рисуем линию от правого нижнего угла к левому нижнему draw_line(0, 0, 3, 0); break; } case UP: { // рисуем линию от левого верхнего угла к правому верхнему draw_line(0, 3, 3, 3); break; } case CENTER: { // рисуем квадрат в центре draw_line(1, 1, 2, 1); draw_line(1, 2, 2, 2); break; } } matrixOnC.show(); } // функция для обработки 3D джойстика void player_move () { int x, y, z; // считываем текущее значение джойстика по Х x = analogRead(X); if (x < 100 && stateStickOldX) { player = LEFT; stateStickOldX = false; } if (x > 924 && stateStickOldX) { player = RIGHT; stateStickOldX = false; } if (100 < x && x < 924) { stateStickOldX = true; } // считываем текущее значение джойстика по Y y = analogRead(Y); if (y < 100 && stateStickOldY) { player = UP; stateStickOldY = false; } if (y > 924 && stateStickOldY) { player = DOWN; stateStickOldY = false; } if (100 < y && y < 924) { stateStickOldY = true; } // считываем текущее значение джойстика по Z z = digitalRead(Z); if (z == 1 && stateStickOldZ) { player = CENTER; stateStickOldZ = false; } if (z == 0) stateStickOldZ = true; } // функция для преобразования номера светодиода в координаты int xyHelper(int x, int y) { return y * 4 + x; } // функция для рисования линий по алгоритму Брезенхэма void draw_line(int x1, int y1, int x2, int y2) { const int deltaX = abs(x2 - x1); const int deltaY = abs(y2 - y1); const int signX = x1 < x2 ? 1 : -1; const int signY = y1 < y2 ? 1 : -1; int error = deltaX - deltaY; matrixOnC.setPixelColor(xyHelper(x2, y2), color[0], color[1], color[2]); while (x1 != x2 || y1 != y2) { matrixOnC.setPixelColor(xyHelper(x1, y1), color[0], color[1], color[2]); const int error2 = error * 2; if (error2 > -deltaY) { error -= deltaY; x1 += signX; } if (error2 < deltaX) { error += deltaX; y1 += signY; } } matrixOnC.show(); }