#include <FastLED.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
#define NUM_LEDS 24 // Für 24 LEDs
#define LED_PIN 13
#define BUZZER_PIN 12
#define RED_BUTTON 4
#define GREEN_BUTTON 5
#define BLUE_BUTTON 18
#define YELLOW_BUTTON 19
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define MAX_SEQUENCE 50 // Maximale Sequenzlänge für Spiel 2 und 5
#define ADVERTISEMENT_TIMEOUT 30000 // 30 Sekunden Inaktivität
#define GAME_OVER_DISPLAY_TIME 10000 // 10 Sekunden für Game Over Anzeige
#define TIMING_GAME_TIMEOUT 30000 // 30 Sekunden Timeout für Spiel 3
#define DEEP_SLEEP_TIMEOUT 300000 // 5 Minuten (300.000 ms) für Deep Sleep
#define EEPROM_SIZE 21 // 5 Highscores * 4 Bytes + 1 Byte für buzzerEnabled
#define ADDR_HIGHSCORE_REACTION 0 // Adresse für Spiel 1 Highscore
#define ADDR_HIGHSCORE_MEMORY 4 // Adresse für Spiel 2 Highscore
#define ADDR_HIGHSCORE_TIMING 8 // Adresse für Spiel 3 Highscore
#define ADDR_HIGHSCORE_CHASE 12 // Adresse für Spiel 4 Highscore
#define ADDR_HIGHSCORE_RHYTHM 16 // Adresse für Spiel 5 Highscore
#define ADDR_BUZZER_ENABLED 20 // Adresse für Buzzer-Zustand
#define BUZZER_TOGGLE_HOLD_TIME 1000 // Zeit für langes Drücken (ms)
#define BUZZER_TOGGLE_OFFSET 50 // Zeitfenster für gleichzeitiges Drücken (ms)
#define HIGHSCORE_RESET_HOLD_TIME 2000 // Zeit für langes Drücken zum Highscore-Reset (ms)
#define HIGHSCORE_RESET_OFFSET 50 // Zeitfenster für gleichzeitiges Drücken (ms)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
CRGB leds[NUM_LEDS];
int buttons[] = {RED_BUTTON, GREEN_BUTTON, BLUE_BUTTON, YELLOW_BUTTON};
CRGB colors[] = {CRGB::Red, CRGB::Green, CRGB::Blue, CRGB::Yellow};
int currentColorIndex = -1;
bool gameRunning = false;
unsigned long startTime = 0;
int sequenceCount = 0;
int reactionTime = 2000;
int currentLevel = 1;
int gameMode = 0; // 0: Kein Spiel, 1: Reaktionsspiel, 2: Farben-Memory, 3: LED-Timing, 4: LED-Lauflicht, 5: Rhythm Master
int memorySequence[MAX_SEQUENCE]; // Speicher für Farben-Memory-Sequenz
int rhythmSequence[MAX_SEQUENCE]; // Speicher für Rhythmus-Sequenz
int rhythmTones[] = {800, 1000, 1200, 1400}; // Töne für Rot, Grün, Blau, Gelb
int playerIndex = 0; // Index für Spielereingabe in Spiel 2 und 5
int ledPosition = 0; // Aktuelle Position des Lauflichts (Spiel 4)
int stepDelay = 200; // Verzögerung zwischen LED-Schritten (Spiel 4)
int rhythmTiming = 6000; // Zeitfenster für Rhythmus-Eingaben (Spiel 5)
unsigned long lastStepTime = 0; // Zeitpunkt des letzten Schritts (Spiel 4, 5)
int cycleCount = 0; // Zählt Schritte für einen vollständigen Zyklus (Spiel 4)
unsigned long lastInteractionTime = 0; // Zeitpunkt der letzten Interaktion
int targetPosition = 0; // Zufällige Position der farbigen LED (Spiel 3)
int whiteLedPosition = 0; // Position der weißen LED (Spiel 3)
unsigned long lastActionTime = 0; // Zeitpunkt des letzten Treffers oder Spielstarts (Spiel 3)
int highScoreReaction = 0; // Highscore für Spiel 1
int highScoreMemory = 0; // Highscore für Spiel 2
int highScoreTiming = 0; // Highscore für Spiel 3
int highScoreChase = 0; // Highscore für Spiel 4
int highScoreRhythm = 0; // Highscore für Spiel 5
bool buzzerEnabled = true; // Buzzer-Zustand (true = ein, false = aus)
void setup() {
Serial.begin(115200);
EEPROM.begin(EEPROM_SIZE);
highScoreReaction = EEPROM.readInt(ADDR_HIGHSCORE_REACTION);
highScoreMemory = EEPROM.readInt(ADDR_HIGHSCORE_MEMORY);
highScoreTiming = EEPROM.readInt(ADDR_HIGHSCORE_TIMING);
highScoreChase = EEPROM.readInt(ADDR_HIGHSCORE_CHASE);
highScoreRhythm = EEPROM.readInt(ADDR_HIGHSCORE_RHYTHM);
buzzerEnabled = EEPROM.readByte(ADDR_BUZZER_ENABLED) != 0;
esp_sleep_enable_ext1_wakeup((1ULL << RED_BUTTON) | (1ULL << GREEN_BUTTON) | (1ULL << BLUE_BUTTON) | (1ULL << YELLOW_BUTTON), ESP_EXT1_WAKEUP_ANY_HIGH);
FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);
FastLED.setBrightness(200);
pinMode(BUZZER_PIN, OUTPUT);
for (int i = 0; i < 4; i++) {
pinMode(buttons[i], INPUT_PULLUP);
}
randomSeed(millis());
clearLEDs();
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("Display Initialisierung fehlgeschlagen!");
for (;;);
}
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(2);
display.setCursor(20, 10);
display.println("Ready!");
display.setTextSize(1);
display.setCursor(20, 40);
display.println("Select Game");
display.display();
lastInteractionTime = millis();
}
void loop() {
if (millis() - lastInteractionTime > DEEP_SLEEP_TIMEOUT) {
enterDeepSleep();
}
if (checkHighScoreReset()) {
resetHighScores();
return;
}
if (checkBuzzerToggle()) {
toggleBuzzer();
return;
}
if (!gameRunning) {
if (millis() - lastInteractionTime > ADVERTISEMENT_TIMEOUT) {
playAdvertisement();
} else {
checkForStart();
}
} else {
if (gameMode == 1) {
checkButtonsReaction();
checkTimeoutReaction();
} else if (gameMode == 2) {
checkButtonsMemory();
} else if (gameMode == 3) {
updateColorTiming();
checkButtonsColorTiming();
checkTimeoutColorTiming();
} else if (gameMode == 4) {
updateRunningLight();
checkButtonsRunningLight();
} else if (gameMode == 5) {
checkButtonsRhythm();
}
}
}
void enterDeepSleep() {
Serial.println("Gehe in Deep Sleep...");
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(10, 20);
display.println("Entering Deep Sleep...");
display.display();
delay(2000);
EEPROM.commit();
display.clearDisplay();
display.display();
clearLEDs();
esp_deep_sleep_start();
}
bool checkHighScoreReset() {
if (digitalRead(RED_BUTTON) == LOW || digitalRead(GREEN_BUTTON) == LOW ||
digitalRead(BLUE_BUTTON) == LOW || digitalRead(YELLOW_BUTTON) == LOW) {
unsigned long startTime = millis();
bool redPressed = digitalRead(RED_BUTTON) == LOW;
bool greenPressed = digitalRead(GREEN_BUTTON) == LOW;
bool bluePressed = digitalRead(BLUE_BUTTON) == LOW;
bool yellowPressed = digitalRead(YELLOW_BUTTON) == LOW;
while (millis() - startTime < HIGHSCORE_RESET_OFFSET) {
if (digitalRead(RED_BUTTON) == LOW && digitalRead(GREEN_BUTTON) == LOW &&
digitalRead(BLUE_BUTTON) == LOW && digitalRead(YELLOW_BUTTON) == LOW) {
unsigned long holdStart = millis();
while (millis() - holdStart < HIGHSCORE_RESET_HOLD_TIME) {
if (digitalRead(RED_BUTTON) != LOW || digitalRead(GREEN_BUTTON) != LOW ||
digitalRead(BLUE_BUTTON) != LOW || digitalRead(YELLOW_BUTTON) != LOW) {
Serial.println("Buttons vorzeitig losgelassen");
return false;
}
delay(10);
}
Serial.println("Alle Buttons für Reset erkannt");
while (digitalRead(RED_BUTTON) == LOW || digitalRead(GREEN_BUTTON) == LOW ||
digitalRead(BLUE_BUTTON) == LOW || digitalRead(YELLOW_BUTTON) == LOW);
return true;
}
redPressed = redPressed || (digitalRead(RED_BUTTON) == LOW);
greenPressed = greenPressed || (digitalRead(GREEN_BUTTON) == LOW);
bluePressed = bluePressed || (digitalRead(BLUE_BUTTON) == LOW);
yellowPressed = yellowPressed || (digitalRead(YELLOW_BUTTON) == LOW);
delay(10);
}
Serial.println("Nicht alle Buttons gedrückt");
return false;
}
return false;
}
void resetHighScores() {
highScoreReaction = 0;
highScoreMemory = 0;
highScoreTiming = 0;
highScoreChase = 0;
highScoreRhythm = 0;
EEPROM.writeInt(ADDR_HIGHSCORE_REACTION, highScoreReaction);
EEPROM.writeInt(ADDR_HIGHSCORE_MEMORY, highScoreMemory);
EEPROM.writeInt(ADDR_HIGHSCORE_TIMING, highScoreTiming);
EEPROM.writeInt(ADDR_HIGHSCORE_CHASE, highScoreChase);
EEPROM.writeInt(ADDR_HIGHSCORE_RHYTHM, highScoreRhythm);
EEPROM.commit();
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(10, 20);
display.println("Highscores Reset!");
display.display();
delay(1000);
if (!gameRunning) {
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(2);
display.setCursor(20, 10);
display.println("Ready!");
display.setTextSize(1);
display.setCursor(20, 40);
display.println("Select Game");
display.display();
} else {
updateDisplay();
}
lastInteractionTime = millis();
Serial.println("Highscores zurückgesetzt");
}
bool checkBuzzerToggle() {
if (digitalRead(RED_BUTTON) == LOW || digitalRead(YELLOW_BUTTON) == LOW) {
unsigned long startTime = millis();
bool redPressed = digitalRead(RED_BUTTON) == LOW;
bool yellowPressed = digitalRead(YELLOW_BUTTON) == LOW;
while (millis() - startTime < BUZZER_TOGGLE_OFFSET) {
if (digitalRead(RED_BUTTON) == LOW && digitalRead(YELLOW_BUTTON) == LOW) {
if (BUZZER_TOGGLE_HOLD_TIME > 0) {
unsigned long holdStart = millis();
while (millis() - holdStart < BUZZER_TOGGLE_HOLD_TIME) {
if (digitalRead(RED_BUTTON) != LOW || digitalRead(YELLOW_BUTTON) != LOW) {
Serial.println("Rot + Gelb vorzeitig losgelassen");
return false;
}
delay(10);
}
}
Serial.println("Rot + Gelb erkannt");
while (digitalRead(RED_BUTTON) == LOW || digitalRead(YELLOW_BUTTON) == LOW);
return true;
}
redPressed = redPressed || (digitalRead(RED_BUTTON) == LOW);
yellowPressed = yellowPressed || (digitalRead(YELLOW_BUTTON) == LOW);
delay(10);
}
if (redPressed && !yellowPressed) {
Serial.println("Nur Rot gedrückt");
} else if (yellowPressed && !redPressed) {
Serial.println("Nur Gelb gedrückt");
}
return false;
}
return false;
}
void toggleBuzzer() {
buzzerEnabled = !buzzerEnabled;
EEPROM.writeByte(ADDR_BUZZER_ENABLED, buzzerEnabled ? 1 : 0);
EEPROM.commit();
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(10, 20);
display.println(buzzerEnabled ? "Buzzer ON" : "Buzzer OFF");
display.display();
delay(1000);
if (!gameRunning) {
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(2);
display.setCursor(20, 10);
display.println("Ready!");
display.setTextSize(1);
display.setCursor(20, 40);
display.println("Select Game");
display.display();
} else {
updateDisplay();
}
lastInteractionTime = millis();
Serial.println("Buzzer-Zustand geändert: " + String(buzzerEnabled ? "ON" : "OFF"));
}
void checkForStart() {
bool buttonPressed = false;
if (digitalRead(RED_BUTTON) == LOW && digitalRead(YELLOW_BUTTON) != LOW && digitalRead(BLUE_BUTTON) != LOW) {
Serial.println("Starte Spiel 1 (Reaction)");
startReactionGame();
buttonPressed = true;
while (digitalRead(RED_BUTTON) == LOW);
} else if (digitalRead(GREEN_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(YELLOW_BUTTON) != LOW && digitalRead(BLUE_BUTTON) != LOW) {
Serial.println("Starte Spiel 2 (Memory)");
startMemoryGame();
buttonPressed = true;
while (digitalRead(GREEN_BUTTON) == LOW);
} else if (digitalRead(BLUE_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(YELLOW_BUTTON) != LOW && digitalRead(GREEN_BUTTON) != LOW) {
Serial.println("Starte Spiel 3 (LED Timing)");
startColorTimingGame();
buttonPressed = true;
while (digitalRead(BLUE_BUTTON) == LOW);
} else if (digitalRead(YELLOW_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(BLUE_BUTTON) != LOW) {
Serial.println("Starte Spiel 4 (LED Chase)");
startRunningLightGame();
buttonPressed = true;
while (digitalRead(YELLOW_BUTTON) == LOW);
} else if (digitalRead(BLUE_BUTTON) == LOW && digitalRead(YELLOW_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(GREEN_BUTTON) != LOW) {
Serial.println("Starte Spiel 5 (Rhythm Master)");
startRhythmGame();
buttonPressed = true;
while (digitalRead(BLUE_BUTTON) == LOW || digitalRead(YELLOW_BUTTON) == LOW);
}
if (buttonPressed) {
lastInteractionTime = millis();
delay(50);
}
}
void playAdvertisement() {
int melody[] = {659, 659, 659, 523, 698, 698, 698, 587, 659, 523, 587, 494, 523, 587, 659, 698, 659, 587, 523, 494};
int noteDurations[] = {300, 300, 300, 500, 300, 300, 300, 500, 300, 300, 300, 500, 300, 300, 300, 500, 300, 300, 300, 500};
int melodyLength = 20;
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(10, 20);
display.println("Play Now!");
display.display();
int currentLed = 0;
bool isBlinkPhase = true;
unsigned long lastLedUpdate = millis();
int blinkDelay = 80;
int runDelay = 120;
int oppositeLed = NUM_LEDS / 2;
for (int i = 0; i < melodyLength; i++) {
if (buzzerEnabled) {
tone(BUZZER_PIN, melody[i], noteDurations[i]);
}
unsigned long noteStart = millis();
while (millis() - noteStart < noteDurations[i] + 100) {
if (millis() - lastInteractionTime > DEEP_SLEEP_TIMEOUT) {
if (buzzerEnabled) noTone(BUZZER_PIN);
enterDeepSleep();
}
if (millis() - lastLedUpdate >= (isBlinkPhase ? blinkDelay : runDelay)) {
clearLEDs();
if (isBlinkPhase) {
for (int j = 0; j < NUM_LEDS; j++) {
leds[j] = colors[random(4)];
}
} else {
leds[currentLed] = colors[random(4)];
leds[oppositeLed] = colors[random(4)];
currentLed = (currentLed + 1) % NUM_LEDS;
oppositeLed = (oppositeLed - 1 + NUM_LEDS) % NUM_LEDS;
}
FastLED.show();
lastLedUpdate = millis();
if ((millis() - noteStart) % 1000 < 50) {
isBlinkPhase = !isBlinkPhase;
}
}
if (checkHighScoreReset()) {
if (buzzerEnabled) noTone(BUZZER_PIN);
resetHighScores();
return;
}
if (checkBuzzerToggle()) {
if (buzzerEnabled) noTone(BUZZER_PIN);
toggleBuzzer();
return;
}
if (digitalRead(RED_BUTTON) == LOW && digitalRead(YELLOW_BUTTON) != LOW && digitalRead(BLUE_BUTTON) != LOW) {
if (buzzerEnabled) noTone(BUZZER_PIN);
clearLEDs();
startReactionGame();
while (digitalRead(RED_BUTTON) == LOW);
lastInteractionTime = millis();
delay(50);
return;
} else if (digitalRead(GREEN_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(YELLOW_BUTTON) != LOW && digitalRead(BLUE_BUTTON) != LOW) {
if (buzzerEnabled) noTone(BUZZER_PIN);
clearLEDs();
startMemoryGame();
while (digitalRead(GREEN_BUTTON) == LOW);
lastInteractionTime = millis();
delay(50);
return;
} else if (digitalRead(BLUE_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(YELLOW_BUTTON) != LOW && digitalRead(GREEN_BUTTON) != LOW) {
if (buzzerEnabled) noTone(BUZZER_PIN);
clearLEDs();
startColorTimingGame();
while (digitalRead(BLUE_BUTTON) == LOW);
lastInteractionTime = millis();
delay(50);
return;
} else if (digitalRead(YELLOW_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(BLUE_BUTTON) != LOW) {
if (buzzerEnabled) noTone(BUZZER_PIN);
clearLEDs();
startRunningLightGame();
while (digitalRead(YELLOW_BUTTON) == LOW);
lastInteractionTime = millis();
delay(50);
return;
} else if (digitalRead(BLUE_BUTTON) == LOW && digitalRead(YELLOW_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(GREEN_BUTTON) != LOW) {
if (buzzerEnabled) noTone(BUZZER_PIN);
clearLEDs();
startRhythmGame();
while (digitalRead(BLUE_BUTTON) == LOW || digitalRead(YELLOW_BUTTON) == LOW);
lastInteractionTime = millis();
delay(500);
return;
}
}
if (buzzerEnabled) noTone(BUZZER_PIN);
}
clearLEDs();
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(2);
display.setCursor(20, 10);
display.println("Ready!");
display.setTextSize(1);
display.setCursor(20, 40);
display.println("Select Game");
display.display();
lastInteractionTime = millis();
}
void startReactionGame() {
gameMode = 1;
gameRunning = true;
sequenceCount = 0;
reactionTime = 2000;
currentLevel = 1;
updateDisplay();
showNextColorReaction();
}
void startMemoryGame() {
gameMode = 2;
gameRunning = true;
sequenceCount = 0;
currentLevel = 1;
playerIndex = 0;
memorySequence[0] = random(4);
updateDisplay();
showMemorySequence();
}
void startColorTimingGame() {
gameMode = 3;
gameRunning = true;
sequenceCount = 0;
currentLevel = 1;
stepDelay = 500;
targetPosition = random(NUM_LEDS);
currentColorIndex = random(4);
whiteLedPosition = 0;
lastStepTime = millis();
lastActionTime = millis();
updateColorTiming();
updateDisplay();
}
void startRunningLightGame() {
gameMode = 4;
gameRunning = true;
sequenceCount = 0;
currentLevel = 1;
ledPosition = 0;
stepDelay = 200;
cycleCount = 0;
lastStepTime = millis();
currentColorIndex = random(4);
updateRunningLight();
updateDisplay();
}
void startRhythmGame() {
gameMode = 5;
gameRunning = true;
sequenceCount = 0;
currentLevel = 1;
playerIndex = 0;
rhythmTiming = 1000;
// Initiale Melodie: 4 zufällige Töne
for (int i = 0; i < 4; i++) {
rhythmSequence[i] = random(4);
}
updateDisplay();
showRhythmSequence();
}
void showNextColorReaction() {
int newColorIndex;
do {
newColorIndex = random(4);
} while (newColorIndex == currentColorIndex);
currentColorIndex = newColorIndex;
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = colors[currentColorIndex];
}
FastLED.show();
if (buzzerEnabled) tone(BUZZER_PIN, 1000, 100);
startTime = millis();
sequenceCount++;
updateReactionTime();
updateDisplay();
}
void showMemorySequence() {
for (int i = 0; i < currentLevel; i++) {
for (int j = 0; j < NUM_LEDS; j++) {
leds[j] = colors[memorySequence[i]];
}
FastLED.show();
if (buzzerEnabled) tone(BUZZER_PIN, 1000, 100);
delay(500);
clearLEDs();
delay(200);
}
playerIndex = 0;
}
void showRhythmSequence() {
int sequenceLength = 4; // Feste Länge oder dynamisch: min(4 + currentLevel / 2, MAX_SEQUENCE)
for (int i = 0; i < sequenceLength; i++) {
for (int j = 0; j < NUM_LEDS; j++) {
leds[j] = colors[rhythmSequence[i]];
}
FastLED.show();
if (buzzerEnabled) tone(BUZZER_PIN, rhythmTones[rhythmSequence[i]], rhythmTiming / 2);
delay(rhythmTiming / 2);
clearLEDs();
delay(rhythmTiming / 2);
}
playerIndex = 0;
lastStepTime = millis();
}
void updateColorTiming() {
if (millis() - lastStepTime >= stepDelay) {
clearLEDs();
leds[targetPosition] = colors[currentColorIndex];
whiteLedPosition = (whiteLedPosition + 1) % NUM_LEDS;
leds[whiteLedPosition] = CRGB::White;
FastLED.show();
if (buzzerEnabled) tone(BUZZER_PIN, 1000, 50);
lastStepTime = millis();
}
}
void updateRunningLight() {
if (millis() - lastStepTime >= stepDelay) {
clearLEDs();
leds[ledPosition] = colors[currentColorIndex];
FastLED.show();
if (buzzerEnabled) tone(BUZZER_PIN, 1000, 50);
ledPosition = (ledPosition + 1) % NUM_LEDS;
cycleCount++;
lastStepTime = millis();
if (cycleCount >= NUM_LEDS) {
gameOver();
}
}
}
void updateReactionTime() {
if (sequenceCount <= 5) {
reactionTime = 2000;
currentLevel = 1;
} else if (sequenceCount <= 10) {
reactionTime = 1800;
currentLevel = 2;
} else if (sequenceCount <= 15) {
reactionTime = 1600;
currentLevel = 3;
} else if (sequenceCount <= 20) {
reactionTime = 1400;
currentLevel = 4;
} else if (sequenceCount <= 25) {
reactionTime = 1200;
currentLevel = 5;
} else if (sequenceCount <= 30) {
reactionTime = 1000;
currentLevel = 6;
} else if (sequenceCount <= 35) {
reactionTime = 800;
currentLevel = 7;
} else if (sequenceCount <= 40) {
reactionTime = 600;
currentLevel = 8;
} else if (sequenceCount <= 45) {
reactionTime = 400;
currentLevel = 9;
} else {
reactionTime = 200;
currentLevel = 10;
}
}
void checkButtonsReaction() {
for (int i = 0; i < 4; i++) {
if (digitalRead(buttons[i]) == LOW) {
if (i == currentColorIndex) {
if (buzzerEnabled) tone(BUZZER_PIN, 1500, 50);
delay(100);
showNextColorReaction();
} else {
gameOver();
}
while (digitalRead(buttons[i]) == LOW);
lastInteractionTime = millis();
delay(50);
}
}
}
void checkButtonsMemory() {
for (int i = 0; i < 4; i++) {
if (digitalRead(buttons[i]) == LOW) {
for (int j = 0; j < NUM_LEDS; j++) {
leds[j] = colors[i];
}
FastLED.show();
if (buzzerEnabled) tone(BUZZER_PIN, 1500, 50);
delay(200);
clearLEDs();
if (i == memorySequence[playerIndex]) {
playerIndex++;
if (playerIndex == currentLevel) {
sequenceCount = currentLevel;
currentLevel++;
if (currentLevel <= MAX_SEQUENCE) {
int newColor;
do {
newColor = random(4);
} while (currentLevel > 1 && newColor == memorySequence[currentLevel - 2]);
memorySequence[currentLevel - 1] = newColor;
updateDisplay();
delay(500);
showMemorySequence();
} else {
gameOver();
}
}
} else {
gameOver();
}
while (digitalRead(buttons[i]) == LOW);
lastInteractionTime = millis();
delay(50);
}
}
}
void checkButtonsColorTiming() {
for (int i = 0; i < 4; i++) {
if (digitalRead(buttons[i]) == LOW) {
if (i == currentColorIndex && whiteLedPosition == targetPosition) {
if (buzzerEnabled) tone(BUZZER_PIN, 1500, 50);
sequenceCount++;
stepDelay = max(100, stepDelay - 50);
if (sequenceCount % 5 == 0) {
currentLevel = sequenceCount / 5 + 1;
}
targetPosition = random(NUM_LEDS);
int newColorIndex;
do {
newColorIndex = random(4);
} while (newColorIndex == currentColorIndex);
currentColorIndex = newColorIndex;
lastActionTime = millis();
updateDisplay();
updateColorTiming();
} else {
gameOver();
}
while (digitalRead(buttons[i]) == LOW);
lastInteractionTime = millis();
delay(50);
}
}
}
void checkButtonsRunningLight() {
for (int i = 0; i < 4; i++) {
if (digitalRead(buttons[i]) == LOW) {
if (i == currentColorIndex) {
if (buzzerEnabled) tone(BUZZER_PIN, 1500, 50);
sequenceCount++;
stepDelay = max(50, stepDelay - 20);
if (sequenceCount % 5 == 0) {
currentLevel = sequenceCount / 5 + 1;
}
cycleCount = 0;
int newColorIndex;
do {
newColorIndex = random(4);
} while (newColorIndex == currentColorIndex);
currentColorIndex = newColorIndex;
updateDisplay();
clearLEDs();
leds[ledPosition] = colors[currentColorIndex];
FastLED.show();
lastStepTime = millis();
} else {
gameOver();
}
while (digitalRead(buttons[i]) == LOW);
lastInteractionTime = millis();
delay(50);
}
}
}
void checkButtonsRhythm() {
int sequenceLength = 4; // Feste Länge oder dynamisch: min(4 + currentLevel / 2, MAX_SEQUENCE)
if (playerIndex < sequenceLength) {
if (millis() - lastStepTime >= rhythmTiming) {
gameOver(); // Timing verpasst
}
for (int i = 0; i < 4; i++) {
if (digitalRead(buttons[i]) == LOW) {
for (int j = 0; j < NUM_LEDS; j++) {
leds[j] = colors[i];
}
FastLED.show();
if (buzzerEnabled) tone(BUZZER_PIN, rhythmTones[i], 100);
delay(200);
clearLEDs();
if (i == rhythmSequence[playerIndex]) {
playerIndex++;
if (playerIndex == sequenceLength) {
sequenceCount++;
rhythmTiming = max(200, rhythmTiming - 50);
if (sequenceCount % 5 == 0) {
currentLevel = sequenceCount / 5 + 1;
}
// Neue zufällige Melodie
for (int j = 0; j < sequenceLength; j++) {
rhythmSequence[j] = random(4);
}
updateDisplay();
delay(500);
showRhythmSequence();
} else {
lastStepTime = millis();
}
} else {
gameOver();
}
while (digitalRead(buttons[i]) == LOW);
lastInteractionTime = millis();
delay(50);
}
}
}
}
void checkTimeoutReaction() {
if (millis() - startTime > reactionTime) {
gameOver();
}
}
void checkTimeoutColorTiming() {
if (millis() - lastActionTime > TIMING_GAME_TIMEOUT) {
gameOver();
}
}
void showHighscoreMessage() {
if (buzzerEnabled) {
tone(BUZZER_PIN, 800, 200);
delay(250);
tone(BUZZER_PIN, 900, 300);
delay(350);
tone(BUZZER_PIN, 1000, 400);
delay(450);
tone(BUZZER_PIN, 1200, 200);
delay(250);
tone(BUZZER_PIN, 1400, 100);
delay(150);
tone(BUZZER_PIN, 1500, 100);
delay(150);
noTone(BUZZER_PIN);
}
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(SSD1306_WHITE);
display.setCursor(10, 20);
display.println("New Highscore!");
display.display();
delay(2000);
}
void gameOver() {
gameRunning = false;
startTime = 0;
int previousGameMode = gameMode;
gameMode = 0;
int currentScore = previousGameMode == 1 ? max(0, sequenceCount - 1) : sequenceCount;
if (previousGameMode == 1 && currentScore > highScoreReaction) {
highScoreReaction = currentScore;
EEPROM.writeInt(ADDR_HIGHSCORE_REACTION, highScoreReaction);
EEPROM.commit();
Serial.println("Neuer Highscore Reaction: " + String(highScoreReaction));
showHighscoreMessage();
} else if (previousGameMode == 2 && currentScore > highScoreMemory) {
highScoreMemory = currentScore;
EEPROM.writeInt(ADDR_HIGHSCORE_MEMORY, highScoreMemory);
EEPROM.commit();
Serial.println("Neuer Highscore Memory: " + String(highScoreMemory));
showHighscoreMessage();
} else if (previousGameMode == 3 && currentScore > highScoreTiming) {
highScoreTiming = currentScore;
EEPROM.writeInt(ADDR_HIGHSCORE_TIMING, highScoreTiming);
EEPROM.commit();
Serial.println("Neuer Highscore Timing: " + String(highScoreTiming));
showHighscoreMessage();
} else if (previousGameMode == 4 && currentScore > highScoreChase) {
highScoreChase = currentScore;
EEPROM.writeInt(ADDR_HIGHSCORE_CHASE, highScoreChase);
EEPROM.commit();
Serial.println("Neuer Highscore Chase: " + String(highScoreChase));
showHighscoreMessage();
} else if (previousGameMode == 5 && currentScore > highScoreRhythm) {
highScoreRhythm = currentScore;
EEPROM.writeInt(ADDR_HIGHSCORE_RHYTHM, highScoreRhythm);
EEPROM.commit();
Serial.println("Neuer Highscore Rhythm: " + String(highScoreRhythm));
showHighscoreMessage();
}
for (int i = 0; i < 5; i++) {
for (int j = 0; j < NUM_LEDS; j++) {
leds[j] = CRGB::Red;
}
FastLED.show();
if (buzzerEnabled) tone(BUZZER_PIN, 500, 200);
delay(300);
clearLEDs();
delay(200);
}
clearLEDs();
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(10, 0);
display.println("Game Over");
display.setTextSize(2);
display.setCursor(10, 16);
display.print("Score: ");
display.println(currentScore);
display.setTextSize(1);
display.setCursor(10, 36);
display.print("Level: ");
display.println(currentLevel);
display.setCursor(10, 48);
display.print("High: ");
if (previousGameMode == 1) {
display.println(highScoreReaction);
} else if (previousGameMode == 2) {
display.println(highScoreMemory);
} else if (previousGameMode == 3) {
display.println(highScoreTiming);
} else if (previousGameMode == 4) {
display.println(highScoreChase);
} else if (previousGameMode == 5) {
display.println(highScoreRhythm);
}
display.display();
unsigned long gameOverStart = millis();
while (millis() - gameOverStart < GAME_OVER_DISPLAY_TIME) {
if (millis() - lastInteractionTime > DEEP_SLEEP_TIMEOUT) {
enterDeepSleep();
}
if (checkHighScoreReset()) {
resetHighScores();
return;
}
if (checkBuzzerToggle()) {
toggleBuzzer();
} else if (digitalRead(RED_BUTTON) == LOW && digitalRead(YELLOW_BUTTON) != LOW && digitalRead(BLUE_BUTTON) != LOW) {
startReactionGame();
while (digitalRead(RED_BUTTON) == LOW);
lastInteractionTime = millis();
delay(50);
return;
} else if (digitalRead(GREEN_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(YELLOW_BUTTON) != LOW && digitalRead(BLUE_BUTTON) != LOW) {
startMemoryGame();
while (digitalRead(GREEN_BUTTON) == LOW);
lastInteractionTime = millis();
delay(50);
return;
} else if (digitalRead(BLUE_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(YELLOW_BUTTON) != LOW && digitalRead(GREEN_BUTTON) != LOW) {
startColorTimingGame();
while (digitalRead(BLUE_BUTTON) == LOW);
lastInteractionTime = millis();
delay(50);
return;
} else if (digitalRead(YELLOW_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(BLUE_BUTTON) != LOW) {
startRunningLightGame();
while (digitalRead(YELLOW_BUTTON) == LOW);
lastInteractionTime = millis();
delay(50);
return;
} else if (digitalRead(BLUE_BUTTON) == LOW && digitalRead(YELLOW_BUTTON) == LOW && digitalRead(RED_BUTTON) != LOW && digitalRead(GREEN_BUTTON) != LOW) {
startRhythmGame();
while (digitalRead(BLUE_BUTTON) == LOW || digitalRead(YELLOW_BUTTON) == LOW);
lastInteractionTime = millis();
delay(50);
return;
}
}
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(2);
display.setCursor(20, 10);
display.println("Ready!");
display.setTextSize(1);
display.setCursor(20, 40);
display.println("Select Game");
display.display();
lastInteractionTime = millis();
}
void clearLEDs() {
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = CRGB::Black;
}
FastLED.show();
}
void updateDisplay() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(10, 0);
if (gameMode == 1) {
display.println("Game 1: Reaction");
} else if (gameMode == 2) {
display.println("Game 2: Memory");
} else if (gameMode == 3) {
display.println("Game 3: LED Timing");
} else if (gameMode == 4) {
display.println("Game 4: LED Chase");
} else if (gameMode == 5) {
display.println("Game 5: Rhythm");
}
display.setTextSize(2);
display.setCursor(10, 16);
display.print("Score: ");
display.println(gameMode == 1 ? sequenceCount - 1 : sequenceCount);
display.setTextSize(1);
display.setCursor(10, 36);
display.print("Level: ");
display.println(currentLevel);
display.setCursor(10, 48);
display.print("High: ");
if (gameMode == 1) {
display.println(highScoreReaction);
} else if (gameMode == 2) {
display.println(highScoreMemory);
} else if (gameMode == 3) {
display.println(highScoreTiming);
} else if (gameMode == 4) {
display.println(highScoreChase);
} else if (gameMode == 5) {
display.println(highScoreRhythm);
}
display.display();
}