Inhaltsverzeichnis

Die Lua-Standardbibliothek

In Ebene 2 unseres Skript-Tutorials dreht sich vieles darum, neue Funktionen kennenzulernen. Dadurch werden die Möglichkeiten, Lua-Variablen oder das Spiel selbst zu beeinflussen, deutlich ausgebaut. An dieser Stelle ist es wichtig, dass du die Grundlagen unbedingt kennst und verstanden hast.

In diesem Artikel geht es darum, einige wichtige Funktionen aus der Lua-Standardbibliothek vorzustellen. Lua bietet dem Programmierer standardmäßig nicht nur Datentypen und Kontrollfluss, sondern auch „Standardfunktionen“, die sehr oft gebraucht werden und darum nicht jedes mal vom Nutzer selbst programmiert werden sollten. Eine davon ist table.getn, die du bereits im Artikel zu Tables kennengelernt hast. Aber auch mathematische Funktionen, wie die Berechnung der Quadratwurzel oder des Sinus einer Zahl zählen dazu.

Es wäre nicht sinnvoll, jede einzelne der Funktionen hier aufzulisten. Diese Liste findest du (nach Kategorie sortiert) hier. Da aber nicht jeder die komplette Referenz studiert, existiert dieser Artikel, um zumindest auf die wichtigsten Standardfunktionen, auf die man immer wieder stößt, aufmerksam zu machen.

Es lohnt sich, die einzelnen Funktionen einmal auszuprobieren, um zu schauen, was sie tun. Kaputtmachen kann man damit glücklicherweise nichts - die wirklich „gefährlichen“ Funktionen stehen in Siedler nicht zur Verfügung.


pairs und ipairs

pairs und ipairs geben sogenannte Iteratoren zurück, die für for-Schleifen benutzt werden können. Die Konstruktion von Iteratoren wird erst in Ebene 3 beschrieben, aber die von Lua bereitgestellten sollte man kennen. Wie sie verwendet werden, erklärt direkt der nächste Artikel.


next

next (_Table [, _Key ]) gibt für ein Table _Table das nächste Key-Value-Paar des Tables, abhängig von _Key zurück. Der „nächste“ Wert ist dabei nicht notwendigerweise der, der der Reihenfolge entspricht, in der man das Table befüllt hat, sondern bezieht sich darauf, wie das Table intern gespeichert ist. Man hat darum keinen Einfluss darauf, in welcher Reihenfolge man via next Werte zurückerhalt.

Ist _Key nicht angegeben (daher die eckigen Klammern - der Parameter ist optional), wird ein beliebiges Key-Value-Paar zurückgegeben (falls vorhanden). Ist _Table leer oder das letzte Element erreicht, wird nil zurückgegeben.

Meistens wird die Funktion dazu benutzt, um zu prüfen, ob ein Table leer ist:

function IsTableEmpty(_Table)
    return next(_Table) == nil
end

Da die Funktion mehrere Rückgabewerte hat, hilft beim Verständnis sicher auch der zugehörige Artikel.


unpack

unpack (_Table) gibt für ein numerisches Table _Table alle Werte (einzeln) zurück. Wie Funktionen mit mehreren Rückgabewerten verwendet werden, erfährst du im zugehörigen Artikel. Stell dir dazu folgendes vor: In einem Table können zwar mehrere Werte gespeichert sein (z.B. {0, 42, 5, „Dario“}), aber das Table selbst ist eine einzige Variable. Mit unpack kannst du aus dem Table wieder einzelne Variablen machen:

-- Wir zeigen zwei Varianten, um das Beispieltable zu entpacken
-- Variante 1 mit den bereits bekannten Mitteln:
 
-- Beginne mit dem Table
MyTable = {0, 42, 5, "Dario"}
-- Speichere nun alle Werte in einzelne Variablen
Variable1 = MyTable[1]
Variable2 = MyTable[2]
Variable3 = MyTable[3]
Variable4 = MyTable[4]
 
-- Variante 2 unter Zuhilfenahme von unpack:
 
-- Beginne wieder mit dem Table
MyTable = {0, 42, 5, "Dario"}
-- Speichere nun alle Werte in einzelne Variablen mit unpack
Variable1, Variable2, Variable3, Variable4 = unpack(MyTable)

Beide gezeigten Varianten haben genau den gleichen Effekt. Der Vorteil von unpack ist, dass man die Größe des Tables nicht kennen muss und vor allem bei großen Tables deutlich weniger zu schreiben hat.


math.random

math.random(_a, _b) ermittelt eine (ganzzahlige) Zufallszahl. In welchen Grenzen sich diese Zufallszahl bewegt, hängt von den Parametern _a und _b, bzw. ob sie überhaupt angegeben wurden.

Sind _a und _b angegeben, wird eine ganze Zahl zwischen (einschließlich) _a und _b zurückgegeben. Ist nur _a angegeben, wird eine ganze Zahl zwischen 1 und _a zurückgegeben. Sind keine Parameter angegeben, wird eine rationale Zahl zwischen 0 und 1 zurückgegeben.

Falls man eine rationale Zufallszahl mit einer größeren Obergrenze als 1 braucht, kann man das Ergebnis von math.random einfach mit dieser Obergrenze multiplizieren:

-- Ermittle eine Zufallszahl zwischen 0 und 2*π
RandomNumber = math.random() * 2*math.pi


table.getn

table.getn (_Table) hast du schon in Ebene 1 kennengelernt. Die Funktion gibt die Anzahl der sequentiellen numerischen Einträge im Table _Table zurück (also wie viele Einträge von Index 1 aufwärts ununterbrochen im Table sind).

Die Funktion wird oft in Schleifen verwendet, um durch numerische Tables zu iterieren (siehe z.B. hier). In Kombination mit math.random(_a, _b) kann sie auch verwendet werden, um ein zufälliges Element aus einem numerischen Table zu wählen:

MyTable = {"Hallo", "Hello", "Salut", "Ciao", "Hola", "Hej"}
 
-- Wähle zufällig einen Gruß:
RandomIndex = math.random(table.getn(MyTable))
RandomGreeting = MyTable[RandomIndex]
 
print(RandomGreeting)


table.insert/table.remove

table.insert (_Table, [_Index,] _Value) und table.remove (_Table, [_Index,] ) fügen einen numerischen Eintrag in das Table _Table am Index _Index ein oder löschen ihn wieder heraus. Für alle anderen Einträge (bzw. solche mit höherem Index) werden die jeweiligen Indizes angepasst, sodass das nicht händisch gemacht werden muss. Ein kleines Beispiel, in dem wir einen Eintrag einfügen und einen anderen löschen:

-- hier stimmt etwas nicht
MyOrder = {1, 1, 2, 9, 5, 8, 13}
-- wir entfernen die Zahl an Stelle 5
table.remove(MyOrder, 4)
 
-- table.getn gibt nun die richtige Länge des Tables zurück,
-- nämlich 6 (da wir ein Element entfernt haben)
for i = 1, table.getn(MyOrder) do
    -- Index 1 bis 6 sind lückenlos besetzt, da table.remove den Index der letzten drei Werte
    -- (also 5, 8 und 13) um jeweils 1 reduziert hat
    print(i .. ": " .. MyOrder[i])
end
 
-- jetzt setzen wir an die Stelle 4 die korrekte Zahl
-- An Stelle 4 steht eigentlich schon eine Zahl (nämlich 5)
-- Die rückt automatisch zusammen mit allen folgenden Zahlen um 1 nach oben
table.insert(MyOrder, 4, 3)
 
-- table.getn passt sich auch bei einem table.insert-Aufruf an
for i = 1, table.getn(MyOrder) do
    -- Index 1 bis 7 sind lückenlos besetzt, da table.insert den Index der letzten drei Werte
    -- (also 5, 8 und 13) um jeweils 1 erhöht hat
    -- Der Index 4 wurde nicht überschrieben
    print(i .. ": " .. MyOrder[i])
end


(Fast) alles, was mit Mathe zu tun hat

Leider mögen einige Leute Mathematik nicht besonders. Fürs Programmieren ist sie aber unerlässlich. Die Übersicht über die math-Funktionen solltest du gut durchlesen, um deine Möglichkeiten zur Befolgung (einfacher) Rechenvorschirften zu kennen. Die Grundrechenarten reichen oft nicht aus.

Ein Beispiel ist die Funktion LookAt(_Settler, _Entity), die eine Entity _Settler so ausrichtet, das sie _Entity anschaut. Sie funktioniert allerdings nur für Siedler (im ersten Parameter). Willst du beispielsweise ein Gebäude auf eine Straße ausrichten oder eine Palisade senkrecht zu einem Bezugspunkt, hilft math.atan2.

Auch kann es vonnöten sein, den Abstand zwischen zwei (Entity-)Positionen zu ermitteln. Dazu braucht man den Satz des Pythagoras, mit dessen Hilfe der Euklidische Abstand in der (Siedler-)Ebene ausgerechnet wird. Ohne Potenz und Quadratwurzel ist das nicht möglich.


Im nächsten Kapitel beschäftigen wir uns mit fortgeschrittenen Schleifen und lernen unter anderem die oben kurz beschriebenen Funktionen pairs und ipairs näher kennen.

Nächstes Kapitel: Weiteres zu Schleifen
Zurück nach oben