Für ein weiteres Spiele-Projekt unseres Kunden H.U. Küster musste ich zunächst ein weiteres MAX7219 8x32 4 in 1 Dot Matrix LED Anzeigemodul (insgesamt werden vier benötigt) bestellen, um eine Spielfläche von 32x32 Leuchtpunkten zu erhalten. Aber die Erinnerungen wurden sofort geweckt, als er das Spiel beschrieb: Snake, die mit jedem geschluckten Punkt länger werdende Schlange, die weder den Rand noch den eigenen Körper berühren durfte. Dieses Spiel hatte ich auf meinem alten Nokia Handy, und es war nach einer langen Arbeitswoche der beste Zeitvertreib während der Wartezeit an der Elbfähre.
Die insgesamt vier Matrix LED Anzeigemodule habe ich wie bei der Großen Uhrzeitanzeige mit Tesa-Film zusammengeklebt, für den ersten Versuch vier Taster auf dem Steckbrett gegen Masse geschaltet und an die im Sketch verwendeten Pins gesteckt. Damit wird der verfressene Kopf der Schlange gesteuert und auch das Spiel startet erst, wenn ein beliebiger Taster zum ersten Mal gedrückt wird.
Spannungsversorgung für die Displays sind 5V und GND, am Anfang reicht die 5V-Buchse am Micro Controller mit ATMEGA 328P, jedoch je mehr LEDs leuchten, desto höher wird der Stromverbrauch, und man sollte eine externe Spannungsversorgung, die ja auch die MCU versorgen kann, in Betracht ziehen.
Verwendete Hardware:
1 |
||
4 |
||
1 |
Optional: PS2 Joystick Shield Game Pad Keypad V2.0 |
|
1 |
Optional: KY-023 Joystick-Modul |
|
1 |
Optional: KY-006 Passiver Piezo Buzzer Alarm Modul |
|
Steckbrett (Breadboard), Taster und Kabel (Jumper Wire) |
Bei den Datenleitungen für die Displays gilt zu beachten, dass die im Sketch verwendete Programm-Bibliothek LedControl.h" von Eberhard Fahle nur 8 hintereinander geschaltete Displays ansteuern kann. Da jedes Matrix-Modul bereits aus vier einzelnen Anzeigen besteht, können nur jeweils zwei Module per „Daisy Chain“ verbunden werden und beide Blöcke werden separat instanziiert.
// by Eberhard Fahle ist im Bibliotheksverwalter zu finden; Kann aber nur 8 Displays ansteuern.
byte Anzahl_Displays = 8;
LedControl block_1 = LedControl(12, 11, 10, Anzahl_Displays); // DIN; CLK; CS; 12-11-10
LedControl block_2 = LedControl(9, 8, 7, Anzahl_Displays); // DIN; CLK; CS; 9-8-7
Die Pinbelegung für die zwei Datenleitungen (jeweils DIN, CLK und CS) ergibt sich aus dem Sketch oder dem folgenden Schaltbild:
Der optionale Lautsprecher ist ein Piezo-Lautsprecher. Da der sehr hochohmig ist, kann man ihn direkt anschließen. Andere Lautsprecher müssen ggf. mit Vorwiderstand angeschlossen werden.
Noch einmal die einfachen Spielregeln: Sinn des Spieles ist, dass eine Schlange durch das Spielfeld gesteuert werden muss und als Ziel Punkte hat, die sie verspeist. Dabei wird sie jedes Mal um ein Glied länger. Dabei darf sie aber nicht über den Rand gehen oder sich selber treffen. Was am Anfang ziemlich einfach ist, wird aber mit wachsender Länge der Schlange immer schwieriger.
Am Anfang ist nur der Startpunkt zu sehen. Wird eine der Richtungstasten gedrückt, erscheint das erste Ziel und die Schlange beginnt sich zu bewegen.
Trifft die Schlange den Rand oder sich selber, wird das Spiel abgebrochen. Die Schlange löst sich Glied für Glied auf. Danach wird für einige Sekunden die Länge der Schlange angezeigt und das Spiel wird neu gestartet.
Wem das Spiel zu schnell oder zu langsam ist, kann die Geschwindigkeit in Zeile 137 verändern.
// Geschwindigkeit des Programms
delay(200);
In dieser Einstellung ist das Spiel am Anfang zwar etwas langsam, aber wenn man es dann in Bereiche über 50 geschafft hat, hat man ganz schön zu kämpfen. Hier der Original-Sketch von Herrn Küster zum Download.
Mein Problem beim Spielen war gelegentlich, dass die billigen Taster für das Steckbrett nicht immer den Richtungsbefehl annahmen und ich dann verlor. Das kann selbstverständlich auch an der Zeile delay(200); hier stoppt das Programm für 200ms und nimmt keine weiteren Eingaben an. Also mussten erstens bessere Taster her, z.B. die auf dem Joystick-Shield, das ich schon bei anderen Projekten verwendet hatte (zurzeit leider nur im AZ-Delivery Shop bei Amazon). Und zweitens eine Programmänderung, damit die Wartezeit nicht zur Blockade führt (engl. non-blocking). Dafür gibt es den Beispiel-Sketch BlinkWithoutDelay.
Die Buchsen für den oberen Teil des Displays (DIN=D12, CLK=D11, CS=D10) kann man auf dem Shield ablesen, ebenso DIN=D9 des unteren Teils der Anzeige. Dann bleibt eine Buchse frei (3V3). CLK kommt dann an KEY (dahinter verbirgt sich D8) und CS kommt in die nächste, unbeschriftete Buchse (=D7). Die Taster A bis D sind fest verdrahtet, liegen aber etwas anders als beim Aufbau von Herrn Küster. Also kurzerhand einige wenige Änderungen am Sketch in Zeile 60 vornehmen:
byte links = 5; byte unten = 4; byte oben = 2; byte rechts = 3; // Port für Tastenabfrage
Zum Glück fast die gleichen Pins, nur in anderer Reihenfolge; also keine Konflikte mit dem Display. Jedoch muss der optionale Piezo-Lautsprecher dann an Pin 6 angeschlossen werden.
Da mir die Leuchtpunkte etwas zu hell waren, habe ich kurzerhand in den Zeilen 73 und 76 noch die Intensität auf 1 gesetzt:
block_1.setIntensity(zw1, 1);
block_2.setIntensity(zw1, 1);
Weitere Änderungen waren notwendig für die Ersetzung des delay(200); durch eine if-Abfrage, ob seit der letzten Eingabe 200ms vergangen sind. Dafür benötigen wir am Anfang:
long int previousMillis = 0;
long int intervall = 200;
vor der entscheidenden do while-Schleife:
previousMillis = millis();
und dann
if (millis() - previousMillis >= intervall) {
schritt();
previousMillis = millis();
}
Über die Variable intervall können Sie wie oben beschrieben die Geschwindigkeit des Spiels variieren.
Hier der Sketch zum Download.
Damit waren meine Überlegungen nicht zu Ende, denn das Spiel müsste doch auch mit dem Joystick-Modul gut zu spielen sein.
Dafür müssen allerdings weitere Veränderungen am Sketch vorgenommen, denn die eingebauten Potentiometer liefern an den analogen Eingängen A0 und A1 Werte zwischen 0 und 1023, in der Mittelposition jeweils ca. 511.
Zu Beginn der void loop() Funktion gibt es zwei do while-Schleifen für die Anfrage der Taster (Buttons), einmal zum Start des Spiels und einmal für die Dauer des Spiels. Beide müssen wie folgt geändert werden:
// do while Schleifen
do {
// Abfrage des Joysticks Tasten und Festlegen der Richtung
if (analogRead(A0) > 850) {
richtung = 1;
}
else if (analogRead(A1) > 850) {
richtung = 2;
}
else if (analogRead(A0) < 150) {
richtung = 3;
}
else if (analogRead(A1) < 150) {
richtung = 4;
}
Tatsächlich konnte ich persönlich mit dem Joystick-Modul die meisten Punkte erringen. Auch der Joystick am o.g. Joystick-Shield nutzt im Übrigen die analogen Eingänge A0 und A1. Allerdings müssen dann die Zuordnungen der Richtung angepasst werden.
Hier der Download der Sketche für den analogen Joystick und für das Joystick-Shield mit Joystick und Buttons.
Viel Spaß beim Nachbauen und Spielen.
Haben Sie ein interessantes Projekt, über das wir an dieser Stelle berichten können? Schreiben Sie mir: Albrecht[at]AZ-Delivery.com