Spiel "8-Bit Reaction"

Video: Live-Demonstration des Spiels "8-Bit Reaction"

Verwendete Bauteile

Spielverlauf

Es gibt 8 RGB-LEDs und dazu passend 8 Taster. Nach Spielbeginn startet ein Timer, der genau 60 Sekunden lang läuft. Während dieser Zeit muss der Spieler so schnell wie möglich die Taster bei den jeweils aufleuchtenden blauen LEDs drücken. Schafft er dies, dann leuchtet die LED kurz grün auf und er bekommt einen Punkt. Wenn ein falscher Taster gedrückt wird (d.h. entsprechende LED ist dunkel), dann leuchtet die LED rot und ein Punkt wird abgezogen.
Wenn die 60 Sekunden Spielzeit vorbei sind, endet das Spiel und die erreichte Punktezahl wird binär kodiert über die LEDs angezeigt. Ein erneuter Knopfdruck auf einen beliebigen Taster startet das Spiel erneut.

Aufbau der Schaltung

Details zum RGB-Modul siehe: RGB-LED-Modul WS2812B.

Aufbau der Schaltung

Sketch

/**
 * How to play:
 * Within the fixed game time of 60 seconds the player has to press the
 * button next to a blue lighting LED. After the time is up the score is
 * shown in binary coded LEDs.
 */

#define PIN_LED_MATRIX 8
#define PIN_BUTTON_1  5
#define PIN_BUTTON_2  6
#define PIN_BUTTON_3  7
#define PIN_BUTTON_4  4
#define PIN_BUTTON_5 10
#define PIN_BUTTON_6 11
#define PIN_BUTTON_7 12
#define PIN_BUTTON_8 13

#define AMOUNT_LEDS 8

#define GAME_INIT    0
#define GAME_END     1
#define GAME_RUNNING 2

#define RED   1
#define GREEN 2
#define BLUE  3
#define BLACK 4

#define GAME_RUNNING_TIME 30 // in seconds

#include <Adafruit_NeoPixel.h>

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(AMOUNT_LEDS, PIN_LED_MATRIX, NEO_GRB + NEO_KHZ800);
byte gamePhase = GAME_INIT, gameScore, pressedButton;
byte buttons[AMOUNT_LEDS] = {PIN_BUTTON_1, PIN_BUTTON_2, PIN_BUTTON_3, PIN_BUTTON_4, PIN_BUTTON_5, PIN_BUTTON_6, PIN_BUTTON_7, PIN_BUTTON_8};
unsigned long litLeds[8], timeGameEnd, nextLedAction;

void setup()
{
  randomSeed(analogRead(A0));
  for (byte i = 0; i < AMOUNT_LEDS; i++) {
    pinMode(buttons[i], INPUT_PULLUP);
  }
  pixels.begin();
  resetLEDs();
}

void loop()
{
  switch (gamePhase) {
    case GAME_INIT:
      while (getPressedButton() == 0);
      initGame();
      break;
    case GAME_END:
      gameOverAnimation();

      // show gameScore as binary
      for (byte i = 0; i < AMOUNT_LEDS; i++) {
        if (bitRead(gameScore, i) == 1) {
          toggleLed(AMOUNT_LEDS - 1 - i, GREEN);
        } else {
          toggleLed(AMOUNT_LEDS - 1 - i, BLACK);
        }
      }
      pixels.show();
      gamePhase = GAME_INIT;
      break;
    case GAME_RUNNING:
      updateLeds();
      checkButtons();
      if (timeGameEnd < millis()) {
        gamePhase = GAME_END;
      }
      break;
  }
}

void initGame()
{
  timeGameEnd = millis() + (byte)GAME_RUNNING_TIME * 1000L;
  nextLedAction = millis() + 100;
  for (byte i = 0; i < AMOUNT_LEDS; i++) {
    litLeds[i] = 0;
  }
  gameScore = 0;
  gamePhase = GAME_RUNNING;
  initAnimation();
}

void initAnimation()
{
  for (byte j = 0; j < 6; j++) {
    for (byte i = 0; i < AMOUNT_LEDS; i++) {
      if (i % 2 == j % 2) {
        toggleLed(i, GREEN);
      } else {
        toggleLed(i, BLACK);
      }
    }
    pixels.show();
    delay(200);
  }
  resetLEDs();
  delay(1000);
}

void gameOverAnimation()
{
  for (byte j = 0; j < 6; j++) {
    for (byte i = 0; i < AMOUNT_LEDS; i++) {
      if (j % 2) {
        toggleLed(i, RED);
      } else {
        toggleLed(i, BLACK);
      }
    }
    pixels.show();
    delay(200);
  }
  resetLEDs();
}

void resetLEDs()
{
  for (byte i = 0; i < AMOUNT_LEDS; i++) {
    toggleLed(i, BLACK);
  }
  pixels.show();
}

void updateLeds()
{
  for (byte i = 0; i < AMOUNT_LEDS; i++) {
    if (litLeds[i] > 1 && litLeds[i] < millis()) {
      litLeds[i] = 0;
      toggleLed(i, BLACK);
    }
  }

  if (millis() > nextLedAction) {
    byte nextIndex = random(AMOUNT_LEDS);
    if (litLeds[nextIndex] == 0) {
      litLeds[nextIndex] = 1;
      toggleLed(nextIndex, BLUE);
      nextLedAction = millis() + random(120, 1500);
    }
  }

  pixels.show();
}

void checkButtons()
{
  byte firstPressedButton = getPressedButton();
  if (firstPressedButton == 0) {
    return;
  }

  byte ledIndex = firstPressedButton - 1;
  if (litLeds[ledIndex] == 1) {
    toggleLed(ledIndex, GREEN);
    gameScore++;
  } else {
    toggleLed(ledIndex, RED);
    if (gameScore > 0) {
      gameScore--;
    }
  }

  pixels.show();
  litLeds[ledIndex] = millis() + 300;
}

void toggleLed(byte ledNum, byte type)
{
  uint32_t color;

  switch (type) {
    case RED:
      color = pixels.Color(25, 0, 0);
      break;
    case GREEN:
      color = pixels.Color(0, 25, 0);
      break;
    case BLUE:
      color = pixels.Color(0, 0, 25);
      break;
    case BLACK:
      color = pixels.Color(0, 0, 0);
      break;
  }

  pixels.setPixelColor(ledNum, color);
}

byte getPressedButton()
{
  byte currentButtonPress = 0;
  for (byte i = 0; i < AMOUNT_LEDS; i++) {
    if (!digitalRead(buttons[i])) {
      currentButtonPress = i + 1;
      break;
    }
  }

  if (currentButtonPress == 0) {
    pressedButton = 0;
    return 0;
  } else {
    if (currentButtonPress != pressedButton) {
      pressedButton = currentButtonPress;
      return currentButtonPress;
    }
    return 0;
  }
}
zurück