AB16 – Spiel “Meteorit”
AB16 – Spiel “Meteorit”
In dieser Aufgabe geht es darum, das einfache Meteor-Spiel zu verstehen und anzupassen.
Lade als erstes das Spiel sample12 und spiele es.
Im Spiel fällt ein Meteor vom oben zum unteren Rand. Das Raumschiff besteht aus zwei Häusschen,
welche man mit den Tasten links und rechts schieben kann. Wenn der Meteor mit dem Raumschiff
kollidiert, ist das Spiel zu ende.
Auf dem Bild siehst du, Zellennummern. Das Raumschiff aktuell bei der Position x=3, y=1 und das
Raumschiff belegt zwei Zellen x=2,y=7 und x=3,y=7.
Auf der folgenden Seite findest Du das ganze Programm erklärt, danach kommen die Aufgaben.
Hilfestellungen und Tipps:
- gemeinsam arbeiten
- Klammern, Strichpunkte und Gross- und Kleinschreibung exakt beachten
- nur wenige Anpassung auf einmal machen
- häufiges Testen des Programms
- nötigenfalls nochmals von vorne beginnen, wenn es nicht weitergeht
- bei Bedarf kann das Beispiel sample12b beigezogen werden
AB16 – Spiel “Meteorit”
Dokumentiertes Beispiel sample12:
#include "OXOcardRunner.h"
void setup() {
clearDisplay();
}
Im Setup löschen wir den Bildschirm.
A
byte ship_x = 0;
byte ship_y = 7;
byte meteor_x = 0;
byte meteor_y = 0;
bool stopped = false;
ship_x und ship_y speichern die Position des
Raumschiffs, in meteor_x und meteor_y wird die
Position des Meteors gespeichert. Beim Spielen hast
du bemerkt, dass das Spiel stoppt, wenn du getroffen
bist. Wenn das der Fall ist, wird die Variable
„stopped“ auf „true“ gesetzt
void loop() {
Wir sind in der Loop-Schleife.
B
handleAutoTurnOff(120);
Diese Anweisung stellt den Computer nach 120
Sekunden ab.
C if (stopped) {
if (isMiddleButtonPressed()) {
stopped = false;
} else {
return;
}
}
Wir testen, ob das Spiel gestoppt ist und bleiben in
dem Zustand, bis die mittlere Taste gedrückt wird.
Return stoppt die Ausführung von Loop und beginnt
dann wieder von vorne.
D
clearDisplay();
drawPixel(meteor_x, meteor_y, 80);
drawPixel(ship_x, ship_y);
drawPixel(ship_x + 1, ship_y);
Wir zeichnen den Meteor und dann das Raumschiff.
Letzteres besteht aus zwei nebeneinanderliegenden
Pixeln, daher „ship_x +1, ship_y“.
E
if ((ship_x == meteor_x ||
ship_x + 1 == meteor_x)
&& ship_y == meteor_y) {
drawRectangle(0, 0, 8, 8, 255);
tone(100, 1000);
ship_x = 0;
ship_y = 7;
stopped = true;
}
Stimmt die Koordinate des Raumschiffs mit der des
Meteors überein? Dann haben wir eine Kollision und
das Spiel ist zu Ende. Wir zeichnen ein Rechteck,
lassen einen tiefen Ton spielen und dann setzen wir
die Spielvariablen wieder in den Ursprung.
F
if (isLeftButtonPressed()) {
if (ship_x > 0) {
ship_x = ship_x - 1;
} else {
ship_x = 0 ;
}
}
Wenn der linke Button gedrückt ist, schieben wir das
Schiff nach links, ausser wir sind schon am Rand.
G if (isRightButtonPressed()) {
if (ship_x < 6) {
ship_x = ship_x + 1;
} else {
ship_x = 6;
}
}
Wenn wir den rechten Button drücken, schieben wir
das Schiff nach rechts bis zum Rand
H meteor_y = meteor_y + 1;
if (meteor_y > 7) {
meteor_x = random(8);
meteor_y = 0;
}
Hier bewegen wir den Meteor um eine Position nach
unten. Wenn der Meteor unten angekommen ist,
legen wir eine neue Ausgangs-position mit der
Zufallsfunktion random fest und beginnen wieder von
oben.
I
delay(50);
}
Dieser Delay-Aufruf stellt sicher, dass das Spiel nicht
zu schnell wird.
AB16 – Spiel “Meteorit”
Gib mir einen Beep!
Mit dieser Erweiterung hörst du einen regelmässigen Beep, quasi eine Art Herzschlag des Spiels.
Diese Erweiterungen geht so:
Ergänze im Block A einen Variable:
byte loop_counter = 0;
Diese Variable zählt die Durchgänge des Loop-Blocks und wir brauchen Sie bei dieser Passage, die
du zwischen H und I einsetzt:
if (loop_counter < 10) {
loop_counter = loop_counter + 1;
} else {
loop_counter = 0;
tone(1000, 50);
}
Dieser Block wird bei jedem Durchgang, d.h. alle 50 Millisekunden einmal ausgerufen. Wenn die
Variable loop_counter noch nicht 10 ist, wird sie um eins erhöht. Wenn wir 10 erreicht habe, wird die
Variable wieder auf 0 gesetzt, damit sie wieder bis 10 zählen kann und ein Signalton wird ausgeführt.
Ergänze zusätzlich die Zeile
noTone();
im Block E gleich vor der Zeile „tone(100,1000).
Du kannst hier folgendes ändern: wenn du die Zahl 10 verringerst, wird der Beep schneller,
umgekehrt langsamer. Bei der tone-Funktion kannst du einen beliebigen Ton hinterlegen, der dir
gefällt.
Schneller!
Viele Spiele werden schneller, je länger man sie spielt. Das möchten wir natürlich auch machen.
Hierzu sind folgende Ergänzungen zu machen:
Im Block C schreibst du vor dem return-Befehl folgendes:
resetTimer();
Ersetze nun den I-Block, d.h. die Delay-Anweisung mit folgendem Code:
int seconds = getTimerSeconds();
if (seconds < 5) {
delay(50);
} else if (seconds < 10) {
delay(40);
} else {
delay(30);
}
Wir verwenden hier zwei neue Befehle „resetTimer“ und „getTimerSeconds()“. Der Befehl
„getTimerSeconds“ gibt die Anzahl der Sekunden zurück, seit das Gerät gestartet wurde, bzw. seit
dem letzten Aufruf von „resetTimer“. Die Anweisungen machen nun folgendes. Bei jedem Neustart
bzw. Fehler setzen wir den Timer wieder zurück. Im zweiten Block fragen wir ab, wie viele Sekunden
AB16 – Spiel “Meteorit”
bereits vergangen sind. Unter 5 Sekunden warten wir 50 Millisekunden, zwischen 5 und 10 Sekunden
warten wir etwas weniger lang und wenn es über 10 Sekunden dauert, geben wir uns noch noch
ganz kurze Pausen, mit dem Effekt, dass das Spiel immer schneller wird.
Du kannst hier die Intervalle ändern und natürlich auch die Geschwindigkeit. Du kannst nach
demselben Muster auch weitere Abstufung einbauen, z.B. 50, 40, 30, 20.
Spiel-Intro
Jedes Spiel hat ein Intro, d.h. eine Einleitung, die abgespielt wird, bevor das Spiel startet.
Ersetze im A-Block die Zeile
bool stopped = false;
mit
bool stopped = true;
Ergänze im C-Block vor dem „return“ folgende Zeile:
drawIntro();
Das ist ein Funktionsname für eine Funktion, die wir ganz am Schluss des Codes deklarieren wollen.
Hier findest du den Code dazu:
void drawIntro() {
clearDisplay();
drawImage(0b11100111,
0b10000101,
0b10100101,
0b11100111,
0b00000000,
0b00000000,
0b00000000,
0b00000000);
delay(300);
clearDisplay();
drawImage(0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b01111110,
0b00111100,
0b00011000,
80);
delay(300);
}
Dieser Block zeichnet zwei Bilder, die aus Nullen und Einsen aufgebaut sind. Du kannst sie erkennen,
wenn du dieses Blatt etwas weiter vom Kopf weghältst und die Augen etwas zusammenkneifst.
„clearDisplay“ löscht den Bildschirm, „drawImage“ zeichnet das Bild, „delay“ wartet die Anzahl
Millisekunden, die du angibst.
Du kannst folgendes anpassen: Du kannst weitere Bilder ergänzen, bzw. die bestehenden abändern.
Du kannst natürlich auch Geräusche mit dem „tone“-Befehl ergänzen.
AB16 – Spiel “Meteorit”
Eigene Crash-Animation
Nach demselben Prinzip wie die Intro-Animation aufgebaut ist, möchten wir nun eine Crash-
Animation programmieren, die dann abgespielt wird, wenn das Raumschiff mit dem Meteor
zusammenstösst.
Ersetze bitte folgende Zeilen im Block E:
drawRectangle(0, 0, 8, 8, 255);
noTone();
tone(100, 1000);
Mit folgender Zeile:
noTone();
drawGameOver();
(Wenn du das Beep-Beispiel nicht gemacht hast, fehlt dir möglichweise die Zeile „noTone();“.)
Dann fügst du ganz unten am Programm folgende Subroutine ein:
void drawGameOver() {
for (int i = 0;i<1000;i++) {
byte x = random(8);
byte y = random(4);
byte b = random(255);
drawPixel(x,4+y,b);
tone(random(200));
}
noTone();
}
Die Funktion zeichnet unterschiedliche Pixel in unterschiedlicher Helligkeit und dazu wilde Töne!
Du kannst hier auch mit der Funkton drawPixel(..) und delay(..) mehrere Bilder hintereinander
anzeigen und so eine kleine Animation abspielen.
Dostları ilə paylaş: |