Загрузка данных
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Adafruit_NeoPixel.h>
// LCD
LiquidCrystal_I2C lcd(0x27, 16, 2);
// RGB-кольцо
#define LED_PIN 6
#define LED_COUNT 16
Adafruit_NeoPixel ring(
LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800
);
// Пины
#define JOY_X A0
#define JOY_SW 2
#define BUZZER 3
#define RED_PIN 9
#define GREEN_PIN 10
#define BLUE_PIN 11
// Настройки
const unsigned long GAME_TIME = 50000;
const unsigned long HOLD_TIME = 3000;
const int TOTAL_ROUNDS = 5;
int selected = 0;
int target = 0;
int roundNumber = 0;
unsigned long gameStart = 0;
unsigned long holdStart = 0;
unsigned long lastMove = 0;
unsigned long lastMusic = 0;
unsigned long stateStart = 0;
unsigned long lastLCD = 0;
bool holding = false;
int musicNote = 0;
int melody[] = {
523, 587, 659, 784,
659, 587, 523, 440
};
enum GameState {
WAITING,
COUNTDOWN,
PLAYING,
FEEDBACK,
WIN,
LOSE
};
GameState state = WAITING;
// Преобразование оттенка в RGB
uint32_t hueColor(int hue) {
int h = hue * 6;
int sector = h / 256;
int f = h % 256;
int q = 255 - f;
int r = 0, g = 0, b = 0;
switch (sector) {
case 0: r = 255; g = f; break;
case 1: r = q; g = 255; break;
case 2: g = 255; b = f; break;
case 3: g = q; b = 255; break;
case 4: r = f; b = 255; break;
default: r = 255; b = q; break;
}
return ring.Color(r, g, b);
}
// RGB светодиод показывает целевой цвет
void showTarget() {
uint32_t c = hueColor(target * 16);
uint8_t r = (c >> 16) & 255;
uint8_t g = (c >> 8) & 255;
uint8_t b = c & 255;
analogWrite(RED_PIN, r);
analogWrite(GREEN_PIN, g);
analogWrite(BLUE_PIN, b);
}
// Отображение кольца
void showRing() {
for (int i = 0; i < LED_COUNT; i++) {
if (i == selected) {
ring.setPixelColor(i, ring.Color(255, 255, 255));
} else {
ring.setPixelColor(i, hueColor(i * 16));
}
}
ring.show();
}
// Выключение RGB
void clearLights() {
ring.clear();
ring.show();
analogWrite(RED_PIN, 0);
analogWrite(GREEN_PIN, 0);
analogWrite(BLUE_PIN, 0);
}
// Музыка
void music() {
if (millis() - lastMusic >= 250) {
lastMusic = millis();
tone(BUZZER, melody[musicNote], 180);
musicNote++;
if (musicNote >= 8) {
musicNote = 0;
}
}
}
// Начальный экран
void waitingScreen() {
noTone(BUZZER);
clearLights();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("COLOR CHALLENGE");
lcd.setCursor(0, 1);
lcd.print("PRESS TO START");
state = WAITING;
}
// Начало игры
void startGame() {
roundNumber = 0;
selected = 0;
musicNote = 0;
lcd.clear();
lcd.print("GET READY!");
state = COUNTDOWN;
stateStart = millis();
}
// Новый раунд
void newRound() {
// Цель совпадает с одним из 16 цветов кольца
target = random(0, 16);
selected = 0;
showTarget();
showRing();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("ROUND ");
lcd.print(roundNumber + 1);
lcd.print("/5");
lcd.setCursor(0, 1);
lcd.print("FIND COLOR!");
state = PLAYING;
}
// Победа
void winGame() {
state = WIN;
noTone(BUZZER);
clearLights();
lcd.clear();
lcd.print("YOU WIN!");
lcd.setCursor(0, 1);
lcd.print("5/5 COMPLETED");
tone(BUZZER, 1200, 300);
}
// Поражение
void loseGame() {
state = LOSE;
clearLights();
lcd.clear();
lcd.print("TIME IS OVER!");
lcd.setCursor(0, 1);
lcd.print("GAME OVER");
tone(BUZZER, 1000);
stateStart = millis();
}
void setup() {
pinMode(JOY_SW, INPUT_PULLUP);
pinMode(BUZZER, OUTPUT);
pinMode(RED_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(BLUE_PIN, OUTPUT);
lcd.init();
lcd.backlight();
ring.begin();
ring.setBrightness(60);
ring.show();
randomSeed(analogRead(A2));
waitingScreen();
}
void loop() {
unsigned long now = millis();
// ОЖИДАНИЕ
if (state == WAITING) {
if (digitalRead(JOY_SW) == LOW) {
delay(30);
if (digitalRead(JOY_SW) == LOW) {
startGame();
while (digitalRead(JOY_SW) == LOW) {}
}
}
}
// ОБРАТНЫЙ ОТСЧЁТ
else if (state == COUNTDOWN) {
int count = 3 - (now - stateStart) / 1000;
if (count >= 1) {
lcd.setCursor(0, 0);
lcd.print("STARTING...");
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(7, 1);
lcd.print(count);
static int lastCount = 0;
if (count != lastCount) {
tone(BUZZER, 1000, 180);
lastCount = count;
}
}
if (now - stateStart >= 3000) {
noTone(BUZZER);
gameStart = millis();
lastMusic = millis();
// Сбрасываем отсчёт для следующего запуска
stateStart = 0;
newRound();
}
}
// ИГРА
else if (state == PLAYING) {
// Проверка времени
if (now - gameStart >= GAME_TIME) {
loseGame();
return;
}
music();
// Движение джойстика
int x = analogRead(JOY_X);
if (now - lastMove >= 180) {
if (x < 400) {
selected--;
if (selected < 0) {
selected = 15;
}
lastMove = now;
showRing();
}
else if (x > 620) {
selected++;
if (selected > 15) {
selected = 0;
}
lastMove = now;
showRing();
}
}
// LCD таймер
if (now - lastLCD >= 200) {
lastLCD = now;
int seconds = (GAME_TIME - (now - gameStart)) / 1000;
lcd.setCursor(0, 0);
lcd.print("TIME: ");
lcd.print(seconds);
lcd.print("s R:");
lcd.print(roundNumber + 1);
lcd.print(" ");
lcd.setCursor(0, 1);
if (holding) {
int left = 3 - (now - holdStart) / 1000;
lcd.print("HOLD: ");
lcd.print(left);
lcd.print(" SEC ");
} else {
lcd.print("HOLD SEL 3 SEC ");
}
}
// Кнопка SEL
if (digitalRead(JOY_SW) == LOW) {
if (!holding) {
holding = true;
holdStart = now;
}
if (now - holdStart >= HOLD_TIME) {
holding = false;
noTone(BUZZER);
if (selected == target) {
roundNumber++;
lcd.clear();
lcd.print("CORRECT!");
lcd.setCursor(0, 1);
lcd.print("SCORE: ");
lcd.print(roundNumber);
lcd.print("/5");
tone(BUZZER, 1400, 200);
if (roundNumber >= TOTAL_ROUNDS) {
winGame();
} else {
state = FEEDBACK;
stateStart = now;
}
} else {
lcd.clear();
lcd.print("WRONG COLOR!");
lcd.setCursor(0, 1);
lcd.print("TRY AGAIN");
tone(BUZZER, 250, 200);
state = FEEDBACK;
stateStart = now;
}
}
} else {
holding = false;
}
}
// ПЕРЕХОД К СЛЕДУЮЩЕМУ РАУНДУ
else if (state == FEEDBACK) {
if (now - gameStart >= GAME_TIME) {
loseGame();
}
else if (now - stateStart >= 700) {
noTone(BUZZER);
newRound();
lastMusic = now;
}
}
// ПОБЕДА
else if (state == WIN) {
if (digitalRead(JOY_SW) == LOW) {
while (digitalRead(JOY_SW) == LOW) {}
waitingScreen();
}
}
// ПОРАЖЕНИЕ
else if (state == LOSE) {
if (now - stateStart >= 3000) {
noTone(BUZZER);
lcd.clear();
lcd.print("GAME OVER");
lcd.setCursor(0, 1);
lcd.print("PRESS TO RETRY");
state = WAITING;
}
}
}