LUA Syntax

Aus Das Wherigo-Handbuch
Wechseln zu: Navigation, Suche

Inhaltsverzeichnis

Variablen

Variablen sind Platzhalter für Werte. In einer Variablen kann also etwas gespeichert werden. Der Name einer Variable kann aus beliebigen Buchstaben, Zahlen und dem Unterstrich bestehen. Als Einschränkung gilt, dass der Name nur mit einem Buchstaben oder dem Unterstrich beginnen darf. Außerdem gibt es Wörter, die für in der Sprache LUA reserviert sind. Das sind: zunächst einmal: and, break, do, else, elseif, end, false, for, function, if, in, local, nil, not, or, repeat, return, then, true, until, while. Das sind Befehle, die eine spezielle Bedeutung haben. Es gibt noch mehr davon, wenn spezielle Bibliotheken (Befehlserweiterungen) eingebunden werden. Ansonsten können Variablen beliebige Namen haben. Der Übersicht halber empfiehlt es sich, sie jedoch so zu bennenen, dass sie sich selbst erklären. Zum Beispiel:

anzahl_seiten --Hier steht die Anzahl von irgend welchen Seiten drin.
high_score --Ein Highscore
entfernung_zum_ziel --Erklärt sich selbst

Man unterscheidet Variablen nach dem Inhalt, den sie speichert. Das kann eine Zahl, eine Zeichenfolge (ein String), oder ein logischer Zustand (Wahr/Falsch, true/false) sein. Ein Spezialfall sind LUA-tables. Dazu später. Glücklicherweise muss der Variablentyp im Vorfeld nicht festgelegt werden.

Wert zuweisen

Mit dem Gleichheitszeichen (=) wird einer Variablen ein Wert zugewiesen. Dabei steht die Variable, der etwas zugewiesen wird immer links, also genau umgekehrt als in Mathe

anzahl_seiten = 6
mein_cachername = "docfred"  --Strings stehen immer in Anführungszeichen
entfernung_zum_ziel = 250.9  --Der Dezimaltrenner ist immer der Punkt (.)
sommerzeit = true  --Eine logische Variable kennt nur zwei Zustände 

In Mathe haben wir gelernt, dass das was rechts und links von Gleichheitszeichen steht auch gleich sein muss. Beim Programmieren ist das etwas anders, denn folgendes ist erlaubt:

anzahl_seiten = anzahl_seiten +1


Hat die variable anzahl_seiten vor dieser Zeile (und auch rechts vom Gleichheitszeichen) noch den Wert 5, so erhält sie auf der linken Seite den Wert 6. Den behält sie auch im weiteren Verlauf, bis zur nächsten Zuweisung.

Dies geht auch mit Stringvariablen

name = "Müller"
name = "Andreas "..name  --Die zwei Punkte fügen zwei Zeichenketten aneinander (Stringaddition)

Der String name enthält nach dieser Stringaddition den Inhalt "Andreas Müller".

Eine Variable hat nicht einen festen Typ. Durch Zuweisung kann sich dieser ändern

zahl = 6  --eine nummerische Variable
zahl = "sechs"  --eine Stringvariable

Operationen mit unterschiedlichen Variablentypen

Ein weitere angenehme Eigenschaft ist, dass auch unterschiedliche Variablentypen (in gewissen Grenzen) kombiniert werden können. Z.B.:

spieler = "docfred" --Ein Stringvariable
punkte = 6 --Eine numerische Variable
message = spieler.. " hat "..punkte.." Punkte." --Das ist dann auch eine Variable vom Typ string

Hier wird die Variabie punkte wie ein String verwendet. message hat dann den Inhalt "docfred hat 6 Punkte."

Das geht auch umgekehrt

aufgabe = "6mal klatschen" --Eine Stringvariable
wiederholung = 3 --Eine numerische Variable
gesamtzahl = wiederholung * aufgabe --Das ist eine Multiplikation. Der numerische Anfangsteil von aufgabe wird als Zahl interpretiert. Das Ergebnis ist eine Zahl.

Im Gegensatz zu dem oberen Beispiel: "aus Zahl wird Zeichen", sollte man das untere eher sein lassen.

Gültigkeit von Variablen

In Lua gibt es nur zwei Gültigkeitsbereiche. Entweder global der local.

Globale Variablen gelten überall, lokale Variablen (vereinfacht gesagt) nur innerhalb einer Funktion (also zwischen function und dem dazugehörigen end). Es sei den sie werden innerhalb der Funktion als global definiert. Siehe auch bei Funktionen.

Für diejenigen, für die es zu stark vereinfacht ist - lokale Variablen gelten innerhalb eines sogenannten Blocks - d.h. sie können auch nur für einen Teil der Funktion gelten...

Funktionen

Funktionen erkennt man an den Klammern hinter den Namen. In eine Funktion kann man ein Programmteil packen, welches öfters benotigt wird. Funktionen machen den Programm-Code übersichtlicher. In diesem Beispiel wird das Ergebnis der Funktion an die Variable mit dem Namen "ergebnis" übergeben. Das sieht dann zunächst im Programm so aus. An anderer Stelle muss diese Funktion dann definiert werden.a

 ergebnis = meine_eigene_funktion()

An anderer Stelle muss diese Funktion dann definiert werden. Das könnte dann so aussehen:

 function meine_eigene_funktion()
      berechnetes_ergebnis = berechne irgend was
   return berechnetes_ergebnis
 end

Eine Funktion endet immer mit 'end'. Der Wert, hinter dem Befeht 'return' wird zurückgegeben. Das heißt die Funktion hat dann diesen Wert. Was man an diesem Beispiel auch noch erklären kann ist folgender Sachverhalt. Variablen die innerhalb einer Funktion definiert werden, in diesem Besipiel es es 'berechnetes_ergebnis', sind local. D.h. sie ist nur zwischen 'function' und 'end' definiert. Außerhalb der Funktion kann eine Variable mit dem selben Namen existieren, die aber nicht mit dem Wert innerhalb der Funktion überschrieben wird. Man kann aber auch ganz explizit bei Variablendefinitionen das Schlüsselwort local voranstellen - man kann über das Schlüsselwort global aber auch dafür sorgen, daß die Variablendefinition auch ausserhalb der Funktion gilt.

Jetzt ein konkreteres Beispiel. Eine Funktion, die zwei Zahlen addiert (wie sinnvoll ;-)):

  c = addieren(a, b)

 function addieren(aa, bb,)
      cc = aa + bb
   return cc
 end

Die Variablen aa, bb, cc, sind local definiert - aa und bb nehmen bei einem Funktionsaufruf die Werte an, mit denen die Funktion aufgerufen wird - also im oberen Beispiel die Werte von a und b. Am Schluß wird der Wert von cc von der Funktion zurückgegeben - bei dem obigen Funktionsaufruf erhält damit c den Wert von cc, der innerhalb der Funktion berechnet wird zugewiesen. Normalerweise stehen in einer Funktion natürlich sinnvollere Berechnungen siehe auch bei Beispiele/Codeschnipsel in LUA

Schleifen

In LUA gibt es verschiedene Schleifen-Konstrukte. Die bekannteste Schleife ist die for-Schleife. Daneben gibt es aber noch die while-(do-) und die repeat(-until-)Schleife

Ganz normale for-Schleifen

Mit einer for-Schleife kann man Dinge wiederholt durchgehen. Der Vorteil dieser Schleife ist, das eine sog. Schleifenvariable (man nimmt gerne i, für geschachtelte dann j, k... als Variablenname) hoch bzw. runtergezählt wird. Diese Variable kann man auch in der Schleife verwenden um z.B. durch ein Array(table) durchzugehen.

Die allgemeine Syntax lautet

 for schleifenvariable = anfangswert, endwert, schrittweite do
    -- mache irgendwas - 
 end

Die Schleifenvariable nimmt beim ersten Durchgang durch die Schleife den anfangswert an, erhöht sich bei jedem weiteren Durchgang um die Schrittweite, die Schleife ist beendet und wird nicht mehr durchgeführt, sobald der endwert überschritten ist.

Ein konkretes Beispiel

 msg = "Zahlen: "
 for i = 1, 10, 2 do
    msg = msg..i.." "
 end

nach Ausführen der for-Schleife erhält die String-Variable msg den String "Zahlen: 1 3 5 7 9 "

while-(do-)Schleifen

Im Gegensatz zu den for-Schleifen wird bei den while- und repeat-Schleifen nicht automatisch eine Schleifenvariable de- bzw- inkremenentiert. Es wird einfach eine Bedingung geprüft. Bei den while-Schleifen wird die Bedingung am Anfang geprüft. Ist die Bedingung unwahr (false) dann wird die Schleife gar nicht durchlaufen. Bei der repeat-Schleife wird diese immer mindestens einmal durchlaufen, selbst wenn die Bedingung schon zu Beginn false ist, weil diese erst am Schleifenende geprüft wird.


zufalls_wert = 1
while zufalls_wert < 6 do --Wenn der zufalls_wert 6 ist, wird die Schleife verlassen. Der Code wird nach dem end weiter abgearbeitet
  zufalls_wert = math.random(1, 6) --Diese Funktion liefert eine Zufallszahl zwischen 1 und 6 
end


Hier kann einfach eine beliebige Bedingung abgefragt werden. Theoretisch könnte man mit solch einer Schleife zufällig eine Zahl zwischen 1 und 6 erzeugen und das solange bis ein Timer abgelaufen ist.

repeat-(until)Schleifen

IF-Bedingungen und logische Operatoren

Freiwillige vor

LUA-Tables

Lua-Tables stellen einen sehr flexiblen und nützlichen Datentyp dar. Im Prinzip besteht die gesamte Lua-Cartridge eines WIG aus ineinander verschachtelten Tables. Das soll uns aber zunächst nicht interessieren. Wir wollen zunächst mit einfachen Beispielen beginnen.

Indizierte Variablen/Arrays

Steigt man etwas tiefer in die WIG-Programmierung ein, so ist bald der Wunsch nach einer indizierbaren Variablen da. Das lässt sich mit einer table realisieren. Ein table wir mit geschweiften Klammern definiert. Die Größe muss glücklicherweise nicht vordefiniert werden, sodass man zur Laufzeit noch Elemente hinzufügen kann.

mein_table = {}


In diesem Schritt kann man auch gleich Werte eintragen:

fruechte_table{"Apfel","Birne","Kirsche"}

Diese Enzelelemente lassen sich jetzt so ansprechen:

frucht = fruechte_table[1] -- Die Variable Frucht enthält jetzt den Wert: Apfel

Die Laufvariable steht jetzt in eckigen Klammern. Jeder, der sich mit Schleifen auskennt, weiss jetzt, dass man alle Elemente mit einer Schleife auslesen könnte. Dazu später. Wichtig ist auch, dass das erste Element 1 ist und nicht 0! Man könnte das Array auch so füllen:

fruechte_table{}
fruechte_table[1]="Apfel"
fruechte_table[2]="Birne"
fruechte_table[3]="Kirsche"

Wichtig für URWIGO-Prtogrammierer: Es sollte in URWIGO eine Variable mit einem gleichlautenden Identifer angelegt werden. Diese Variable wir dann mit dem table "überschrieben". Dadurch wird erreicht, dass beim Speichern der Cartridge der table mit gespeichert wird. Dieser Variablen darf man dann natürlich wärend des Ablaufes auch keinen neuen Wert mehr zuweisen.


Will man nachträglich noch eine Element anfügen, ohne dass man weiss, wieviele Elemente es bereits gibt, geht das mit table.insert(table,wert).

table.insert(fruechte_table, "Zwetschge")

fruechte_table[4] hat jetzt den Wert "Zwetschge".


Will man nachträglich an einer bestimmten Stelle noch ein Element einfügen, geht das auch. Der Befehl lautet: table.insert(table,position,wert).Wir fügen an der zweiten Stelle was ein:

table.insert(fruechte_table, 2, "Pflaume")

Damit steht an der zweiten Stelle jetzt Pflaume und die Birne ist an die dritte Stelle gerutscht.


Entfernen geht auch. Der Befehl lautet: table.remove(table,position). Wir entfnenen aus dem Anfangsbeispiel das erste Element:

table.remove(fruechte_table, 1)

Damit steht die Birne an der ersten Stelle. Die anderen sind vorgerutscht.

Assoziative Arrays

Neben den numerischen Arrays gibt es auch sog. assoziative Arrays. Dabei geschieht die Auswahl des Elementes nicht über eine Zahl, sondern über einen Schlüssel(key). Jeder key hat dan einen Wert. Das könnte dann so aussehen:

frucht ={geschmack="sauer", farbe="rot", schale="hart"}

oder

frucht ={}
frucht.geschmack="sauer"
frucht.farbe="rot"
frucht.schale="hart"

mit Schleifen durch alle Elemente einer Table gehen

Das obige Beispiel ist zwar sehr schön verständlich - was wäre aber, wenn LUA keine Möglichkeit hätte, alle Elemente einer solchen Table auch abzufragen - dann müsste man ja wissen, was denn hinzugefügt wurde.

LUA wäre nicht LUA, wenn nicht dafür auch Mittel vorhanden wären. Es gibt eine spezielle Form der For-Schleife, mit der man durch alle Elemente von Tables gehen kann - unabhängig davon, ob es sich um Tables mit numerischen Indizes oder mit nicht numerischen Indizes handelt.

Die Syntax für obiges Beispiel einer assoziativen Table sieht so aus:

   local text = ""
   for index, inhalt in pairs(fruechte_table) do 
       text = text.."Attribut: "..index.." = "..inhalt.." "  
        -- index ist nach jedem Durchgang geschmack, farbe, schale, inhalt ist sauer, rot, hart
   end

Das führt dann zum Ergebnistext:

  Attribut: geschmack = sauer Attribut: farbe = rot Attribut: Schale = hart

Verschachtelte Tables

Das geniale an tables ist, dass ein table ein bzw. mehrere tables enthalten kann.

Hier ein Beispiel mit einem numerischen und assoziativen Arrays:

fruechte_table{}
fruechte_table[1]={} --Hier wird jetzt das erste Element des äußeren numerischen table mit einem neuen (assoziativen) table gefüllt.  
fruechte_table[1].name="Apfel"
fruechte_table[1].farbe="gruen"
fruechte_table[1].schale="hart"
fruechte_table[1].geschmack="sauer"
fruechte_table[2]={name="Birne", farbe="gelb", gechmack="suess"}
fruechte_table[3]={name="Kirsche", farbe="rot", geschmack="suess"}


Das geniale ist, dass wir jetzt z.B. folgendes machen könnten:


satz ="Die Fucht mit dem Namen "..fruechte_table[x].name.." ist "..fruechte_table[x].farbe.."."

Für x=2 würde dann der Satz heißen "Die Frucht mit dem Namen Birne ist gelb."

Ein Beispiel mit einem Bilder-Array

Beim Erstellen eines WIG tritt ab und zu das Problem auf, dass man abhängig von einem Ergebnis ein unterschiedliches Bild ausgeben will. Z.B. habe ich einen Wuerfel-Item. Mit diesem Würfel möchte ich würfeln. Das Item Wuerfel bekommt einen Command "werfen". Danach soll das Item-Bild dann den Würfel mit der Zahl zeigen. Ich lege jetzt sechs Medien an. Die Identifier werden mit "wuerfel1" bis "wuerfel6" angelegt. Jetzt schreibe ich:

wuerfel ={wuerfel1, wuerfel2, wuerfel3, wuerfel4, wuerfel5, wuerfel6}

Damit habe ich ein Array, das die Medien-Elemente enthält. Das ist nicht das Selbe wie wuerfel ={"wuerfel1", "wuerfel2", "wuerfel3", "wuerfel4", "wuerfel5", "wuerfel6"}. In diesem Fall wären es Strings!

Hätte ich jetzt in der Variablen "wurf" die Wurfzahl stehen, so kann ich mit folgender Zeile dem Item "Wuerfel" das entsprechende Image zuordnen.

wuerfel.image = wuerfel[wurf]

So würde das dann für den Command "werfen" des Wuerfel-Items (ausnahmsweise) in URWIGO aussehen:

Würfeln.jpg

Das Bild des Würfels zeigt dann das Ergebnis der Variablen "wurf" als Bild an.

Ein Beispiel mit einem kombinierten Array

Das Ganze könnte man jetzt noch so machen:

wuerfel{}
wuerfel[1]={bild=wuerfel1, beschreibung="Das war leider nur die Eins."}
wuerfel[2]={bild=wuerfel2, beschreibung="Immerhin eine Zwei."}
.
.
wuerfel[6]={bild=wuerfel6, beschreibung="Bravo, eine Sechs. Maximale Pnuktzahl!"}


Jetzt würde folgendes gehen:

wuerfel.image = wuerfel[wurf].bild 
wuerfel.description = wuerfel[wurf].beschreibung

Auf diese Weise wird nicht nur das Bild gewechselt, sondern auch der Text. Cool, oder?

Meine Werkzeuge
Namensräume
Varianten
Aktionen
Navigation
Werkzeuge