/*
Игра на адресной светодиодной ленте "Понг"
- Нажимай кнопку, когда шарик попал в твою зону
- Чем ближе к краю ленты, тем сильнее будет отскок
- Нажал не в своей зоне - проиграл
- Пропустил - проиграл
*/
#define LED_PIN 2 // пин ленты
#define LED_NUM 100 // кол-во светодиодов
#define LED_BR 250 // яркость ленты
#define BUT_1_PIN 3 // пин кнопки 1
#define BUT_2_PIN 4 // пин кнопки 2
#define BUZ_1_PIN 5 // пин пищалки 1
#define BUZ_2_PIN 6 // пин пищалки 2
#define JOY_1_VERT_PIN A0
#define JOY_1_HORZ_PIN A1
#define JOY_1_SEL_PIN 8
#define JOY_2_VERT_PIN A2
#define JOY_2_HORZ_PIN A3
#define JOY_2_SEL_PIN 9
#define ZONE_SIZE 10 // размер зоны
#define MIN_SPEED 5 // минимальная скорость
#define MAX_SPEED 20 // максимальная скорость
#define WIN_SCORE 5 // победный счёт
// =============================================
#include "FastLED.h"
CRGB leds[LED_NUM];
// ========== КНОПКА ==========
// мини класс кнопки
#define BTN_DEB 50 // дебаунс, мс
struct Button {
public:
Button (byte pin) {
_pin = pin;
pinMode(_pin, INPUT_PULLUP);
}
bool click() {
bool btnState = digitalRead(_pin);
if (!btnState && !_flag && millis() - _tmr >= BTN_DEB) {
_flag = true;
_tmr = millis();
return true;
}
if (btnState && _flag && millis() - _tmr >= BTN_DEB) {
_flag = false;
_tmr = millis();
}
return false;
}
uint32_t _tmr;
byte _pin;
bool _flag;
};
Button BUT_1(BUT_1_PIN);
Button BUT_2(BUT_2_PIN);
// ============ SETUP =============
void setup() {
FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, LED_NUM);
FastLED.setBrightness(LED_BR);
pinMode(BUZ_1_PIN, OUTPUT);
pinMode(BUZ_2_PIN, OUTPUT);
pinMode(JOY_1_VERT_PIN, INPUT);
pinMode(JOY_1_HORZ_PIN, INPUT);
pinMode(JOY_1_SEL_PIN, INPUT_PULLUP);
pinMode(JOY_2_VERT_PIN, INPUT);
pinMode(JOY_2_HORZ_PIN, INPUT);
pinMode(JOY_2_SEL_PIN, INPUT_PULLUP);
Game_New();
}
// ========== ПЕРЕМЕННЫЕ ==========
int pos = 0;
int spd;
byte score1 = 0, score2 = 0;
uint32_t tmr;
//int JOY_1_VERT;
//int JOY_1_HORZ;
//bool BUT_1_SEL;
//int JOY_2_VERT;
//int JOY_2_HORZ;
//bool BUT_2_SEL;
// ============= LOOP =============
void loop() {
//BUT_1_VERT = analogRead(BUT_1_VERT_PIN);
//BUT_2_VERT = analogRead(BUT_2_VERT_PIN);
//BUT_1_HORZ = analogRead(BUT_1_HORZ_PIN);
//BUT_2_HORZ = analogRead(BUT_2_HORZ_PIN);
//BUT_1_SEL = digitalRead(BUT_1_SEL_PIN) == LOW;
//BUT_2_SEL = digitalRead(BUT_1_SEL_PIN) == LOW;
//BUT_1_SEL = analogRead(BUT_1_SEL_PIN);
//int BUT_2_SEL = analogRead(BUT_1_SEL_PIN);
//digitalRead(SEL_PIN) == LOW)
//BUT_1_SEL = 0;
Joystick_Press();
//Button_Press();
gameRoutine();
}
// ========= ОПРОС ДЖОЙСТИКА =========
void Joystick_Press() {
if (analogRead(JOY_1_VERT_PIN) < 300)
{
}
else
{
if (analogRead(JOY_1_VERT_PIN) > 700)
{
}
else
{
if (analogRead(JOY_1_HORZ_PIN) < 300)
{
}
else
{
if (analogRead(JOY_1_HORZ_PIN) > 700)
{
}
else
{
if (digitalRead(JOY_1_SEL_PIN) == LOW)
{
if (pos >= ZONE_SIZE * 10)
{
gameOver(0); // мячик вне зоны 1 игрока - проиграл
}
else
{ // мячик в зоне - отбил
tone(BUZ_1_PIN, 1200, 60);
spd = map(pos, ZONE_SIZE * 10, 0, MIN_SPEED, MAX_SPEED); // меняем скорость
}
}
}
}
}
}
if (analogRead(JOY_2_VERT_PIN) < 300)
{
}
else
{
if (analogRead(JOY_2_VERT_PIN) > 700)
{
}
else
{
if (analogRead(JOY_2_HORZ_PIN) < 300)
{
}
else
{
if (analogRead(JOY_2_HORZ_PIN) > 700)
{
}
else
{
if (digitalRead(JOY_2_SEL_PIN) == LOW)
{
if (pos < (LED_NUM - ZONE_SIZE) * 10) {
gameOver(1);
}
else {
tone(BUZ_2_PIN, 1200, 60);
spd = map(pos, (LED_NUM - ZONE_SIZE) * 10, LED_NUM * 10, -MIN_SPEED, -MAX_SPEED);
}
}
}
}
}
}
}
// ========= ОПРОС КНОПОК =========
void Button_Press() {
//if (BUT_1.click()) { // произошёл клик игрока 1
//if (BUT_1_SEL = 1) { // произошёл клик игрока 1
// if (pos >= ZONE_SIZE * 10) {
// gameOver(0); // мячик вне зоны 1 игрока - проиграл
// }
// else { // мячик в зоне - отбил
// tone(BUZ_1_PIN, 1200, 60);
// spd = map(pos, ZONE_SIZE * 10, 0, MIN_SPEED, MAX_SPEED); // меняем скорость
// }
//}
// аналогично для игрока 2
// if (BUT_2.click()) {
// if (pos < (LED_NUM - ZONE_SIZE) * 10) {
// gameOver(1);
//}
//else {
//tone(BUZ_2_PIN, 1200, 60);
//
// spd = map(pos, (LED_NUM - ZONE_SIZE) * 10, LED_NUM * 10, -MIN_SPEED, -MAX_SPEED);
//}
//}
}
// ========= ЗАЛИВКА ЗОН =========
void fillZones(CRGB color1, CRGB color2) {
// заливаем концы ленты переданными цветами
for (int i = 0; i < ZONE_SIZE; i++) {
leds[i] = color1;
leds[LED_NUM - i - 1] = color2;
if (score1 > 1) {
for (int i = 0; i < (score1 * 2); i++) {
leds[i] = CRGB::Yellow;
}
}
if (score2 > 1) {
for (int i = 0; i < (score2 * 2); i++) {
leds[LED_NUM - i] = CRGB::Yellow;
}
}
}
}
// ========= МИГАТЬ И ПИЩАТЬ =========
// (цвет1, цвет2, частота, время задержки)
void blinkTone(CRGB color1, CRGB color2, int freq, int del) {
fillZones(color1, color2); // залить зоны
FastLED.show(); // показать
tone(BUZ_1_PIN, freq); // пищать
tone(BUZ_2_PIN, freq); // пищать
delay(del); // ждём
noTone(BUZ_1_PIN); // не пищать
noTone(BUZ_2_PIN); // не пищать
fillZones(0, 0); // выключить зоны
FastLED.show(); // показать
delay(del); // ждать
}
void blinkTone_1(CRGB color1, CRGB color2, int freq, int del) {
fillZones(color1, color2); // залить зоны
FastLED.show(); // показать
tone(BUZ_1_PIN, freq); // пищать
delay(del); // ждём
noTone(BUZ_1_PIN); // не пищать
fillZones(0, 0); // выключить зоны
FastLED.show(); // показать
delay(del); // ждать
}
void blinkTone_2(CRGB color1, CRGB color2, int freq, int del) {
fillZones(color1, color2); // залить зоны
FastLED.show(); // показать
tone(BUZ_2_PIN, freq); // пищать
delay(del); // ждём
noTone(BUZ_2_PIN); // не пищать
fillZones(0, 0); // выключить зоны
FastLED.show(); // показать
delay(del); // ждать
}
// =========== ПРОИГРЫШ ===========
// (номер игрока, 0 или 1)
void gameOver(byte player) {
newRound(); // новый раунд
if (player == 0) {
score2++;
if (score2 == WIN_SCORE) { // победил игрок 2
score1 = score2 = 0; // обнуляем счёт
// победный бип бип бип игрока 2
blinkTone_2(CRGB::Black, CRGB::Yellow, 600, 200);
blinkTone_2(CRGB::Black, CRGB::Green, 600, 200);
blinkTone_2(CRGB::Black, CRGB::Green, 600, 200);
delay(500);
Game_New(); // новая игра
} else {
blinkTone_1(CRGB::Red, CRGB::Green, 200, 500); // красный бииип игрока 1
}
} else {
score1++;
if (score1 == WIN_SCORE) { // победил игрок 1
score1 = score2 = 0;
blinkTone_1(CRGB::Yellow, CRGB::Black, 600, 200);
blinkTone_1(CRGB::Green, CRGB::Black, 600, 200);
blinkTone_1(CRGB::Green, CRGB::Black, 600, 200);
delay(500);
Game_New(); // новая игра
} else {
blinkTone_2(CRGB::Green, CRGB::Red, 200, 500);
}
}
}
// ============== НОВАЯ ИГРА ==============
void Game_New() {
blinkTone(CRGB::Red, CRGB::Red, 300, 300);
blinkTone(CRGB::Yellow, CRGB::Yellow, 300, 300);
blinkTone(CRGB::Green, CRGB::Green, 600, 300);
fillZones(CRGB::Green, CRGB::Green);
FastLED.show();
randomSeed(millis()); // делаем случайные числа более случайными
newRound();
}
// ============== НОВЫЙ РАУНД ==============
void newRound() {
spd = random(0, 2) ? MIN_SPEED : -MIN_SPEED; // случайное направление
pos = (LED_NUM * 10) / 2; // в центр ленты
}
// ============== ИГРА ==============
void gameRoutine() {
if (millis() - tmr >= 10) { // каждые 10 мс
tmr = millis();
pos += spd; // двигаем мячик
if (pos < 0) { // вылетел слева
gameOver(0); // игрок 1 проиграл
return; // выходим
}
if (pos >= LED_NUM * 10) { // вылетел справа
gameOver(1); // игрок 2 проиграл
return; // выходим
}
FastLED.clear();
fillZones(CRGB::Green, CRGB::Green); // показываем зоны
leds[pos / 10] = CRGB::Cyan; // рисуем мячик
FastLED.show();
}
}