zurück

Spiel "Alien Invasion"

09.07.2018

Die Idee zu diesem Geschicklichkeits- und Reaktionsspiel hatte ich spontan und wollte sie sogleich umsetzen.

Video: Live-Demonstration von "Alien Invasion"

Verwendete Bauteile

Für das Spiel

Für die "Licht-Kanone"

Spielverlauf

Ziel des Spiels ist zu verhindern, dass fremde Raumschiffe die Erde erobern.
Die Raumschiffe sind 5 rote LEDs, die in zufälligen Abständen aufleuchten. Direkt vor jeder LED ist ein Fotowiderstand (LDR), der mit einem Lichtstrahl von einem Laserpointer o.ä. beschossen werden kann. Sobald man diesen LDR triff, erlischt die entsprechende LED (d.h. das Raumschiff ist zerstört). Man bekommt pro zerstörtem Raumschiff einen Punkt und einen weiteren Schuss (zu Beginn des Spiels hat man 5 Stück). Das Spiel ist verloren, wenn man es nicht schafft, ein Raumschiff abzuschießen (zu langsam) oder die Munition alle ist.

Aufbau

Details zum Aufbau und Programmierung des OLED-Moduls siehe auch "Game Of Life" mit einem OLED-Display

Aufbau der Schaltung
Abb.: Aufbau der Schaltung

Sketch

/**
 * How to play:
 * Goal of the game is to shoot as many alien spaceships as possible.
 * At game start you have 5 shots. One of 5 red LEDs ("spaceship") lit randomly for a short
 * time and you have to shoot this spaceship as fast as possible. If you do not hit the
 * spaceship fast enough you loose and the game is over. After you hit the spaceship the
 * LED will go off. If you run out of shots the game is over, but for every successfully
 * hit spaceship you gain one more shot.
 */

#define PIN_PIEZO 6

#define AMOUNT_SPACESHIPS 5
#define AMOUNT_SHOTS_INIT 5

#define MAX_SPACESHIP_DELAY  2000 // in ms
#define MIN_SPACESHIP_DELAY   250 // in ms
#define SPACESHIP_DELAY_STEP  100 // in ms

#define TONE_SHOT  1
#define TONE_END_1 2
#define TONE_END_2 3

bool gameRunning;
byte pinLEDs[AMOUNT_SPACESHIPS] = {9, 10, 11, 12, 13};
byte pinLDRs[AMOUNT_SPACESHIPS] = {7,  2,  3,  4,  5};
int activeSpaceship;
byte shots;
unsigned int spaceshipDelay;
unsigned int score;
unsigned long shipAppearance;

void setup()
{
  Serial.begin(9600);
  randomSeed(analogRead(0));
  pinMode(PIN_PIEZO, OUTPUT);
  for (byte i = 0; i < AMOUNT_SPACESHIPS; i++) {
    pinMode(pinLEDs[i], OUTPUT);
    pinMode(pinLDRs[i], INPUT);
    digitalWrite(pinLEDs[i], LOW);
  }

  spaceshipDelay = MAX_SPACESHIP_DELAY;
  gameRunning = true;
  activeSpaceship = -1;
  score = 0;
  shots = AMOUNT_SHOTS_INIT;
  initAnimation();
}

void loop()
{
  if (gameRunning) {
    updateSpaceships();
    checkShoot();
  }
}

void updateSpaceships()
{
  if (activeSpaceship > -1) {
    if ((millis() - shipAppearance) > spaceshipDelay) {
      endGame();
    }
    return;
  }

  // delay between two spaceships
  delay(random(500, 3000));

  activeSpaceship = random(0, AMOUNT_SPACESHIPS);
  digitalWrite(pinLEDs[activeSpaceship], HIGH);
  shipAppearance = millis();
  if (spaceshipDelay > (MIN_SPACESHIP_DELAY + SPACESHIP_DELAY_STEP)) {
    spaceshipDelay -= SPACESHIP_DELAY_STEP;
  }
}

void checkShoot()
{
  if (activeSpaceship == -1) {
    return;
  }
  for (byte i = 0; i < AMOUNT_SPACESHIPS; i++) {
    if (digitalRead(pinLDRs[i]) == HIGH) {
      continue;
    }

    shots--;
    if (activeSpaceship == i) {
      // player hit spaceship
      digitalWrite(pinLEDs[activeSpaceship], LOW);
      activeSpaceship = -1;
      score++;
      shots++;
      tone(PIN_PIEZO, 400, 50);
      return;
    }
    if (shots <= 0) {
      endGame();
      return;
    }
  }
}

void initAnimation()
{
  Serial.println("Incoming alien ships...");
  for (byte i = 0; i < 9; i++) {
    for (byte j = 0; j < AMOUNT_SPACESHIPS; j++) {
      digitalWrite(pinLEDs[j], i%2);
    }
    delay(250);
  }
}

void endGame()
{
  gameRunning = false;
  Serial.println("GAME OVER");
  Serial.println("Final score: " + String(score));
  for (byte i = 0; i < 6; i++) {
    for (byte j = 0; j < AMOUNT_SPACESHIPS; j++) {
      digitalWrite(pinLEDs[j], i%2);
    }
    tone(PIN_PIEZO, 660 - (i%2 * 50));
    delay(300);
    noTone(PIN_PIEZO);
  }
  for (byte i = 0; i < AMOUNT_SPACESHIPS; i++) {
    digitalWrite(pinLEDs[i], LOW);
  }
}
Ausgabe des Spielstands in der seriellen Konsole
Abb.: Ausgabe des Spielstands in der seriellen Konsole