C++

Einleitung

In der folgenden Facharbeit werden ich ein wenig auf die Geschichte der Programmiersprachen, ihren Aufbau und ihre Verwandtschaft zueinander eingehen. Dabei werde ich mich vor allem auf die, im professionellen Bereich am meisten verbreitete Programmiersprache C / C++ konzentrieren. Anschließend werde ich anhand eines Beispiel Programms den Vorgang der Programmierung in der Praxis erläutern und die Probleme beschreiben die dabei auftreten können. Mein Praktikum, welches ich bei der Stadt Bielefeld in der Abteilung für Technikunterstützte Informationsverarbeitung (TuI) im Neuen Rathaus verbracht habe werde ich dabei nicht berücksichtigen, da mein Tätigkeitsbereich dort sehr eingeschränkt war. Die einzigen Aufgaben, die mir zugeteilt wurden, waren meist PCs oder PC-Zubehör vom Lager in ein Büros zu bringen oder umgekehrt. Des weiteren durfte ich einmal einen Schaltschrank zusammenschrauben, bei zwei PCs die Festplatten formatieren und noch in einer Außenstelle PCs verkabeln. Insgesamt lässt sich sagen das mindestens fünfzig Prozent der Zeit in der ich dort war nichts zu tun war, das lag daran, dass zu diesem Zeitpunkt mehrere Leute wegen Krankheit ausgefallen waren. Deshalb fand ich das Praktikum zeitweise etwas Langweilig, aber da ich dort einen PC zur Verfügung gestellt bekommen habe, über den ich die zwei Wochen frei verfügen konnte hielt sich die Langeweile in Grenzen. Die Zeit, in der nichts zu tun war, verbrachte ich damit, meine Programmierkenntnisse etwas zu vertiefen. So habe ich während, dieser zwei Wochen eine Menge über das Programmieren in C erfahren, beziehungsweise mir selbst beigebracht. Des weiteren habe ich noch etwas über das Städtische Netzwerk gelernt, über die Funktionsweise, Probleme und die Absicherung für den Datenschutz. Doch um darauf näher einzugehen, fehlt mir das erforderliche Fachwissen, da ich während meiner Praktikums Zeit nur einen kleinen Einblick in diesen Themenkomplex bekommen habe. Am vorletzten Tag des Praktikums hatte ich dann die Möglichkeit, mit einem der dortigen "Programmierer" zu sprechen. Zu meiner Enttäuschung stelle ich fest, dass sich die Aufgaben für den Programmierer dort praktisch nur auf den Bereich der Fehlerbehebung beziehen. Die Programmierer dort programmieren nahezu keine Anwendungen selbst, sondern passen nur gegebene Programme an die jeweiligen Aufgabenbereiche an oder korrigieren Fehler in bestehenden Programmen. Die dort eingesetzte Programmiersprache stellt COBOL dar. Außerdem werden dort noch einige Programmteile in Assembler geschrieben. Des weiteren wird noch teilweise Access, ein speziell für die Verwaltung von Datenbanken ausgelegtes Programm eingesetzt. Mit COBOL werden die Programme geschrieben bzw. verändert die im städtischen Netzwerk betrieben werden. Access wird im Gegensatz zu COBOL jedoch nur als Einzelplatz Anwendung eingesetzt, da es mehr Speicherplatz verbraucht und somit nicht so gut als Netzwerk Anwendung geeignet ist.

Programmiersprachen

Programmiersprachen sind Sprachen, die dazu dienen, Anwendungen auf dem Computer zu erstellen. Da ein Computer nur die Maschinensprache versteht, die von Maschine zu Maschine unterschiedlich ist. Die eigentliche Maschinensprache ist extrem schwer bis gar nicht zu verstehen, deshalb wurde die Sprache Assembler entwickelt. Assembler ist eine Programmiersprache, die jedem Maschinenbefehl einen entsprechenden symbolischen Namen gibt, so werden die Maschinenbefehle leichter verständlich. Ein Beispiel für Assembler siehe ungefähr so aus:

mov ax, 0x0e07
xor bx, bx
int 0x10

Der so entstandene Quell Code kann jedoch nicht ausgeführt werden, sondern muss erst in Maschinensprache umgewandelt werden. Dazu gib es im wesentlichen zwei Wege, einmal den Weg über einen Compiler, andererseits den Weg über den Interpreter. Der Interpreter setzt dabei den Quell Code in Echtzeit in die Maschinenbefehle um und ermöglicht so das direkte ausführen des Quell Codes mit Hilfe des Interpreters ohne längere Wartezeiten und ist so nützlich, um kleinere Probleme zu finden und zu beheben. Der Compiler geht einen ähnlichen Weg, nur setzt er den Quell Code nicht in Echtzeit um, sondern übersetzt den Quell Code zuerst komplett in Maschinen Sprache.

Der Weg, den der Compiler dabei geht führt oft vorher über einen Precompiler (C, C++), dieser sorgt dafür, dass statt Symbolischen Konstanten die entsprechenden Zahlen gesetzt werden und das Makros entsprechend eingesetzt werden, außerdem werden hierbei noch die Kommentare im Quell Code entfernt. Der so vorbearbeitete Quell Code wird nun an den Compiler übergeben.

Der Vorteil von Assembler liegt darin, dass jedem Befehl im Quell Code genau ein Maschinenbefehl zugeordnet ist und so die Übersetzung extrem leicht fällt. Ein zweiter Vorteil von Assembler ist, dass man damit extrem Maschinen Nah programmieren kann, was die Voraussetzung für schnelle Programme ist. Der Nachteil an Assembler liegt in der Portabilität, das heißt Assembler Programme können nur auf einem bestimmten Rechnertyp laufen. Höhere Programmiersprachen, z.B. C/C++, gehen einen anderen Weg. Sie sind nicht so konzipiert, dass sie jedem Maschinenbefehl genau ein Kommando gegenüberstellen, sondern arbeiten mit abstrakteren Befehlen, die im allgemeinen leichter verständlich sind. Ein berühmtes Beispiel Programm in C währe:

#include <stdio.h>
> main () {
printf ("hello, world\n");
}

Dieses Programm würde den Text hello, world auf den Bildschirm schreiben.

Im wesentlichen bestehen alle modernen Programmiersprachen im wesentlichen aus zwei Bestandteilen, Variablen und Funktionen. Einige Programmiersprachen unterscheiden noch zwischen Funktionen und Prozeduren, aber in C gibt es zwischen ihnen keinen wesentlichen Unterschied. Eine Variable ist ein Objekt, welches je nach Klassifizierung den Wert einer Ganzzahl (Integer), Kommazahl (Float), eines Buchstabens (Char) oder eines Wortes (String) annehmen kann, unter Umständen stehen jedoch noch mehr Typen zur Klassifizierung zur Verfügung. Meist müssen Variablen erst definiert werden, um später im Programm benutzt werden zu können. Außerdem steht meist noch die Möglichkeit zur Verfügung Datenfelder (auch Array oder Vector genannt) zu definieren, diese bieten die Möglichkeiten sozusagen eine Tabelle zu erstellen, bei der man über die Angabe von Koordinaten auf die einzelnen Felder zugreifen kann, im Gegensatz zu einer normalen Tabelle können die Datenfelder meist jedoch nicht nur in 2 Dimensionen, sondern in beliebig vielen Dimensionen definiert werden.

Eine Funktion oder eine Prozedur ist ein Unterprogramm, welches eine bestimmte Aufgabe erfüllen soll, zum Beispiel in dem obigen Programm, erfüllt die Funktion printf, die Aufgabe die Zeichenkette hello, world in die Standard Ausgabe (hier der Bildschirm) zu schreiben. In anderen Programmiersprachen wäre printf eine Prozedur, da es nur zur Ausgabe auf den Bildschirm führt. Eine Funktion wäre ein Unterprogramm, das ein Resultat liefer, zum Beispiel:

a = wurzel (4);

In diesem Fall würde a den Wert 2 annehmen, da die Funktion wurzel als Resultat die Wurzel aus 4 hätte. In diesem Fall ist es deutlich, dass wurzel eine Funktion sein muss, jedoch ist auch printf eine Funktion, da sie als Resultatwert die Länge der Zeichenkette liefert. Dieses ist ein Vorteil von C gegenüber anderen Programmiersprache, wie zum Beispiel BASIC oder PASCAL. Der Resultatwert wird oft benutzt um Fehler anzuzeigen, in diesem Fall nimmt er meist den Wert -1 an, oder um Werte für den weiteren Programmverlauf zu liefern, wie zum Beispiel printf die Länge der Zeichenkette liefert.

Ein weiterer wichtiger Bestandteil von Programmiersprachen ist die if Abfrage, diese für eine Anweisung aus wenn eine Bedingung erfüllt ist. Es gibt zudem die Möglichkeit alternative Anweisungen bereitzustellen mit else oder die alternative Anweisung nochmals von einer Bedingung abhängig zu machen mit elseif. In einigen Programmiersprache kommt nach der Bedingung ein then, bei C ist dieses jedoch unnötig, da die Bedingung in Klammern steht.

/* C: */
if (Bedingung)
Anweisung;
elseif (Bedingung)
Anweisung;
else
Anweisung;
REM BASIC:
IF Bedingung THEN
Anweisung
ELSEIF Bedingung THEN Anweisung
ELSE Anweisung
ENDIF

Ein weiterer wichtiger Teil von Programmiersprachen sind Schleifen, diese bewirken, dass eine Reihe von Kommando so lange ausgeführt werden bis eine Bedingung war wird oder so lange eine Bedingung war bleibt. Außerdem gibt es noch eine Art von Schleifen (meist FOR - Schleife genannt) die ein Variable nach einem vorgegebenen Muster verändern bis eine Bedingung erfüllt ist.

Geschichte von C

C entstand Anfang der siebziger Jahre in Zusammenhang mit dem Betriebssystem UNIX an den AT&T Bell Laboratories. Als Hauptentwickler der Programmiersprache gelten Dennis Ritchie und Brian W. Kernighan. Einige Ideen wurden dabei aus der Programmiersprache BCPL von M. Richards übernommen. Unmittelbarer Vorgänger von C ist das von K. Thompson 1970 im Zusammenhang mit der UNIX Entwicklung entstandene B. Des weiteren gingen noch Konzepte von ALGOL 60 und von ALGOL 68 in die Programmiersprache C über. 1983 richtete das American National Standards Institute (ANSI) eine Kommission mit dem Ziel ein, eine eindeutige und Maschinen unabhängige Definition der Sprach C zu erarbeiten. Das Ergebnis dieser Arbeit war der ANSI - Standart für C. Dieser Standard definiert C nun eindeutiger und präziser. Außerdem enthält der Standard nun neue Definitionen für den Aufruf von Funktionen.

C stellt im Gegensatz zu den ersten höheren Programmiersprache FORTRAN, ALGOL 60 (wissenschaftliche - technische Berechnung) und COBOL (kommerzielle Anwendungen) eine universell nutzbare Programmiersprache zur dar. Der Sprachumfang von C ist dagegen im Gegensatz zu ALOG 68 stark begrenzt, stellt jedoch eine ungeheure Flexibilität zur Verfügung. Es ist in C möglich sowohl Maschinen nah zu programmieren, als auch portable, das heißt Maschinen unabhängige, Programme zu schreiben.

C++, der "Nachfolger" von C, wurde ebenfalls in den AT&T Bell Laboratories entwickelt. Die Hauptrolle bei der Entwicklung spielte Bjarne Stroustrup. C++ erweitert die Möglichkeiten von C für objektorientierte Programmierung.

Programmbeispiel

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, dass 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 Eigenschaften 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, dass 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, dass 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üsste 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, dass 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, dass man die Kollisionsabfrage vor dem setzten des Pixel durchführt, da sonst der Pixel jedes Mal 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 muss das Spielfeld entsprechend mit Linien begrenzt werden, diese müssen auch rot sein, damit die Kollisionsabfrage diese erfassen kann oder ansonsten müsste man die Kollisionsabfrage entsprechend erweitern, wie man es für den zweiten Spieler tun muss, 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 Unterprogramms die Explosion auf den Bildschirm zeichnen ohne dass man die Kommandos für die Explosion jedes Mal neu schreiben muss, 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, dass 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 muss 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ässt 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. Dass 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üsste 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, dass bei jedem Programm Durchlauf die Punktzahl auf den Bildschirm geschrieben wurde. Der zweite Fehler war leicht zu beheben, der Aufruf für das Unterprogramm musste nur so plaziert werden, dass 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ässt es so auch auf langsameren PC lauf fähig und lässt 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, dass 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, dass 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 dass er Schaden anrichtet.

Den kompletten Quell-Code zu diesem Q-BASIC Spiel gibt es hier.

Hi-Res
DECLARE SUB ShowScore (p1 AS INTEGER, p2 AS INTEGER)
DECLARE SUB Explo (ex AS INTEGER, ey AS INTEGER, Player AS INTEGER)
DECLARE SUB SetScr ()
DECLARE SUB Pause ()
COMMON x AS INTEGER
COMMON y AS INTEGER
COMMON x1 AS INTEGER
COMMON y1 AS INTEGER
COMMON m AS INTEGER
COMMON n AS INTEGER
COMMON m1 AS INTEGER
COMMON n1 AS INTEGER
COMMON SHARED a AS STRING
COMMON r AS INTEGER
COMMON p AS INTEGER
COMMON p1 AS INTEGER
COMMON Time AS SINGLE
CONST g = 20
CONST maxX = 639 - g
CONST maxY = 479 - g
CONST minX = 0 + g
CONST minY = 16 + g
CONST Farbe1 = 2
CONST Farbe2 = 1
CONST StartX = 300
CONST StartY = 240
CONST StartX1 = 340
CONST StartY1 = 240
CONST StartM = 0
CONST StartM1 = 0
CONST StartN = 1
CONST StartN1 = -1
CONST StartTime = 300
SCREEN 12
SetScr
CALL ShowScore(p, p1)
Time = StartTime
x = StartX
y = StartY
x1 = StartX1
y1 = StartY1
n = StartN
n1 = StartN1
Pause
DO UNTIL a$ = "q"
a$ = INKEY$
FOR za = 1 TO Time: NEXT za
Time = Time - .01
x = x + m
y = y + n
x1 = x1 + m1
y1 = y1 + n1
IF POINT(x, y) = Farbe2 OR POINT(x, y) = Farbe1 THEN
p = p + 1
CALL Explo(x, y, 1)
x = StartX
y = StartY
x1 = StartX1
y1 = StartY1
m = StartM
n = StartN
m1 = StartM1
n1 = StartN1
Time = StartTime
Pause
CLS
SetScr
CALL ShowScore(p, p1)
END IF
IF POINT(x1, y1) = Farbe2 OR POINT(x1, y1) = Farbe1 THEN
p1 = p1 + 1
CALL Explo(x1, y1, 2)
Pause
SetScr
CALL ShowScore(p, p1)
x = StartX
y = StartY
x1 = StartX1
y1 = StartY1
m = StartM
n = StartN
m1 = StartM1
n1 = StartN1
Time = StartTime
END IF
PSET (x, y), Farbe1
PSET (x1, y1), Farbe2
SELECT CASE a$
'Player 1
CASE "w"'(CHR$(0) + "H")' oben
IF n <> 1 THEN n = -1: m = 0
CASE "s"'(CHR$(0) + "P") 'unten
IF n <> -1 THEN n = 1: m = 0
CASE "d"'(CHR$(0) + "M") 'rechts
IF m <> -1 THEN n = 0: m = 1
CASE "a"'(CHR$(0) + "K") 'links
IF m <> 1 THEN n = 0: m = -1
CASE ("y")
SELECT CASE m
CASE 1 'rechts
m = 0
n = -1
CASE -1 'links
m = 0
n = 1
CASE 0
SELECT CASE n 'oben
CASE -1
m = -1
n = 0
CASE 1 'unten
m = 1
n = 0
END SELECT
END SELECT
CASE ("x")
SELECT CASE m
CASE 1 'rechts
m = 0
n = 1
CASE -1 'links
m = 0
n = -1
CASE 0
SELECT CASE n 'oben
CASE -1
m = 1
n = 0
CASE 1 'unten
m = -1
n = 0
END SELECT
END SELECT
'Player 2
CASE ("8") 'oben
IF n1 <> 1 THEN n1 = -1: m1 = 0
CASE ("5") 'unten
IF n1 <> -1 THEN n1 = 1: m1 = 0
CASE ("6") 'rechts
IF m1 <> -1 THEN n1 = 0: m1 = 1
CASE ("4")'links
IF m1 <> 1 THEN n1 = 0: m1 = -1
CASE ("1")
SELECT CASE m1
CASE 1 'rechts
m1 = 0
n1 = -1
CASE -1 'links
m1 = 0
n1 = 1
CASE 0
SELECT CASE n1 'oben
CASE -1
m1 = -1
n1 = 0
CASE 1 'unten
m1 = 1
n1 = 0
END SELECT
END SELECT
CASE ("2")
SELECT CASE m1
CASE 1 'rechts
m1 = 0
n1 = 1
CASE -1 'links
m1 = 0
n1 = -1
CASE 0
SELECT CASE n1 'oben
CASE -1
m1 = 1
n1 = 0
CASE 1 'unten
m1 = -1
n1 = 0
END SELECT
END SELECT

CASE ("c")
p = 0: p1 = 0:
Pause
SetScr
CALL ShowScore(p, p1)
x = StartX
y = StartY
x1 = StartX1
y1 = StartY1
m = StartM
n = StartN
m1 = StartM1
n1 = StartN1
Time = StartTime
END SELECT
LOOP
SUB Explo (ex AS INTEGER, ey AS INTEGER, Player AS INTEGER)
SELECT CASE Player
CASE 1
FOR r = 1 TO 40 STEP 1
CIRCLE (ex, ey), r, 2
CIRCLE (ex, ey), r / 2, 10
FOR za = 1 TO 10: NEXT za
NEXT r
CASE 2
FOR r = 1 TO 40 STEP 1
CIRCLE (ex, ey), r, 1
CIRCLE (ex, ey), r / 2, 9
FOR za = 1 TO 10: NEXT za
NEXT r
END SELECT
FOR r = 0 TO 40 STEP 1
CIRCLE (ex, ey), r, 0
FOR za = 1 TO 100: NEXT za
NEXT r
END SUB
SUB Pause
DO UNTIL (a$ = CHR$(13) OR a$ = "q" OR a$ = " ")
a$ = INKEY$
LOOP
END SUB
SUB SetScr
CLS
LINE (minX, minY)-(maxX, minY), 2
LINE (maxX, minY)-(maxX, maxY), 2
LINE (minX, minY)-(minX, maxY), 1
LINE (minX, maxY)-(maxX, maxY), 1
END SUB
SUB ShowScore (p1 AS INTEGER, p2 AS INTEGER)
COLOR 7: LOCATE 1, 1: PRINT "Punkte ->",
COLOR Farbe1: PRINT "Player 1:"; p2,
COLOR Farbe2: PRINT " Player 2:"; p1
END SUB

4679 Worte in "deutsch"  als "hilfreich"  bewertet