zurück

Spiel "Ladder"

20.06.2018

Dieses einfache Geschicklichkeits-Spiel habe ich öfters im Internet gefunden, wollte es aber nach eigenem Aufbau und Programmierung nachbauen.

Video: Live-Demonstration des Spiels

Verwendete Bauteile

Spielverlauf

Ziel des Spiels ist es, durch Drücken eines Knopfes an die Spitze einer (LED-)Leiter zu gelangen.
Sobald man den Spielknopf gedrückt hat, beginnt das Spiel. Während des Spiels wird automatisch immer zwischen der roten LED ganz unten und der aktuellen Leitersprosse (entsprechende farbige LED) hin- und hergewechselt. Der Spieler muss immer dann seinen Knopf drücken, wenn die LED der Leitersprosse leuchtet. Schafft der dies, so steigt er eine weiter Stufe der Leiter auf. Verpasst er dies, so ist das Spiel verloren. Sobald die oberste Stufe erreicht ist, hat der Spieler gewonnen.

Aufbau

Aufbau der Schaltung
Abb.: Aufbau der Schaltung

Sketch

/**
 * How to play:
 * After pressing the button to begin the game you have to press the button always
 * when a "Ladder-LED" is lit. When you press the button when the botton LED is lit
 * you loose the game. After finishing the top LED you win the game.
 */

#define LED_AMOUNT 12

#define BUTTON_PIN 13
#define DEBOUNCE_TIME 300   // in ms

#define GAME_STATE_RUNNING 1
#define GAME_STATE_WON     2
#define GAME_STATE_LOST    3
#define GAME_STATE_INIT    4

#define LED_CHANGE_INTERVAL 1000   // in ms

byte ledPins[LED_AMOUNT] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
byte gameState;
byte currentLedIndex;
byte toggleState;
unsigned long lastButtonClick;
unsigned long lastToggleChange;

void setup()
{
    for (byte i=0; i<LED_AMOUNT; i++) {
        pinMode(ledPins[i], OUTPUT);
    }
    resetLeds();
    pinMode(BUTTON_PIN, INPUT);

    lastButtonClick = 0;
    gameState = GAME_STATE_INIT;
}

void loop()
{
    switch(gameState) {
        case GAME_STATE_INIT:
            if (isButtonPressed()) {
                gameState = GAME_STATE_RUNNING;
                lastToggleChange = millis();
                currentLedIndex = 1;
                toggleState = 0;
            }
            break;
        case GAME_STATE_RUNNING:
            toggleLedState();
            if (isButtonPressed()) {
                checkGameState();
            }
            break;
        case GAME_STATE_WON:
            playWinningAnimation();
            gameState = GAME_STATE_INIT;
            break;
        case GAME_STATE_LOST:
            playLosingAnimation();
            gameState = GAME_STATE_INIT;
            break;
    }
}

bool isButtonPressed()
{
    if (millis() - lastButtonClick < DEBOUNCE_TIME) {
        return false;
    }
    if (digitalRead(BUTTON_PIN) == HIGH) {
        lastButtonClick = millis();
        return true;
    }
    return false;
}

void toggleLedState()
{
    if (millis() - lastToggleChange < (LED_CHANGE_INTERVAL-currentLedIndex*75)) {
        return;
    }

    toggleState++;
    toggleState %= 2;
    digitalWrite(ledPins[0], (toggleState + 1) % 2);
    digitalWrite(ledPins[currentLedIndex], toggleState);
    lastToggleChange = millis();
}

void checkGameState()
{
    if (toggleState == 0) {
        gameState = GAME_STATE_LOST;
    } else {
        currentLedIndex++;
        if (currentLedIndex >= (LED_AMOUNT - 1)) {
            gameState = GAME_STATE_WON;
        }
    }
}

void playWinningAnimation()
{
    resetLeds();
    for (byte iter=0; iter<15; iter++) {
        for (byte i=0; i<LED_AMOUNT; i++) {
            if ((iter+i) % 2 == 0) {
                digitalWrite(ledPins[i], HIGH);
            } else {
                digitalWrite(ledPins[i], LOW);
            }
        }
        delay(100);
    }
    resetLeds();
}

void playLosingAnimation()
{
    resetLeds();
    for (byte i=0; i<LED_AMOUNT; i++) {
        digitalWrite(ledPins[i], HIGH);
    }
    for (byte i=LED_AMOUNT-1; i>=0; i--) {
        digitalWrite(ledPins[i], LOW);
        delay(150);
    }
    resetLeds();
}

void resetLeds()
{
    for (byte i=0; i<LED_AMOUNT; i++) {
        digitalWrite(ledPins[i], LOW);
    }
}