BlitzBasic-Community-Tutorial/ Grundlagen

Bearbeiten

Fangen wir mit unserem ersten Programm an. Tippe folgendes in die BlitzBasic-IDE und starte es mit F5:

Print "Mein erstes Programm!"
WaitKey
End

Jetzt müssten 2 Fenster auftauchen. Das große ganz unten nennt man Debugger. Es durchsucht den Code nach möglichen Fehlern ("bugs") und teilt uns mit, wenn es einen findet. Den Debugger kann man aber auch an- und abschalten, indem man auf "Program > DebugEnable?" klickt.

In der Mitte sollte sich ein kleineres, schwarzes Fenster befinden. Dort läuft der Hauptteil deines Programmes ab (in diesem Fall steht dort "Mein erstes Programm!").

OK, wie funktioniert das jetzt?
Ganz einfach: Um Text auf dem Bildschirm auszugeben, benutzt man den Befehl (oder auch Anweisung genannt)

Print

Nach Print schreibt man einfach den gewünschten Text in Anführungsstrichen. Wie du sicher schon bemerkt hast, muss man jeden Befehl in eine neue Zeile schreiben. Demnach ist der nächste

WaitKey

Um zu verstehen, was er bewirkt, musst du erstmal wissen, dass das Programm sich selbst abschaltet, sobald es die letzte Zeile erreicht, und da der Computer ja eine "HighSpeed-Maschine" ist, würde der Text höchstens eine Nanosekunde aufflimmern. Um das zu verhindern, benutzt man WaitKey: Wie der Name schon sagt, wartet dieser Befehl, bis der Benutzer eine Taste drückt und fährt erst dann mit der nächsten Zeile fort.

Was der Befehl

 End

bewirkt, ist nicht schwer zu erraten. Es beendet das Programm. Aber wie schon erwähnt, schaltet sich das Programm am Schluss selbst ab. Doch dann meckert der Debugger; deshalb sollte man immer in die letzten Zeile ein end schreiben. Probiere es einfach mal ohne es aus.

Also, Print gibt den Text aus. Natürlich kann man ihn auch mehrfach verwenden.

Print "Hallo,"
Print "2. Zeile!"
WaitKey
End

Print hat aber den Nebeneffekt, dass er gleich eine neue Zeile anfängt. Wenn man das nicht möchte, dann muss man einfach "Write" verwenden.

Write "1. Zeile "
Write "hm, immernoch die 1. Zeile"
WaitKey
End

Achja, noch etwas:
Bei den meisten Spielen wird der code über 100 Zeilen lang (ich höre schon die ersten entsetzten Aufschreie). Man kann sich vorstellen, dass das ziemlich unübersichtlich wird. Deshalb gibt es sogenannte Kommentare. Diese überspringt der Compiler einfach und der Debugger meckert auch nicht.
Ein Kommentar wird mit einem Semikolon ( ; ) eingeleitet und reicht bis zum Ende der Zeile. So kann man sich zu jedem Befehl eine kleine Notiz schreiben, wenn man möchte:

Print "Hallo Welt!" ;gibt den Text in Anführungszeichen aus
WaitKey ;wartet auf einen Tastendruck
End ;beendet das Programm
;alles was ich hinter einen Strichpunkt schreibe wird nicht vom Compiler gelesen!

Variablen

Bearbeiten

Was sind Variablen? In der Mathematik sind sie Platzhalter. In der Programmierung speichert man in ihnen Werte, die sich während des Spielverlaufes ändern, wie z.B. Leben, Schaden, Geschwindigkeit etc.

In BlitzBasic gibt es 3 Arten von Variablen:

Integer -  Variablen können Ganzzahlen (1,2,3...)            speichern. 
Float   -  Variablen können Kommazahlen (3.2,74.33892)       speichern.
String  -  Variablen können Zeichenketten ("Hallo", "Ciao")  speichern.


Jede dieser Arten hat ein bestimmtes "Kennzeichen":

Integer-Variablen:   entweder % oder gar kein Zeichen 
Float-Variablen:  # 
String-Variablen: $



Wie erstellt (Fachausdruck: deklariert) man jetzt diese Variablen? Ganz einfach: Zuerst schreibt man den gewünschten Variablennamen:

leben 

Dann fügt man das "Variablenzeichen" an:

leben% ;in diesem Fall kann man es aber auch weglassen 

Und zum Schluss den gewünschten Wert, den man in der Variable speichern will:

leben% = 10

Hier nochmal alle 3 Arten in einem Beispiel:

leben = 10                 ;diesmal hab ich die Endung weggelassen.
Geschwindigkeit# = 7.333   ;Bei Kommazahlen muss immer der Punkt (.) als Dezimalzeichen verwendet werden.
name$ = "Friedrich"        ;Texte die in Stringvariablen gespeichert werden, müssen immer in "" geschrieben werden.


Ein String ist einfach nur Text; eine Anhäufung von Zeichen.

OK, wie verwendet man jetzt Variablen? Am Besten kann man das an einem Beispiel zeigen:


;hier werden die Variablen erstellt
leben  = 10      
speed# = 7.333
name$  = "friedrich"
;hier werden sie auf dem Bildschirm ausgegeben
Print name
Print leben
Print speed

WaitKey
End


Wenn man den INHALT der Variable angeben möchte, dann schreibt man einfach nur den Variablennamen (ohne ""). (Probier einfach mal die Namen in "" zuschreiben und schau was passiert.)

Der Computer ersetzt einfach den Variablennamen (ohne "") mit ihrem Inhalt.

Natürlich könnte man auch schreiben:


Print "10"
Print "7.333"
Print "Friedrich"

WaitKey
End 


Aber das Tolle an Variablen ist ja, dass sie (was für eine Überraschung) variabel sind.

Wieder ein Beispiel:


Leben = 10
Schaden = 3

Print Leben     ;noch ist der Spieler unbeschadet

Leben = Leben - Schaden  ;aber jetzt wird von Leben der Schaden abgezogen

Print Leben    ;die gleiche Zeile wie oben und trotzdem wird etwas anderes ausgegeben

WaitKey
End 


Du dürftest jetzt eigentlich alles bis auf die folgende Zeile verstehen:

Leben = Leben - Schaden 


Dann lösen wir sie mal auf:

Leben =

Dürfte ja noch verständlich sein. Die Variable bekommt einfach einen neuen Inhalt.

Leben = Leben - Schaden

Wie gesagt: der Compiler ersetzt Variablen mit ihrem Inhalt. Also dürfte die Zeile in Wahrheit so aussehen:

Leben = 10 - 3

jetzt sollte eigentlich alles klar sein.

Falls du es noch nicht verstanden hast, kannst du dir noch das nächste anschauen.


leben      = leben + 10          ; man bekommt 10 leben dazu
schaden    = schaden + schaden   ; schaden wird verdoppelt
schaden    = schaden*2           ; das Gleiche
schaden    = schaden/2           ; er wird halbiert
speed      = leben               ; speed wird an leben angepasst
leben      = leben - 1           ; man verliert ein leben
uzga       = uzga + 1            ; man bekommt ein uzga^^
sabberblub = sabberblub - 1      ; man kann sich für eine Variable die dümmsten Namen einfallen lassen

Beachte: am Computer benutzt man die Rechenzeichen * für das Multiplizieren und das / für das Dividieren.

ergebnis = a + b            ; Zwei Zahlen werden zusammengezählt und das Ergebnis in einer Variable gespeichert
ergebnis = a - b            ; die Zahlen werden subtrahiert,
ergebnis = a * b            ; multipliziert,
ergebnis = a / b            ; und dividiert.


Außerdem kann man nicht nur mit Zahlvariablen rechnen, sondern auch mit Strings:

name$  = "Fritz"
alter = 14

meldung$ = "Dein Name ist " + name$ + " und du bist " + alter + " Jahre alt."
Print meldung$
Waitkey 
End 

Man schreibt also einfach die Zeichenkette (in "") und fügt dann mit einem Plus (+) eine Variable oder eine weitere Zeichenkette an. Achtung: Es muss hinter einer Zeichenfolge immer $ stehen, sonst wird der Wert 0 ausgegeben!


Man muss diesen "Mischmasch" aber nicht unbedingt in Variablen speichern. Man kann ihn auch direkt ausgeben:


name$ = "Fritz"
alter = 14
Print "Dein Name ist" + name +" und du bist" + alter +" Jahre alt."

Waitkey
End

Wichtiger Hinweis Die Anweisungen Print und Write sind nur zur einfachen Kontrolle von Variablen-Inhalten gedacht. Für Programme sollte die Anweisung Text verwendet werden

Input und der Umgang mit Funktionen

Bearbeiten

OK, du kannst immerhin schon Text ausgeben und mit Variablen arbeiten. Aber was nützt es einem, der nicht programmieren kann? Gar nichts. Und jetzt kommt Input ins Spiel. Mit Input kann man die Eingabe eines Benutzers in eine Variable speichern.

Print "Gib deinen Spielernamen ein: "
Spielername$ = input$() 
Print "Name: " + Spielername$

WaitKey
End

Input ist eine sogenannte Funktion (oft auch als Befehl oder Anweisung bezeichnet). Diese besteht aus dem Funktionsnamen und einem Parameterteil. Aber nicht vom Namen abschrecken lassen, Parameter bedeutet einfach "Wert". Und wenn eine Funktion mehrere Parameter benötigt, werden sie durch ein (deutsches) Komma getrennt. Die Parameterteile gehören immer zwischen zwei Klammern. Doch im 1. Beispiel ist er leer, da Input keine Werte benötigt (es können aber welche eingesetzt werden). Es liest einfach die Eingabe ein und das war's, es gibt keine Variationen.

Print ist ebenfalls eine Funktion. Der Parameter, den Print benötigt, ist der String (Text), den es ausgeben soll. Aber, bei Print steht der Parameterteil nicht in Klammern. Wie geht denn das? Naja, es ist ja bekannt, dass Ausnahmen die Regeln bestätigen. Natürlich könnte man auch schreiben:

Print("Blah")

Aber es nützt uns nichts, da Print keinen Wert zurückliefert. Das bedeutet, dass man das Ergebnis dieser Funktion nicht in eine Variable schreiben kann, wozu auch? In diesem Fall ist das nicht nötig (man kann die Klammern aber nur in Basic-Dialekten weglassen, nicht in C++ oder anderen Sprachen).
Übrigens kann man bei Input, wenn man will, auch einen Parameter verwenden, nämlich den Text, der den User dazu auffordert, etwas einzugeben. Das würde dann so aussehen:

name$ = Input$("Gib mal deinen Namen ein: ")
print name

BlitzBasic hat hunderte von diesen Funktionen auf Lager. Das Sortiment reicht von einfachen Text-Funktionen über mathematische Funktionen bis hin zu 3D-Effekten.

Wenn man mit der Eingabe des Benutzers auch rechnen möchte (z.B. bei einem Taschenrechnerprogramm), muss man den Rückgabewert von Input einfach in eine Zahl-Variable anstatt in eine String-Variable setzen:

Zahl1% = Input("Gib bitte eine Zahl ein: ")
Zahl2% = Input("Gib bitte noch eine Zahl ein: ")
Print Zahl1+Zahl2

If-Konstruktionen

Bearbeiten

Mittlerweile kannst du also einen Text per "Print" ausgeben und weißt auch schon, wie du den Benutzer eine Eingabe tätigen lässt. Aber was ist nun, wenn du, abhängig von der Benutzereingabe, eine bestimmte Ausgabe erfolgen lassen möchtest? Nehmen wir das Beispiel einer X-beliebigen Quizshow: Der Spieler bekommt drei Antwortmöglichkeiten aus denen er wählen kann, aber nur eine ist richtig:

Print "Frage: Was ist 2+2?"
Print "(a) 6"
Print "(b) 4"
Print "(c) 5"

Antwort$ = Input ("a, b oder c? ")

If Antwort = "b" Then              ;Wenn die Antwort "b" ist
 Print "Richtig, du Mathegenie!"   ;Gebe den Text aus
EndIf                              ;Ende der If-Konstruktion


Huch, was haben wir denn da? Die Zeile (If Antwort = "b" Then) schaut, ob in der Variable "Antwort" der Text "b" gespeichert wurde. Wenn das so ist, wird die folgende Zeile ausgeführt. Man fragt also eine Bedingung ab, und wenn diese erfüllt ist, wird das gemacht, was zwischen If und Endif steht.

P.S.: Man kann das ganze auch - ohne 'EndIf' - in eine Zeile schreiben:

If Antwort = "b" Print "Richtig, du Mathegenie"

Oder wer's lieber etwas geschwätziger hat:

If Antwort = "b" Then Print "Richtig, du Mathegenie"


If und seine Verzweigungen

Bearbeiten

Um beim Beispiel mit dem Gewinnspiel zu bleiben: Was ist, wenn man nicht nur etwas sagen möchte, wenn der Spieler gewonnen hat, sondern ihn auch auslachen möchte, wenn er daneben getippt hat? Dazu gibt es in BB einen weiteren Befehl:

Else (zu Deutsch: sonst/ansonsten)

Um den Gebrauch zu demonstrieren, habe ich das weiter oben stehende Beispielprogramm mal ein wenig modifiziert:

Print "Frage: Was ist 2+2?"
Print "(a) 6"
Print "(b) 4"
Print "(c) 5"

Antwort$ = Input ("a, b oder c? ")

If Antwort = "b" Then               ;Wenn die Antwort "b" ist...
    Print "Richtig, du Mathegenie!" ;Gib diesen Text aus
Else                                ;Ansonsten...
    Print "Muhahaha! Daneben!"      ;Gib diesen Text aus
EndIf
WaitKey
End

Alles was zwischen dem Befehl "Else" und "Endif" steht, wird nur ausgeführt, wenn die erste Bedingung, also Wahl = "b", nicht erfüllt wird.

Was ist aber nun, wenn ich für die Antworten "a" und "c" noch andere Antworten geben möchte als nur, dass der Spieler versagt hat? Naja, dafür gibt es den schönen Befehl "Elseif", der eine Kombination der Begriffe "If" und "Else" darstellt. Um den Gebrauch zu demonstrieren, habe ich das Beispielprogramm noch einmal umgestrickt:

Print "Frage: Was ist 2+2?"
Print "(a) 6"
Print "(b) 4"
Print "(c) 5"

Wahl$ = Input ("a, b oder c? ")

If Wahl = "b" Then  ;Wenn Wahl gleich "b" ist...
  Print "Richtig, du Mathegenie!" ;Gebe diesen Text aus
Elseif Wahl = "a"   ;Ansonsten: Wenn Wahl = "a"
  Print "Ha, voll daneben!"
ElseIf Wahl = "c"   ;Ansonsten: Wenn Wahl = "c"
  Print "Ha, knapp daneben ist auch vorbei!"
Else	;Ansonsten...
  Print "Was hast du bitte schön eingegeben? Jedenfalls nicht a, b oder c."
EndIf
WaitKey
End

Select/Case

Bearbeiten

Wie man beim vorherigen Beispielcode sieht, kann so eine If-Abfrage bei vielen möglichen Antwortmöglichkeiten schon ziemlich lang und umständlich werden. Deshalb gibt es "Select" und "Case". Man sagt erst, welche Variable überprüft werden soll (Das macht man mit Select Deinevariable) und fügt nachher die verschiedenen Antwortmöglichkeiten hinzu (Mit Case "Anwort") und default ist das Äquivalent (entsprechende) zu dem Befehl "Else". Um das Ganze einmal auf das bisher benutzte Beispiel zu übertragen:

Print "Frage: Was ist 2+2?"
Print "(a) 6"
Print "(b) 4"
Print "(c) 5"

Wahl$ = Input ("a,b oder c? ")

Select Wahl                       ;Die Variable "Wahl" soll im folgenden überprüft werden...
Case "b"                          ;Antwort "b"
  Print "Richtig, du Mathegenie!" ;Gebe diesen Text aus
Case "a"                          ;Antwort "a"
  Print "Ha, voll daneben!"
Case "c"                          ;Antwort "c"
  Print "Ha, knapp daneben ist auch vorbei!"
Default                           ;Wenn keine der anderen Antworten passt...
  Print "Was hast du bitteschön eingegeben? Jedenfalls nicht a,b, oder c."
End Select
WaitKey
End


So, damit lassen sich schon nette Sachen basteln, kleine Textadventures oder Scherzprogramme. ;) Bastel einfach ein wenig mit den Codes rum, vertausche die Texte oder füge noch mehr Antwortmöglichkeiten hinzu, und du wirst sehen, dass sich damit schon nette Sachen machen lassen.

Schleifen

Bearbeiten

Tja, die Schleifen, die erleichtern einem das Leben. Es wäre sehr mühsam, wenn man für 200 Variablen die Wertzuweisungen von Hand einzeln eingeben müsste. Außerdem ist auch nur so ein Spiel möglich, da ja immer wieder das Bild aufgebaut und gelöscht werden muss, um die Illusion einer Bewegung zu erzeugen. Eigentlich wiederholen Schleifen nur die dazwischen stehenden Schritte bis zu einer Abbruchbedingung. Mit den Verzweigungen stellen Schleifen die Grundlage jeder Programmiersprache dar. Nur wer diese richtig einzusetzen weiß, kann richtig Programmieren.

For/Next

Bearbeiten

Die For-Schleife ist eine Zähler-Schleife. Mit ihrer Hilfe kann man sich viel Arbeit sparen, vor allem in Verbindung mit Arrays und Types (dazu später mehr).


 For start=1 To 10
  Print "Ein Hoch auf die For-Schleife"
 Next 

 WaitKey 
 End

Dieses Progrämmchen würde 10-mal den Text ausgeben. Dabei ist das Next zwingend nötig, sonst folgt eine Fehlermeldung. Also wird alles was zwischen For und Next steht genau start-mal (was für ein ausdruck^^) ausgeführt. "start" ist in diesem Fall eine Variable, die in jedem Schleifendurchlauf "zunimmt". In diesem Beispiel beginnt sie bei 1 (start = 1) und wird bis 10 (To 10) erhöht. Also schreiben wir uns mal ein kleines CountDown-Programm. (obwohl es eher ein CountUp-Programm ist)

 For zaehler = 1 To 10
  Print zaehler
 Next 

Aber die For-Schleife muss nicht unbedingt in Einser-Schritten zählen.

 For zaehler = 0 to 10 Step 2
  Print zaehler
 Next 

 WaitKey
 End 

Hierbei würde jede 2. Zahl übersprungen werden. Man kann auch Step 3, 4, 5, 6... angeben, dann werden halt mehrere Zahlen übersprungen. Wenn man die Schleife jetzt also rückwärts zählen lassen möchte, dann muss man sie mit -1er Schritten abarbeiten.

For zaehler = 10 to 1 Step -1
 Print zaehler
Next 

WaitKey
End

Und um daraus jetzt ein richtiges CountDown-Programm zu machen, muss man noch den Delay-Befehl einbauen. Wie der Name schon sagt, macht Delay etwas ähnliches wie WaitKey, nur dass es nicht wartet bis man eine taste drückt, sondern bis eine gewisse Zeitspanne vorüber ist. Und diese Zeitspanne gibt man als Parameter an (aber in Millisekunden). Wenn wir also wollten, dass erst nach einer Sekunde eine neue Zahl kommt, dann müssten wir als Parameter 1000 (=1 Sekunde) angeben:


For zaehler = 10 to 1 Step -1
 Delay(1000)
 Print zaehler
Next 

WaitKey
End

Repeat/Until

Bearbeiten

Was zwischen Repeat und Until steht, wird solange wiederholt, bis die bei Until eingetragene Abbruchbedingung erfüllt wird.

 zaehler = 0 

 Repeat                ;WIEDERHOLE
  zaehler = zaehler + 1   ;erhöhe die variable "zähler"
  Print zaehler           ;Gib den wert des zaehlers am bildschirm aus
 until zaehler = 10    ;BIS der zaehler gleich 10 ist
WaitKey
End

Tja, wozu braucht man jetzt das Zeug? Dasselbe könnte man doch mit einer For-Schleife erzielen, oder nicht? Stell dir einfach mal vor, du würdest an einem Egoshooter arbeiten und du möchtest, dass der Gegner auf den Spieler schießt bis er ihn getroffen hat oder tot ist. Mit einer For-Schleife ist das unmöglich, da man ja nicht weiß, wie oft der Gegner schießen muss.

Repeat/Forever

Bearbeiten

Achja, es gibt noch die Repeat/Forever-Schleife.

Repeat 
 Print "immernoch Blah!"
Forever

Was das bedeutet, ist wahrscheinlich klar. Diese Schleife endet nie und wird daher unendlich fortgeführt.

While/Wend

Bearbeiten

Eine der Unterschiede zwischen While- und Repeat-Schleife besteht darin, dass bei der While-Schleife zuerst die Abbruchbedingung getestet wird. Fällt dieser Test positiv aus, wird die Schleife ausgeführt.

While Bedingung  ;solange die Bedingung stimmt
 Print "Blah"
Wend             ;ende der Konstruktion

Wie man sieht, kann man eine While-Schleife anstelle einer Repeat-Schleife zur Erstellung der Main Loop (davon aber später) nutzen. Meistens wird aber die Repeat-Schleife verwendet. Bei manchen Befehlen funktioniert nur die eine bei manchen wieder nur die andere Schleife (sind allerdings wenige Befehle die da kritisch reagieren, vor allem bei den 3D-Kollisons-Befehlen ist das der Fall).

While not a=1
Wend 

Dies ist eine besondere Schreibweise. Wenn a ungleich 1 ist wird die Schleife ausgeführt. Das wars dann an dieser Stelle, ist doch gar nicht so schwer, oder?

Eigene Funktionen

Bearbeiten

Du weißt zwar schon, wie man mit Funktionen umgeht, aber du kannst dir auch eigene programmieren. Dies geschieht in einer Function-Konstruktion, welche ungefähr so aussieht:

Function NameDerFunktion(parameter)
End Function

"Function" leitet also die Konstruktion ein und "End Function" beendet sie wieder. Zwischen die Klammern schreibt man die gewünschten Parameter. Diese sind jedoch lokal, d.h. sie können nur in deiner Funktion (also zwischen Function und EndFunction) verwendet werden.

Aber am besten erklär ich dir das Ganze an einem Beispiel (diese Funktion berechnet das Volumen eines Quaders):

Function Volumen(laenge,breite,hoehe)   
 volumen = laenge * breite * hoehe   ;Volumen ist übrigens auch lokal
 Return volumen
End Function

Dürfte nicht allzu schwer sein, der einzige Befehl, den du noch nicht kennst, ist Return. Damit stellt man einfach den Rückgabewert einer Funktion ein und in diesem Fall soll eben das Volumen zurückgegeben werden. Und so verwendet man die Funktion:

vol = Volumen(1,4,7)
Print vol

In diesem Fall würde 28 (1*4*7) auf dem Bildschirm ausgegeben werden.

Variablen und Funktionen

Bearbeiten

Funktionen sind vom Hauptcode abgekapselt. Da man sich über sie seine eigenen Befehle erstellen will, dürfen sie nicht unbeabsichtigt vom Hauptcode beeinflusst werden. Dies würde geschehen, wenn Variablen, die in Funktion und Hauptcode denselben Namen haben, auch dieselbe Variable wären. Komisch formuliert? Ja, aber eigentlich ganz einfach. x in einer Funktion ist nicht dasselbe x wie das in einer anderen Funktion oder im Hauptcode.

x = 200
Print Test() 
Print x
Waitkey()
Function Test()
 x = x + 1
 Return x
End Function


Obwohl im Hauptcode x = 200 steht, ist das Funktionsergebnis x = 1. Die Funktion kann nicht ohne weiteres auf Variablen des Hauptcodes zugreifen. Für die Funktion ist der Wert der Variable x bei ihrem Start 0. Und sobald die Funktion endet, ist auch alles, was während ihr geschehen ist, vergessen. x ist für das Hauptprogramm weiterhin 0. x ist lokal. Das heißt, es wird nicht von Codeabschnitt zu Codeabschnitt (Hauptcode -> Funktion, Funktion -> Hauptcode, Funktion - Funktion) weitergegeben. Zum Erstellen solcher lokalen Variablen gibt es einen eigenen Befehl, der aber nicht benötigt wird. Sobald man eine neue Variable einführt, setzt Blitz sie automatisch als lokal.

Local x = 10


Der schlaue Leser wird jetzt schon das Gegenstück erwarten. Der Praktiker wird sich denken können, wozu es dient. Der Englischfreak wird sich auch schon denken können, wie es heißt: global. Globale Variablen werden durch alle Funktionen mitgeschleift. Man kann von jeder Ecke des Programms aus auf sie zugreifen. Definiert werden sie überraschenderweise mit dem Befehl Global. Dies kann nur im Hauptcode erfolgen. So setzen wir x also in unserem Beispielcodeschnippsel global:

Global x = 200
Print Test() 
Print x
Waitkey()
Function Test()
 x = x + 1
 Return x
End Function

So, ein Wort geändert und schon wird etwas ganz anderes ausgegeben. Wenn man nun x schreibt, so verstehen Funktion und Hauptprogramm darunter dieselbe Variable. x wird auf 200 gesetzt, in der Funktion auf 201 erhöht, als Rückgabe angezeigt. Auch im Hauptprogramm ist x jetzt 201.


Diese Funktion gibt eine Zeichenkette zurück.

Function Test$()
 Return "Test"
End Function

Diese Funktion gibt eine Ganzzahl zurück.

Function Test%()
 Return 1
End Function

Diese Funktion gibt eine Kommazahl zurück.

Function Test#()
 Return 3.4
End Function

BlitzBasic-Befehle ersetzen

Bearbeiten

Was hier stand, war absoluter Blödsinn. (es wurde eine Funktion erstellt, die mittels Locate und Print einen Text an einer bestimmten Position ausgeben sollte)

  1. Die BlitzBasic-Anweisung Text schreibt bereits einen Text an eine bestimmte Position im aktuellen Buffer, während die vorgestellte Funktion durch die Verwendung von Print nur in den Forebuffer schreiben kann.
  2. Eigene Funktionen ersetzen keine BlitzBasic-Befehle, sondern erweitern sie. Was natürlich nur sinnvoll ist, wenn dadurch einer Verbesserung erreicht wird.

Es ist jedoch tatsächlich möglich, BlitzBasic-Befehle zu ersetzen. Nur sollte man dabei genau wissen, was man macht.

  • Es können nur Funktionen ersetzt werden, die keine reservierten Keywords sind.
  • Die Anzahl und der Typ der Parameter sollten nicht verändert werden, damit bisherige Aufrufe der Funktion nicht zu Fehlermeldungen führen, oder zusätzliche Parameter sollten optional sein.
  • Eine Verwendung der Funktion innerhalb der Definition sollte man vermeiden, da dies zu einem rekursiven Aufruf führt. (auch rekursive Aufrufe sind programmierbar, jedoch deutlich komplizierter)

Wenn man, sagen wir 3 Spieler hat, und für jeden will man mehrere Werte speichern, die z.B. das Leben des Spielers, die x und die y Koordinate. Jetzt könnte man für jeden Spieler und jeden Wert eine Variable deklarieren:

spieler1_x=0
spieler1_y=0
spieler1_leben=100

spieler2_x=5
spieler2_y=5
spieler2_leben=100

spieler3_x=10
spieler3_y=10
spieler3_leben=100

Das wird allerdings sehr schnell in einen unübersichtlichen Code ausarten, geschweige denn von dem Aufwand den der Coder hat...

Daher kann man in Blitz ganze Speicherfelder, genannt Arrays,erstellen:

Dim spieler(2)

"Was soll das jetzt?" werden sich jetzt einige Fragen. Ganz einfach: damit haben wir 3 Variablen deklariert,von 0 bis 2,nämlich

spieler(0)
spieler(1)
spieler(2)

Die Zahl in den Klammern wird übrigens Index genannt. Diese kann man jetzt wie normale Variablen benutzen, hier einige Beispiele:

spieler(0)=5
Print spieler(0)
WaitKey
End

Die ausgabe des Programms wäre logischerweise 5.

Noch ein Beispiel:


spieler(0)=5
If spieler(0)=5 Then spieler(1)=spieler(0)
Print spieler(1)
WaitKey
End

Die Ausgabe wäre wieder 5.


Aber es geht noch besser: Man kann auch mehrere Dimensionen in ein Array packen, nämlich mit

Dim irgendwas(2,2)

Dann hätte man folgende Variablen zur Verfügung:

irgendwas(0,0)
irgendwas(0,1)
irgendwas(0,2)
irgendwas(1,0)
irgendwas(1,1)
irgendwas(1,2)
irgendwas(2,0)
irgendwas(2,1)
irgendwas(2,2) 

Man muss aber nicht unbedingt nur Zahlen darin speichern, auch Texte sind möglich,man muss nach dem Namen nur das bekannte $ setzen:

Dim texte$(2)
texte(0)="Hello " 
texte(1)="World"
texte(2)="!" 
Write texte(0)
Write texte(1)
Write texte(2)
WaitKey
End

Ein eleganterer Weg wären Types, sind aber manchmal, wenn man nicht so viel speichern will, zu aufwändig.

Blitzarrays

Bearbeiten

Alternativ zu den normalen Arrays gibt es auch noch die Blitz-Arrays.

Zu erst definieren wir mal ein Blitz-Array. Dabei müssen wir darauf achten, dass diese nicht mit Dim sondern mit Global bzw. Local vereinbart werden. So kann man Blitz-Arrays, solange man sie mit Local definiert hat, auch nur in Funktionen verwenden. Weiters gilt, dass diese spezielle Art der Arrays nur eindimensional sein kann. Der Index muss bei einem Blitz-Array in eckigen Klammern stehen. Hier ein Beispiel:

Global A[3]

Natürlich kann ein Blitz-Array auch Texte oder Fließkommazahlen beinhalten. $ für Texte, und # für Fließkommazahlen. Dabei ist merkwürdig, dass man die Typkennung nur bei der Definition angeben darf. Wenn man das Blitz-Array verwendet, muss diese entfallen.

Hier ein Beispiel:

Global Musikanten$[3] ;Hier wird ein globales Blitz-Array definiert.

Musikanten[0] = "Hahn"  ;\
Musikanten[1] = "Katze" ; \ Hier werden die Werte zugewiesen.
Musikanten[2] = "Hund"  ; /
Musikanten[3] = "Esel"  ;/

For I = 0 To 3         ;\
   Print Musikanten[I] ; | Hier werden die Werte nach der Reihe ausgegeben.
Next                   ;/

Waitkey

Eine etwas elegantere Weise Daten einzulesen, wäre mit den Befehlen Data und Read. Hier das gleiche Beispiel noch mal mit den neuen Befehlen:

Global Musikanten$[3] ;Hier wird ein globales Blitz-Array definiert.
Data "Hahn", "Katze", "Hund", "Esel" ;Die Werte werden hier aufgelistet.

For I = 0 To 3
   Read Musikanten[I] ;und hier werden sie, mithilfe einer Schleife, eingelesen.
Next
 
For I = 0 To 3         ;\
   Print Musikanten[I] ; | Hier werden die Werte nach der Reihe ausgegeben.
Next                   ;/

Waitkey

Wie man sieht, exakt das gleiche Ergebnis. Diese Art des Dateneinlesens kann man auch bei normalen Arrays verwenden.

Es gibt noch zwei weitere Gründe, die Blitz-Arrays interessant machen:
Zum 1.: Man kann es als Parameter einer Funktion übergeben.
Zum 2.: Man kann es als Element eines Type-Feldes verwenden. (Zu den Types im nächsten Abschnitt gleich mehr.)

Type-Befehlssatz ist eine sehr wichtige Erweiterung des BlitzBasic-Dialekts. Jedoch ist es ein sehr komplexes Thema und besonders Anfänger haben große Schwierigkeiten bei Verwendung von Types. Oft liegt es an anderer Vorstellung wie Types überhaupt funktionieren. Ich selbst war zuerst etwas verwirrt, da Types in anderen Programmiersprachen ganz anders funktionierten. Selbst jetzt gibt es wahrscheinlich nur wenige BB-Programmierer, die alle Tricks kennen. Dieses Tutorial soll endlich Schluss damit machen und alle Möglichkeiten erklären.

Zuerst soll noch gesagt werden, dass Types keine Universallösung darstellen. Es gibt einige Bereiche wo Types vollkommen ungeeignet sind. Meistens kann man etwas sogar ganz ohne Types lösen. Manchmal sind Types jedoch unvermeidbar und manchmal machen Types die Programmierung deutlich einfacher.

Wozu überhaupt Types? Wenn man große Projekte hat, dann benötigt man auch sehr viele Variablen. Oft hat man sogar viele ähnliche Variablengruppen, die man bei großen Programmen aber nur schwer in DIM-Feldern zusammenhalten kann. Types fassen wiederholende Variablen zusammen.


Hier wird die Benutzung empfohlen:

1) Die Anzahl der Objekte ist nicht bekannt oder variiert ständig. Beispielhaft dafür ist z.B. ein Alien-Shooter, wo dauernd Aliens abgeknallt werden. Manchmal sind nur wenige Aliens auf dem Bildschirm, manchmal kommen viele dazu.

2) Bei Verwendung von Objekten, wo man direkten Zugriff auf Eigenschaften haben möchte. Beispielhaft hierfür ist ein GUI mit Fenstern, Buttons, Checkboxen. Dabei möchte man z.B. den Status von Checkbox abfragen oder die Position der Objekte.


Hier wird die Benutzung nicht empfohlen:

1) Bei hoher Objektanzahl (über 10.000) wird die Benutzung nicht empfohlen. Dies wirkt sich sehr negativ auf den Speicher aus (dazu später mehr). Hier wird entweder DIM oder BANK empfohlen.

2) Bei statischer Objektanzahl, wo während des Programmablaufs niemals die Anzahl geändert wird. Hier wird auch entweder DIM oder BANK empfohlen. Ein großer Fehler ist z.B. die Verwaltung von Karteninformationen (Map) mit Types.


#1 Definition
Der Befehl TYPE definiert eine neue Typekollektion mit einem bestimmten Namen. Mit END TYPE wird diese Definition abgeschlossen. So sieht eine leere Definition aus, die in BlitzBasic sogar zugelassen wird:

TYPE person
END TYPE

Zwischen diesen Zeilen lassen sich beliebig viele unterschiedliche Variablen (Eigenschaften) mit FIELD notieren. Es können auch beliebige Variablenarten sein (Integer, Float, String). Dies könnte so aussehen:

TYPE person
 FIELD name$
 FIELD adresse$
 FIELD alter%
 FIELD einkommen#
END TYPE

Achtung! Diese Typedefinition kann nur im Hauptprogramm stehen. Dabei spielt es aber keine Rolle wo. Man kann es sogar in eine Includedatei auslagern. Zugriffe auf diese Typekollektion sind auch aus Funktionen erlaubt. Besser gesagt: die Typekollektion ist immer global verfügbar.

#2 Variablen
Bisher haben wir nur eine Typedefinition. Damit lässt sich aber noch gar nichts machen. Um Zugriff auf Objekte zu erhalten, werden ganz spezielle Variablen (Containervariablen) benötigt. Ich kann nur empfehlen solche Variablen mit LOCAL/GLOBAL zu deklarieren. Diese Variablen unterscheiden sich nur wenig von normalen Variablen - es wird lediglich ein Punkt mit Typebezeichnung dazugeschrieben:

TYPE person
 FIELD name$
 FIELD adresse$
 FIELD alter%
 FIELD einkommen#
END TYPE

LOCAL mutter.person
GLOBAL vater.person

Dieser Anhang (Punkt mit Typebezeichnung) ist sehr wichtig. BB muss ja wissen zu welchem Type so eine Variable zugeordnet wurde. Übrigens kann dieser Anhang bei späterer Verwendung sogar ganz entfallen. Dies funktioniert ja auch mit normalen Variablen. So kann man in dem Beispiel ja auch den Anhang # weglassen:

LOCAL float#
float=0.1

Alle Type-Variablen haben direkt nach der Definition keinen Wert. Dies kann man sich schwer vorstellen, wenn man z.B. mit QuickBasic programmiert hat. Dort konnte man direkt nach der Definition bereits auf TYPE-Eigenschaften zugreifen - es existierte bereits ein Objekt. In BlitzBasic wurde aber lediglich eine Variable ohne Inhalt angelegt. Ich hoffe, dieses Beispiel kann das etwas verständlicher machen:

TYPE person
 FIELD name$
 FIELD adresse$
 FIELD alter%
 FIELD einkommen#
END TYPE

LOCAL integer% ;Wert ist gleich 0
LOCAL vater.person ;Wert ist gleich NULL

In BlitzBasic gibt es keinen Zwang eine Variable mit LOCAL/GLOBAL du deklarieren. So kann man ja "on-the-fly" beliebige Variablen anlegen. Dies funktioniert aber auch mit Type-Variablen:

TYPE person
 FIELD name$
 FIELD adresse$
 FIELD alter%
 FIELD einkommen#
END TYPE
integer%=0
vater.person=NULL

Achtung! Während Zugriffe auf eine Typekollektion auch aus Funktionen erlaubt sind, kann eine Type-Variable global oder lokal sein. Somit kann man Zugriffe von Funktionen aus, auf solche Variablen erlauben oder verweigern.


#3 Erstellen
Bisher hat sich noch gar nichts getan. Wir haben eine Typedefinition und eine Variable für einen Zugriff angelegt. Jetzt fangen wir endlich an Objekte anzulegen. Dazu gibt es den Befehl NEW. Damit reservieren wir Speicher und legen somit ein Objekt an:

TYPE person
 FIELD name$
 FIELD adresse$
 FIELD alter%
 FIELD einkommen#
END TYPE
LOCAL vater.person
LOCAL mutter.person
vater.person=NEW person
mutter.person=NEW person

Dieser Code ist auch erlaubt (wir erinnern uns: Anhang kann nach einer Definition ausgelassen werden):

TYPE person
 FIELD name$
 FIELD adresse$
 FIELD alter%
 FIELD einkommen#
END TYPE

LOCAL vater.person
LOCAL mutter.person

vater=NEW person
mutter=NEW person

Dieser Code funktioniert auch (man kann ja Werte direkt zuweisen):

TYPE person
 FIELD name$
 FIELD adresse$
 FIELD alter%
 FIELD einkommen#
END TYPE

LOCAL vater.person=NEW person
LOCAL mutter.person=NEW person

Das geht ebenfalls (ist ja standardmäßig lokal):

TYPE person
 FIELD name$
 FIELD adresse$
 FIELD alter%
 FIELD einkommen#
END TYPE

vater.person=NEW person
mutter.person=NEW person

Beachte: Jedes Mal, wenn ein Objekt erstellt wird, wird dieses Objekt ganz hinten an unsere Typekollektion angehängt.

#4 Verlinkung
Endlich existiert ein Objekt. Dieses Objekt wird in eine Liste der Typekollektion eingefügt. Die Type-Variable "vater" wurde mit einem Objekt verbunden und die Type-Variable "mutter" wurde mit einem zweiten Objekt verbunden. Diese Verbindungen können aber auch wieder aufgehoben werden:

TYPE person
 FIELD name$
 FIELD adresse$
 FIELD alter%
 FIELD einkommen#
END TYPE

LOCAL vater.person
LOCAL mutter.person

vater=NEW person
mutter=NEW person
mutter=NULL

In diesem oberen Beispiel wurden zwei Objekte erstellt und Type-Variable "mutter" wurde wieder von dem Objekt abgekoppelt. Das eigentliche Objekt existiert aber weiterhin in der Liste. Es wurde nicht gelöscht!!! Man hat nur keinen Zugriff mehr auf dieses Objekt. Wie man dennoch eine Verlinkung zu einem Objekt aufbaut, werde ich etwas später erklären. Ich möchte euch jetzt besser auf eine kleine Falle hinweisen, die bei Funktionen auftreten kann:

TYPE person
 FIELD name$
 FIELD adresse$
 FIELD alter%
 FIELD einkommen#
END TYPE

FUNCTION test()
 LOCAL vater.person
 vater=NEW person
END FUNCTION

test()

Hier wird ein neues Objekt in der Funktion erstellt. Es wird beim Beenden aber nicht freigegeben. Ist ja auch klar: Typekollektionen sind ja immer global. Lediglich die Type-Variable "vater" wird beim Beenden vernichtet. Wenn ihr jetzt die Funktionsweise verstanden habt, dann sollte dieser Code für euch einleuchtend sein:

TYPE person
 FIELD name$
 FIELD adresse$
 FIELD alter%
 FIELD einkommen#
END TYPE

LOCAL vater.person
LOCAL mutter.person

vater=NEW person
mutter=NEW person
mutter=vater

Ich glaube, jetzt werden einige aber einen Aufstand machen: Mutter soll gleich Vater sein??? Ja, denn wir verlinken Mutter-Variable einfach mit dem Objekt von Vater-Variable. So wie bei dem oberen NULL-Beispiel geht auch hier ein direkter Zugriff auf Mutter-Objekt verloren. Mutter-Objekt bleibt aber weiterhin bestehen - nur haben wir wieder keinen Zugriff drauf. Für alle, die das schwer verdauen können: Auf Vater-Objekt kann man jetzt mit zwei Variablen zugreifen, auf Mutter-Objekt aber überhaupt nicht mehr. Somit kann man auch viele Spielereien machen - Z.B. kann man die Verlinkungen zwischen Vater und Mutter vertauschen:

TYPE person
 FIELD name$
 FIELD adresse$
 FIELD alter%
 FIELD einkommen#
END TYPE

LOCAL vater.person
LOCAL mutter.person
LOCAL tmp.person

vater=NEW person
mutter=NEW person

tmp=vater
vater=mutter
mutter=tmp

#5 Zugriff Jetzt können wir neue Objekte erstellen und damit wie die Profis hantieren. Allerdings konnten wir bisher noch nicht auf Eigenschaften zugreifen und Werte manipulieren. Das ist aber kinderleicht - es funktioniert fast wie in zich anderen Programmiersprachen auch:

TYPE person
 FIELD name$
 FIELD adresse$
 FIELD alter%
 FIELD einkommen#
END TYPE

LOCAL vater.person

vater=NEW person
vater\name$="Homer"
vater\adresse$="Springfield"
vater\alter%=40
vater\einkommen#=2345.67

Wie man sieht, wird lediglich Type-Variable angegeben. Nach einem Schrägstrich folgt Name der Eigenschaft und Wertzuweisung. In vielen anderen Programmiersprachen wird statt Schrägstrich ein Punkt verwendet. Warum wurde das nicht auch in BB so gemacht? Dies kommt daher, weil unser Punkt schon für die Kennzeichnung einer Type-Variable vergeben wurde. Besser gesagt: Der obere Code müsste eigentlich so aussehen (dies ist aber länger und unüblich):

TYPE person
 FIELD name$
 FIELD adresse$
 FIELD alter%
 FIELD einkommen#
END TYPE

LOCAL vater.person

vater.person=NEW person
vater.person\name$="Homer"
vater.person\adresse$="Springfield"
vater.person\alter%=40
vater.person\einkommen#=2345.67

In dem oberen Beispiel haben wir Werte zugewiesen. Irgendwie müssen wir diese Werte nun auslesen. Das geht ebenfalls sehr einfach:

TYPE person
 FIELD name$
 FIELD adresse$
 FIELD alter%
 FIELD einkommen#
END TYPE

LOCAL vater.person

vater=NEW person
vater\name$="Homer"
vater\adresse$="Springfield"
vater\alter%=40
vater\einkommen#=2345.67

PRINT vater\name$
PRINT vater\adresse$
PRINT vater\alter%
PRINT vater\einkommen#

Beachte: Man kann nur Werte der Eigenschaften ausgeben. Jedoch kann man nicht einfach "PRINT vater" schreiben. Dies wäre ein Fehler und das Programm würde nicht starten.

Achtung! Unsere Variable "vater" muss natürlich existieren (z.B. LOCAL vater.person). Zudem muss diese Variable mit einem Objekt verbunden sein (hier passierte das über NEW). In diesem Code sind darum gleich zwei Fehler:

TYPE person
 FIELD name$
 FIELD adresse$
 FIELD alter%
 FIELD einkommen#
END TYPE

vater\name$="Homer"
vater\adresse$="Springfield"
vater\alter%=40
vater\einkommen#=2345.67

Wer seine Programme auf maximale Sicherheit trimmen möchte, der prüft vorher, ob eine Variable mit einem Objekt verbunden ist. Dies geschieht so (Ausschnitt):

TYPE person
 FIELD name$
 FIELD adresse$
 FIELD alter%
 FIELD einkommen#
END TYPE
LOCAL vater.person

...
IF vater<>NULL THEN
 vater\name$="Homer"
 vater\adresse$="Springfield"
 vater\alter%=40
 vater\einkommen#=2345.67
ENDIF

#6 Löschen Nun wissen wir endlich wie wir ein Objekt erzeugen können. Aber es war bisher nicht entfernbar. Tja, dazu gibt es wieder einen neuen Befehl DELETE. Als Parameter wird lediglich eine Variable angegeben:

TYPE person
 FIELD name$
 FIELD adresse$
 FIELD alter%
 FIELD einkommen#
END TYPE

LOCAL vater.person

vater=NEW person
DELETE vater

In diesem Beispiel wurde ein Objekt aus unserer Typekollektion komplett entfernt. Die Variable "vater" bleibt aber weiterhin bestehen. Diese bekommt jetzt aber den Wert NULL. Somit haben wir auch den Zugriff auf unser Objekt verloren.

Oft möchte man jedoch gleich alle Objekte einer Typekollektion löschen. Dies geht ebenfalls sehr sehr einfach. Beachte: Jetzt wird aber nicht mehr eine Variable, sondern Typename als Parameter mit DELETE angegeben:

TYPE person
 FIELD name$
 FIELD adresse$
 FIELD alter%
 FIELD einkommen#
END TYPE

LOCAL vater.person
LOCAL mutter.person

vater=NEW person
mutter=NEW person
DELETE EACH person

Achtung! Es gibt eine große Falle, die recht unbekannt ist. Ein Objekt wird nicht wirklich aus dem Speicher gelöscht. Intern wird es lediglich als ungültig markiert und der Speicher nicht freigegeben.

Es basiert an der Annahme: Wenn X Objekte verwendet wurden, dann werden irgendwann später erneut mindestens so viele Objekte benötigt. Die Erstellung von vielen Objekten auf einen Schlag dauert lange, dafür bleibt es später aber konstant. Der einzige Grund war die Erhöhung der Geschwindigkeit. Nach dem Beenden des Programms wird aber natürlich der komplette Speicher freigegeben.

Falls dieser Effekt zu negativ auf den Speicher auswirkt (bei vielen Objekten), dann schlage ich vor entweder DIM oder BANK zu benutzen. Nach der Verwendung von DIM oder BANK wird der Speicher natürlich wieder freigegeben.

#7 Linked List Bisher hatten wir nur einzelne Objekte. BlitzBasic-Types sind aber viel trickreicher. Wir erinnern uns: Einzelne Objekte werden immer ganz hinten in eine globale Typekollektion eingefügt. Dies kann man sich wie eine einfache Liste vorstellen. Warum fügen wir dann nicht einfach zich solche Objekte ein?

TYPE alien
 FIELD x
 FIELD y
END TYPE

LOCAL a.alien
FOR i=1 TO 10
 a=NEW alien
 a\x=RAND(0,640)
 a\y=RAND(0,480)
NEXT

Die Variable "a" wurde nach dem Befehl NEW immer wieder mit einem neuen Objekt verlinkt. Und dann wurde den Eigenschaften "x" und "y" ein Zufallswert zugewiesen. Alle 10 Objekte bleiben aber erhalten - nur wir haben keinen direkten Zugriff mehr auf alle Objekte. Jetzt kommt aber der Trick: Alle Objekte in dieser Typekollektion sind über unsichtbare Fäden nacheinander miteinander verbunden. Und mit FOR...EACH-Schleife kann man abwechselnd alle Objekte abarbeiten:

TYPE alien
 FIELD x
 FIELD y
END TYPE
LOCAL a.alien

FOR i=1 TO 10
 a=NEW alien
 a\x=RAND(0,640)
 a\y=RAND(0,480)
NEXT

FOR a=EACH alien
 PRINT a\x
 PRINT a\y
NEXT

Beachte: Zuerst wird das erste Objekt ausgewählt, die Schleife abgearbeitet und dann das nächste Objekt aus der Liste ausgewählt. Dies dauert solange, bis keine Objekte mehr vorhanden sind. Wenn die Schleife abgearbeitet wurde, dann bekommt unsere Variable "a" den Wert NULL zugewiesen. Wir können aber auch jederzeit die Schleife mit EXIT verlassen (dann bleibt die letzte Verlinkung erhalten):

TYPE alien
 FIELD x
 FIELD y
END TYPE

LOCAL a.alien

FOR i=1 TO 10
 a=NEW alien
 a\x=RAND(0,640)
 a\y=RAND(0,480)
NEXT

FOR a=EACH alien
 IF a\x<10 THEN EXIT
NEXT

Achtung! In BlitzBasic gibt es keine Type-Instanzen. Es gibt nur eine einzige Type-Kollektion, auch wenn man viele verschiedene Type-Variablen verwendet. Darum funktioniert dieser Code nicht so wie man das auf den ersten Blick vermuten möchte:

TYPE alien
 FIELD x
 FIELD y
END TYPE
LOCAL a.alien
LOCAL b.alien

FOR i=1 TO 10
 a=NEW alien
NEXT

FOR i=1 TO 10
 b=NEW alien
NEXT

FOR a=EACH alien
 ...
NEXT

FOR b=EACH alien
 ...
NEXT

In dem Beispiel wurden 20 Objekte erstellt. Egal über welche Variable man nun alle Objekte abarbeiten möchte, es werden immer die 20 Objekte abgearbeitet. Ich denke das ist auch logisch, da unsere Variable dauernd nur zu einem Objekt gelinkt werden kann.

#8 Selektion Wow - diese neuen Möglichkeiten ermöglichen jetzt schon so viel. Aber es ist noch nicht vorbei! Wir haben bisher nur automatisch alle Objekte mit FOR...EACH abgearbeitet. Kurz zur Erinnerung: Wir konnten ja eine Verbindung zu einem Objekt mit NULL aufheben:

TYPE person
 FIELD name$
 FIELD adresse$
 FIELD alter%
 FIELD einkommen#
END TYPE

LOCAL vater.person
LOCAL mutter.person 

vater=NEW person
mutter=NEW person
mutter=NULL

Wir können aber auch mit speziellen Befehlen erneut Verbindungen aufbauen und sogar eine Typekollektion rauf und runterlaufen. Zuerst die einfacheren Befehle:

TYPE alien
 FIELD x
 FIELD y
END TYPE

LOCAL a.alien

FOR i=1 TO 10
 a=NEW alien
 a\x=RAND(0,640)
 a\y=RAND(0,480)
NEXT

a=FIRST alien

In diesem Beispiel wurden 10 Objekte erstellt. Danach wurde aber eine Verbindung mit dem ersten Objekt in der Liste "alien" aufgebaut. Wir haben also manuell unsere Variable "a" mit dem ersten Objekt verbunden. Dies funktioniert aber auch umgekehrt - man kann den letzten Eintrag auswählen:

TYPE alien
 FIELD x
 FIELD y
END TYPE

LOCAL a.alien

FOR i=1 TO 10
 a=NEW alien
 a\x=RAND(0,640)
 a\y=RAND(0,480)
NEXT

a=LAST alien

Hier gibt es aber auch eine Falle! Was ist, wenn wir gar keine Objekte in der Liste haben - zu was bauen wir dann eine Verbindung auf? Ganz einfach: sollten keine Objekte existieren, dann bekommt unsere Variable "a" den Wert NULL zugewiesen. Dies kann man auch ausnutzen:

TYPE alien
 FIELD x
 FIELD y
END TYPE

IF FIRST alien=NULL THEN keineobjekte

Erste oder letzte Objekte auswählen ist ja nicht gerade spannend. Darum kann man noch manuell vorherige oder nachfolgende Objekte auswählen. Hier ein Beispiel, um einen nachfolgenden Eintrag auszuwählen (AFTER) und einen vorherigen Eintrag auszuwählen (BEFORE):

TYPE alien
 FIELD x
 FIELD y
END TYPE

LOCAL a.alien
LOCAl b.alien

FOR i=1 TO 10
 a=NEW alien
 a\x=RAND(0,640)
 a\y=RAND(0,480)
NEXT

a=FIRST alien
a=AFTER a

b=LAST alien
b=BEFORE b

Hier gibt es schon kleine Unterschiede. Anders als bei LAST/FIRST wird nicht mehr Typename, sondern Variablename bei AFTER/BEFORE angegeben. Es gibt aber auch noch paar Tricks:

TYPE alien
 FIELD x
 FIELD y
END TYPE

LOCAL a.alien
LOCAl b.alien
FOR i=1 TO 10
 a=NEW alien
 a\x=RAND(0,640)
 a\y=RAND(0,480)
NEXT
a=AFTER FIRST alien
a=AFTER AFTER a

b=BEFORE LAST alien
b=BEFORE BEFORE b

Bei BEFORE und AFTER muss man ebenfalls aufpassen! Was ist, wenn man bereits den ersten Eintrag ausgewählt hat und nun plötzlich einen vorherigen auswählen will. Oder was ist, wenn man bereits den letzten Eintrag ausgewählt hat und nun plötzlich einen nachfolgenden auswählen will. Tja, in dem Fall wird unser Variable der Wert NULL zugewiesen. Vielleicht werden sich jetzt viele fragen: Was bringen diese Befehle? Tja, deshalb habe ich ein kleines Beispiel, in dem alle Objekte in umgekehrter Reihenfolge abgearbeitet werden:

TYPE alien
 FIELD x
 FIELD y
END TYPE

LOCAL a.alien
FOR i=1 TO 10
 a=NEW alien
 a\x=i
 a\y=i
NEXT

a=LAST alien
WHILE a<>NULL
 PRINT a\x
 a=BEFORE a
WEND

Mathematische und Sonderfunktionen

Bearbeiten

Folgendes ist für die Spieleprogrammierung nicht zwingend nötig aber ganz nützlich:

Es gibt auch eine Anzahl von Mathefunktionen. Am besten sollte man sich die deutsche Onlinehilfe von der Seite [1] besorgen, in der noch einmal die Funktion eines jeden Befehls aufgeführt wird. Ich liefere hier einen Überblick über die wichtigsten:


 Wurzel=Sqr(5)

Diese Funktion ermittelt die Wurzel einer Zahl.

Zahl=8
Wurzel=Sqr(Zahl)

Die geht auch!

B=Log10(10)

Diese Funktion errechnet den 10er-Logarithmus der angegeben Zahl, auch hier kann, wie oben, eine Variable verwandt werden.

Zahl#=Pi
Print Zahl

Pi symbolisiert die Zahl 3,14.

Zahl=5
Zahl xor 10

Xor verschiebt bitweise.