Soweit zur Theorie. Nun werde ich anhand eines kleinen Computer Spieles die Anwendung einer Programmier Sprache zeigen. Die verwendete Programmiersprache ist BASIC.
Das Spiel welches ich erstellen werde, basiert ursprünglich auf dem Film Tron und ist für zwei Spieler gedacht. Es soll in etwa so aussehen, daß man einen Pixel (Punkt auf dem Bildschirm), im Film Tron war es ein Motorrad, steuern kann und dieser eine Linie hinter sich zeichnet. Diese Linie bildet ein Wand und wenn einer der Spieler auf die Wand trifft bekommt der Gegner einen Punkt und das Spiel startet von neuem. Das Geschehen sieht man dabei von oben ohne Scrolling, damit der Programmieraufwand möglichst gering bleibt und die größte mögliche Übersicht gegeben ist. Weitere Eigenschaftes des Spieles werde ich später genauer erläutern. Dieses kleine Spiel habe ich vor einigen Jahren schon einmal in BASIC programmiert. Am zweiten Tag des Praktikums war wenig zu tun und da ich dort einen Computer zur Verfügung gestellt bekommen habe und dort Q-BASIC vorhanden war, habe ich dieses BASIC Programm erneut programmiert, um etwas Beschäftigung zu bekommen. Des weiteren habe ich dieses Spiel in den nächsten Tagen noch leicht verändert und optimiert. Da in den nächsten Tagen auch nicht besonders viel zu tun war, habe ich mir mit diesem Spiel und einem anderen Praktikanten, als zweiten Spieler, der dort die erste Woche war, die Zeit vertrieben.
Fangen wir also zuerst mal mit der Initialisierung des Grafik Bildschirms an, hierzu verwendet man das Kommando \"SCREEN 12\". Die Zahl gib den Grafik - Modus an, in diesem Fall 640*480 Pixel und 16 Farben. Nun wird die Steuerung erstellt, ich werde die gesamte weitere programmierung nur anhand eines Spielers genauer erklären, da beim zweiten Spieler nur leichte Modifikationen notwendig sind und ansonsten die gleichen Kommandos benutzt werden. Ich werde zwei verschiedene Steuermethoden integrieren, eine relative und eine absolute. Das soll heißen, der Spieler kann seinen Punkt mit 4 Tasten in die entsprechende Richtung steuern und bei der absoluten Steuerung kann man den Pixel mit 2 Tasten steuern, hierbei dient eine Taste für eine Rechts- bzw. Für eine Linkskurve. Die Tasten werden dabei mit dem \"INKEY$\" Kommando abgefragt. Um die Taste abzufragen wird jetzt die erste Variable eingeführt, nennen wir sie \"A$\", ihr wird nun \"INKEY$ zugewiesen. Das \"$\" Zeichen dient hier zur Kennzeichnung einer Zeichenketten - Variablen. Die Variable hat nun den Wert der gedrückten Taste auf der Tastatur. Um die Position des Punktes zu bestimmen werden jetzt noch die Variablen \"X\" und \"Y\" eingeführt. Um die Fahrtrichtung des Punktes zu bestimmen werden noch die Variablen \"M\" und \"N\" eingeführt, als Startwert für \"N\" wird -1 genommen, damit sich der Punkt nach oben bewegt, es sind zwei Variablen notwendig um einmal die Bewegung in X - Richtung und einmal die Bewegung in Y - Richtung zu kontrollieren. Damit sich die Koordinate des Pixel verändert addiert man \"M\" zu \"X\" und \"N\" zu \"Y\". Damit der Punkt letztendlich auch auf dem Bildschirm zu sehen ist nimmt man noch das Kommando \"PSET (X, Y), 4\" damit ein Pixel auf dem Bildschirm erscheint, die Zahl \"4\" gibt die Farbe des Pixel an, in diesem Fall rot. Damit das Programm nicht nach der ersten Ausführung abbricht wird noch eine Schleife eingeführt um das Programm fortlaufen zu lassen, bis die Taste \"Q\" gedrückt wird. Das Kommando \" \' \" dient zum einbringen von Kommentaren. Das Programm sieht zur Zeit so aus:
SCREEN 12 \' Initialisierung des Grafik Bildschirms
M = -1 \' Startwert für M
DO UNTIL A$ = \"Q\" \' Einleitung der Schleife
\' sie wird fortgeführt bis \"Q\" gedrückt wird
A$ = INKEY$ \' Abfrage der Tastatur
X = X + M \' den Pixel in X - Richtung verschieben
Y = Y + N \' den Pixel in Y - Richtung verschieben
PSET (X, Y), 4\' den Pixel auf den Bildschirm setzten
LOOP \' Ende der Schleife
Um die Abfrage für die Steuerung jetzt noch richtig zu integrieren habe ich das \"SELECT CASE\" Kommando genommen, damit ist es möglich durch einen gegebenen Fall aus einer Menge möglicher Kommandofolgen die richtige auszusuchen.
SELECT CASE A$ \' Einleitung der Auswahl
\' relative Steuerung
CASE \"w\" \' oben
IF N 1 THEN N = -1 : M = 0
CASE \"a\" \' links
IF M 1 THEN N = 0 : M = -1
CASE \"d\" \' rechts
IF M -1 THEN N = 0 : M = 1
CASE \"s\" \' unten
IF N -1 THEN N = 1 : M = 0
\' absolute Steuerung
CASE \"y\"
SELECT CASE m
CASE 1 \'rechts
m = 0
n = -1
CASE -1 \'links
m = 0
n = 1
CASE 0
SELECT CASE n
CASE -1 \'oben
m = -1
n = 0
CASE 1 \'unten
m = 1
n = 0
END SELECT
END SELECT
END SELECT
Dieser Programm Teil hat zur Folge, daß sich je nach gedrückter Taste der Pixel sich in die entsprechende Richtung bewegt. Die IF-THEN Abfrage bei der relativen Steuerung ist zwar nicht zwingend notwendig, aber verhindert in diesem Fall, daß der Punkt sich in die exakt gegenüber gesetzte Richtung bewegen kann. Das ist notwendig da er sonst auf der schon gezeichneten Linie fahren würde und dieses hatte ein Kollision mit derselben zur Folge. Dieses bringt uns nun zur Kollisionsabfrage, im Augenblick könnte der Punkt sich zwar auf dem Bildschirm bewegen und gesteuert werden, doch er könnte noch nicht mit den Wänden bzw. Linien kollidieren. Damit das Programm es merkt, wenn der Punkt mit einer Wand bzw. Linie kollidiert benutzte ich das \"POINT\" Kommando es liefert die Farbe der angegebenen Koordinate. Also müßte die Zeile für die Kollisionsabfrage in etwa so aussehen:
IF POINT(X, Y) = 4 THEN
{Ereignis Folge}
END IF
Das heißt wenn der Pixel auf einen roten Punkt einer Linie trifft wird eine Ereignis Folge ausgelöst, die ich aber erst später genau beschreiben werden. Für Test Phase kann man das \"BEEP\" Kommando dort einbauen, welches bewirkt, daß der PC kurz piept, so kann man gut nachprüfen ob keine Fehler vorhanden sind. Ein Fehler den man zum Beispiel hätte machen können wäre das verwenden einer falschen Farbe, so wäre der Pixel niemals kollidiert. Wichtig ist zudem, daß man die Kollisionsabfrage vor dem setzten des Pixel durchführt, da sonst der Pixel jedesmal kollidieren würde da er ja selber rot ist. Ist die Kollisionsabfrage jedoch korrekt gesetzt so wird erst geprüft ob schon ein Pixel auf der Position X Y vorhanden ist und wenn nicht dann wird ein neuer Pixel gesetzt und sonst eine Ereignis Folge ausgelöst. Damit der Pixel nicht außerhalb des Bildschirmes gelangen kann muß das Spielfeld entsprechend mit Linien begrenzt werden, diese müssen auch rot sein, damit die Kollisionsabfrage diese erfassen kann oder ansonsten müßte man die Kollisionsabfrage entsprechend erweitern, wie man es für den zweiten Spieler tun muß, wenn er eine andere Farbe haben soll.
In dem jetzigen Stadium ist das Programm fähig ein Punkt über den Bildschirm zu steuern und die Kollision von Punkt und Wand zu registrieren.
Nun werden ich die Ereignis Folge für die Kollisionsabfrage genauer beschreiben. Wenn der Punkt Kollidiert soll es eine kleine Explosion geben, der Punkte stand soll entsprechend verändert werden und das Spiel soll wieder zu seiner Ausgangs Position zurück kehren und eine neue Runde soll beginnen.
Um die Explosion zu realisieren werde ich ein Unterprogramm schreiben, das heißt man kann durch den Aufruf des Unterprogrammes die Explosion auf den Bildschirm zeichnen ohne daß man die Kommandos für die Explosion jedesmal neu schreiben muß, so wird der Quell - Code leichter verständlich und das Programmieren ist angenehmer denn so braucht man nur noch eine Zeile um eine Explosion zu bewerkstelligen und ohne dieses Unterprogramm brauchte man acht Zeilen. Das Unterprogramm würde dann so aussehen:
SUB Explo (EX AS INTEGER, EY AS INTEGER)
FOR R = 1 TO 40 STEP 1
CIRCLE (EX, EY), R, 2
CIRCLE (EX, EY), R/2, 10
NEXT R
FOR R = 0 TO 40 STEP 1
CIRCLE (EX, EY), R, 0
NEXT R
END SUB
Und ein Aufruf des Unterprogrammes so:
CALL Explo (X, Y)
Die oberste Zeile definiert den Namen des Unterprogrammes und welche Variablen bei einem Aufruf übergeben werden. In diesem Beispiel Aufruf sind es die Variablen X und Y, die die Koordinaten der Explosion angeben ihr Wert wird an die Variablen des Unterprogrammes EX und EY übergeben. Das Unterprogramm ist angesehen von diesen zwei Variablen völlig unabhängig vom Rest des Programmes.
Die zweite Zeile von SUB Exlpo ( ) leitet eine FOR - Schleife ein, daß heiß eine Variable, hier \"R\" wird von fortlaufend verändert. In diesem Fall wird sie von 1 nach 40 geändert und das mit einer Schrittweite (STEP) von 1, das heißt R nimmt die Werte 1, 2 , 3 , ... , 39, 40 an. Das \"Circle\" Kommando zeichnet einen Kreis mit Radius \"R\" und Farbe 2 (grün) bzw. Farbe 10 (hellgrün). Beim zweiten \"CIRCLE\" ist der Radius R/2 damit die Mitte der Explosion heller ist als das Äußere der selben und so einfach nur schöner aussieht. Die zweite FOR - Schleife hat nur den Sinn die Gezeichnete Explosion wieder vom Bildschirm zu löschen. Es wird zwar auch noch ein \"CLS\" (Clear Screen, Bildschirm löschen) durchgeführt doch mit der zweiten FOR - Schleife wird ein schönere Effekt erzielt.
Damit wäre CALL Exlpo (X, Y) das erste Kommando der Ereignis Folge bei einer Kollision, nun muß noch der Punkte stand des Gegners erhöht werden dazu werden die Variablen \"P1\" und \"P2\" benutzt, eine jeweils für den dazugehörigen Spieler. Nun müssen noch alle anderen Variablen (\"X\", \"Y\", \"M\", ...) wieder auf ihren Ursprungs Wert gesetzt werden. Dazu werden am Anfang des Programmes Konstanten definiert wie zum Beispiel \"StartX\", \"StartY\", usw. und die entsprechenden Variablen dann gleich dieser Konstanten gesetzt. Konstanten werden hier deshalb anstatt von Zahlen benutzt da man so ihre Werte später leichte ändern kann und so der Quell - Code leichter verständlich wird.
Zwei weiter Unterprogramme werden jetzt noch benötigt eines um die Punktzahl auf dem Bildschirm anzuzeigen und eines um den Screen neu aufzubauen (Rechteck zum begrenzen des Spielfeldes zeichnen). Das erste Unterprogramm würde dann so aussehen:
SUB ShowScore (P1 AS INTEGER, P2 AS INTEGER)
LOCATE 1, 1: PRINT \"PUNKTE ->\",
PRINT \"Player 1:\"; P2,
PRINT \"Player 2:\"; P1
END SUB
Das Kommando \"PRINT\" schreibt den in Anführungszeichen stehenden Text, ausgehend von der aktuellen Cursor Position, auf den Bildschirm. Mit dem \"LOCATE\" Kommando wird der Cursor auf die Entsprechende stelle gesetzt, in diesem Fall die linke - obere Ecke. Das Semikolon bewirkt das der Nachfolgende Text oder die Variable direkt an die letzte Textausgabe angeschlossen werden, ohne einen Zeilenumbruch wie er normalerweise entstehen würde. Das Komma bewirkt das selbe nur läßt es einen größeren Abstand. Das zweite Unterprogramm besteht praktisch nur aus fünf Zeilen:
SUB SetScr
CLS
LINE (minX, minY)-(maxX, minY), 2
LINE (minX, minY)-(maxX, minY), 2
LINE (minX, minY)-(maxX, minY), 1
LINE (minX, minY)-(maxX, minY), 1
END SUB
Mit dem Kommando \"LINE\" kann man eine Linie von der einen angegebenen Koordinate zur anderen ziehen, die letzte Zahl gibt hier wieder die Farben an. Die Koordinaten sind hier wieder Konstante die am Anfang des Programmes Definiert werden, um sie einfacher verändern zu können. Daß die Linien für den Rand verschiedene Farben habe hat keinen technischen Grund sondern ist einfach der Optik wegen.
Damit wäre das Programm in etwa fertig, es müßte nur noch die Steuerung und alles andere für den zweiten Spieler programmiert und noch einige Änderungen bezüglich der Farbe vorgenommen werden.
Nachdem dieses geschehen ist das Programm betriebsbereit, aber noch nicht zwangsläufig Fehlerfrei. Deshalb ist es im Augenblick nur eine Beta Version, das heißt das Programm ist zwar fertig, aber kann noch Fehler haben und wird deshalb noch getestet. Die Alpha Phase habe ich in diesem Fall übersprungen, da sie praktisch während des Programmieren ablief.
Während der Beta Phase stellten sich zwei wesentlich Fehler heraus, erstens waren die Spieler zwar in verschiedenen Farben, aber es war nicht immer genau klar wer nun eigentlich gewonnen hatte und zweitens war das Unterprogramm falsch im Quell - Text integriert, das bedeutete, daß bei jedem Programm Durchlauf die Punktzahl auf den Bildschirm geschrieben wurde. Der zweite Fehler war leicht zu beheben, der Aufruf für das Unterprogramm mußte nur so plaziert werden, daß er nur am Ende einer Runde aufgerufen wird, da so nur die Punktzahl auf den Bildschirm geschrieben wird wenn sie sich verändert, das hat zwar keinen richtigen Vorteil, macht das Spiel aber deutlich schneller und läßt es so auch auf langsameren PC lauf fähig und läßt dem Programmierer mehr Ressourcen frei für eventuelle Erweiterungen. Das erste Problem war von etwas anderer Natur, hier konnte man zwar den Gewinner der jeweiligen Runde an der Punktzahl ablesen, aber das erwies sich als unpraktikabel und so entschloß ich mich einfach die Farben für die Explosion abhängig zu machen vom Spieler der die Runde verloren hat. Außerdem entschied ich mich noch dafür die Angabe der Punktzahlen den Farben der Spieler anzupassen. In der Praxis erwiesen sich diese Änderungen als sehr nützlich und hilfreich.
Ein weiterer \"Fehler\" der sich in der weiteren Testphase heraus stellte war der, daß wenn sich die beiden Spieler aufeinander zu bewegen und einer dabei von oben bzw. unten und der andere von links bzw. rechts kommt und sie sich zum exakt gleichen Zeitpunkt treffen, sie durcheinander durch fahren und die Kollisionsabfrage scheitert. Dieses liegt daran, daß die beiden Punkte erst gezeichnet werden nachdem die Kollisionsabfrage und die Bewegung statt gefunden haben, da sie sich so beide auf dem gleichen Punkt befinden können, aber die Kollisionsabfrage nicht anspricht da die Pixel noch nicht gesetzt sind. Der Fehler ließe sich zwar mit einem Koordinaten Vergleich oder einer umordnung der Programmaufrufe beheben, aber ich entschloß mich diesen \"Fehler\" bestehen zu lassen, da er nur sehr selten Auftritt, zu keiner unfairen Beeinflussung des Spieles führt und mehr zur Erheiterung der Spieler beiträgt, als daß er Schaden anrichtet.
Den kompletten Quell-Code zu diesem Q-BASIC Spiel gibt es hier.
|