// Wir fügen die FastLED-Bibliothek hinzu, um den LED-Streifen zu steuern.
#include <FastLED.h>
// Wir legen fest, an welchem Pin der LED-Streifen angeschlossen ist.
#define LED_PIN 2
// Wir geben an, wie viele LEDs unser Streifen hat.
#define NUM_LEDS 90
// Wir definieren den LED-Typ und die Farbreihenfolge.
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
// Wir erstellen ein Array, um die LED-Daten zu speichern.
CRGB leds[NUM_LEDS];
// Variable für die Länge der Spielerzone.
const int playerZoneLength = 10; // Anzahl der LEDs pro Spielerzone
// Variable für die Anzahl der Blinkvorgänge beim Anzeigen des Spielstands.
const int scoreBlinkCount = 3; // Anzahl der Blinkwiederholungen
// Wir bestimmen die Startposition des blauen Lichts in der Mitte.
int bluePosition = NUM_LEDS / 2;
// Wir speichern die vorherige Position des blauen Lichts.
int previousBluePosition = bluePosition;
// Wir wählen zufällig, ob das blaue Licht nach links oder rechts geht.
int direction = 1; // 1 bedeutet nach rechts, -1 bedeutet nach links.
// Pins für die Taster der Spieler.
#define BUTTON_PIN_PLAYER1 3
#define BUTTON_PIN_PLAYER2 4
// Variablen für die Taster und das Entprellen.
int buttonStatePlayer1 = HIGH; // Startzustand ist HIGH wegen INPUT_PULLUP
int lastButtonStatePlayer1 = HIGH;
unsigned long lastDebounceTimePlayer1 = 0;
unsigned long debounceDelay = 50; // 50 Millisekunden Entprellzeit
int buttonStatePlayer2 = HIGH;
int lastButtonStatePlayer2 = HIGH;
unsigned long lastDebounceTimePlayer2 = 0;
// Variable für die Geschwindigkeit des blauen Lichts.
int speed = 100; // Startgeschwindigkeit in Millisekunden
// Minimale und maximale Geschwindigkeit.
const int minSpeed = 20; // Schnellste Geschwindigkeit (kleinste Verzögerung)
const int maxSpeed = 100; // Langsamste Geschwindigkeit (größte Verzögerung)
// Variablen für die Punkte der Spieler.
int scorePlayer1 = 0;
int scorePlayer2 = 0;
void setup() {
// Wir starten den LED-Streifen.
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);
// Wir stellen sicher, dass alle LEDs ausgeschaltet sind.
FastLED.clear();
FastLED.show();
// Wir starten den Zufallsgenerator.
randomSeed(analogRead(0));
// Wir wählen zufällig die Start-Richtung des blauen Lichts.
if (random(0, 2) == 0) {
direction = -1; // Nach links
} else {
direction = 1; // Nach rechts
}
// Wir legen die Taster-Pins als Eingänge mit Pullup-Widerständen fest.
pinMode(BUTTON_PIN_PLAYER1, INPUT_PULLUP);
pinMode(BUTTON_PIN_PLAYER2, INPUT_PULLUP);
// Wir malen die Spielerzonen einmalig an.
paintPlayerZones();
}
void loop() {
// *** Taster von Spieler 1 lesen und entprellen ***
int readingPlayer1 = digitalRead(BUTTON_PIN_PLAYER1);
if (readingPlayer1 != lastButtonStatePlayer1) {
lastDebounceTimePlayer1 = millis();
}
if ((millis() - lastDebounceTimePlayer1) > debounceDelay) {
if (readingPlayer1 != buttonStatePlayer1) {
buttonStatePlayer1 = readingPlayer1;
if (buttonStatePlayer1 == LOW) {
// Prüfen, ob das blaue Licht im Bereich von Spieler 1 ist und auf ihn zukommt.
if (bluePosition >= 0 && bluePosition < playerZoneLength && direction == -1) {
// Richtung umkehren.
direction = 1;
// Geschwindigkeit basierend auf Position erhöhen.
adjustSpeedPlayer1();
} else {
// Spieler 1 hat falsch gedrückt und verliert die Runde.
scorePlayer2++;
displayScore(); // Spielstand anzeigen
resetGame();
return;
}
}
}
}
lastButtonStatePlayer1 = readingPlayer1;
// *** Taster von Spieler 2 lesen und entprellen ***
int readingPlayer2 = digitalRead(BUTTON_PIN_PLAYER2);
if (readingPlayer2 != lastButtonStatePlayer2) {
lastDebounceTimePlayer2 = millis();
}
if ((millis() - lastDebounceTimePlayer2) > debounceDelay) {
if (readingPlayer2 != buttonStatePlayer2) {
buttonStatePlayer2 = readingPlayer2;
if (buttonStatePlayer2 == LOW) {
// Prüfen, ob das blaue Licht im Bereich von Spieler 2 ist und auf ihn zukommt.
if (bluePosition >= NUM_LEDS - playerZoneLength && bluePosition < NUM_LEDS && direction == 1) {
// Richtung umkehren.
direction = -1;
// Geschwindigkeit basierend auf Position erhöhen.
adjustSpeedPlayer2();
} else {
// Spieler 2 hat falsch gedrückt und verliert die Runde.
scorePlayer1++;
displayScore(); // Spielstand anzeigen
resetGame();
return;
}
}
}
}
lastButtonStatePlayer2 = readingPlayer2;
// *** Nur die LEDs aktualisieren, die sich geändert haben ***
// Setzen der vorherigen Position des blauen Lichts zurück.
restorePreviousLED();
// Position des blauen Lichts ändern.
previousBluePosition = bluePosition; // Speichern der aktuellen Position als vorherige für den nächsten Durchlauf.
bluePosition += direction;
// Grenzen überprüfen und Punktestand aktualisieren, wenn nötig.
if (bluePosition < 0) {
// Spieler 2 bekommt einen Punkt.
scorePlayer2++;
displayScore(); // Spielstand anzeigen
resetGame();
return; // Wir beenden die loop(), um das Spiel zurückzusetzen.
} else if (bluePosition >= NUM_LEDS) {
// Spieler 1 bekommt einen Punkt.
scorePlayer1++;
displayScore(); // Spielstand anzeigen
resetGame();
return; // Wir beenden die loop(), um das Spiel zurückzusetzen.
}
// Neues blaues Licht setzen.
leds[bluePosition] = CRGB::Blue;
FastLED.show();
// Prüfen, ob jemand 10 Punkte hat und gewonnen hat.
if (scorePlayer1 >= 10) {
winnerEffect(1);
return;
} else if (scorePlayer2 >= 10) {
winnerEffect(2);
return;
}
// Kurze Pause je nach Geschwindigkeit.
delay(speed);
}
// Funktion, um die Spielerzonen einmalig zu malen.
void paintPlayerZones() {
// Spieler 1 Zone grün färben.
for (int i = 0; i < playerZoneLength; i++) {
leds[i] = CRGB::Green;
}
// Spieler 2 Zone rot färben.
for (int i = NUM_LEDS - playerZoneLength; i < NUM_LEDS; i++) {
leds[i] = CRGB::Red;
}
FastLED.show();
}
// Funktion, um die vorherige LED zurückzusetzen.
void restorePreviousLED() {
// Wenn die vorherige Position in der Spielerzone von Spieler 1 liegt, setzen wir sie auf grün.
if (previousBluePosition >= 0 && previousBluePosition < playerZoneLength) {
leds[previousBluePosition] = CRGB::Green;
}
// Wenn die vorherige Position in der Spielerzone von Spieler 2 liegt, setzen wir sie auf rot.
else if (previousBluePosition >= NUM_LEDS - playerZoneLength && previousBluePosition < NUM_LEDS) {
leds[previousBluePosition] = CRGB::Red;
}
// Ansonsten setzen wir die vorherige Position auf aus (schwarz).
else if (previousBluePosition >= 0 && previousBluePosition < NUM_LEDS) {
leds[previousBluePosition] = CRGB::Black;
}
}
// Funktion zum Anpassen der Geschwindigkeit für Spieler 1.
void adjustSpeedPlayer1() {
// Berechnen, wie weit das blaue Licht in der Spielerzone ist.
int positionInZone = bluePosition; // Werte von 0 bis playerZoneLength - 1
int zoneLength = playerZoneLength;
// Berechnen des Geschwindigkeitsfaktors.
float factor = (float)positionInZone / (zoneLength - 1);
// Neue Geschwindigkeit berechnen.
speed = maxSpeed - (int)(factor * (maxSpeed - minSpeed));
// Sicherstellen, dass die Geschwindigkeit nicht unter der minimalen Geschwindigkeit liegt.
speed = max(minSpeed, speed);
}
// Funktion zum Anpassen der Geschwindigkeit für Spieler 2.
void adjustSpeedPlayer2() {
// Berechnen, wie weit das blaue Licht in der Spielerzone ist.
int positionInZone = bluePosition - (NUM_LEDS - playerZoneLength); // Werte von 0 bis playerZoneLength - 1
int zoneLength = playerZoneLength;
// Berechnen des Geschwindigkeitsfaktors.
float factor = (float)positionInZone / (zoneLength - 1);
// Neue Geschwindigkeit berechnen.
speed = maxSpeed - (int)(factor * (maxSpeed - minSpeed));
// Sicherstellen, dass die Geschwindigkeit nicht unter der minimalen Geschwindigkeit liegt.
speed = max(minSpeed, speed);
}
// Funktion zum Anzeigen des Spielstands.
void displayScore() {
// Anzahl der Blinkvorgänge.
for (int blink = 0; blink < scoreBlinkCount; blink++) {
// LEDs in der Mitte löschen.
FastLED.clear();
// Spielerzonen beibehalten.
paintPlayerZones();
// Anzeigen der Punkte von Spieler 1 (grün) links von der Mitte.
for (int i = NUM_LEDS / 2 - 1, count = 0; count < scorePlayer1 && i >= 0; i--, count++) {
leds[i] = CRGB::Green;
}
// Anzeigen der Punkte von Spieler 2 (rot) rechts von der Mitte.
for (int i = NUM_LEDS / 2, count = 0; count < scorePlayer2 && i < NUM_LEDS; i++, count++) {
leds[i] = CRGB::Red;
}
FastLED.show();
delay(500);
// LEDs in der Mitte ausschalten (für das Blinken).
for (int i = NUM_LEDS / 2 - scorePlayer1; i < NUM_LEDS / 2 + scorePlayer2; i++) {
if (i >= 0 && i < NUM_LEDS) {
leds[i] = CRGB::Black;
}
}
FastLED.show();
delay(500);
}
// Nach dem Blinken Spielerzonen erneut malen.
paintPlayerZones();
}
// Funktion zum Zurücksetzen des Spiels nach einer Runde.
void resetGame() {
// Spielvariablen zurücksetzen.
bluePosition = NUM_LEDS / 2;
previousBluePosition = bluePosition;
speed = maxSpeed;
// Zufällige Richtung wählen.
if (random(0, 2) == 0) {
direction = -1; // Nach links
} else {
direction = 1; // Nach rechts
}
// LEDs löschen.
FastLED.clear();
// Spielerzonen neu malen.
paintPlayerZones();
// Kurze Pause, bevor es weitergeht.
delay(1000);
}
// Funktion für den Gewinn-Effekt.
void winnerEffect(int player) {
// Toller Effekt für den Gewinner.
for (int i = 0; i < 5; i++) {
if (player == 1) {
// Spieler 1 hat gewonnen, alle LEDs grün machen.
fill_solid(leds, NUM_LEDS, CRGB::Green);
} else {
// Spieler 2 hat gewonnen, alle LEDs rot machen.
fill_solid(leds, NUM_LEDS, CRGB::Red);
}
FastLED.show();
delay(500);
// Alle LEDs ausschalten.
FastLED.clear();
FastLED.show();
delay(500);
}
// Punkte zurücksetzen.
scorePlayer1 = 0;
scorePlayer2 = 0;
resetGame();
}