Noch nie gescriptet? Der Guide Scripting für Einsteiger auf visionaire-studio.net zeigt an einem kleinen Beispiel, wann sich Lua lohnt und wie du deine ersten Skripte schreibst.
Überblick
Willkommen zu AFRLmes Einführung in Lua, für Einsteiger und alle, die ihr Wissen auffrischen wollen. Hier lernst du die Grundlagen von Lua mit Beispielen und Bildern kennen. Wie du Lua zusammen mit Visionaire Studio einsetzt, erfährst du in Lua in Visionaire Studio, in den Datenstrukturen, in den globalen Befehlen, im Skriptverzeichnis und in der offiziellen Lua-Dokumentation von Visionaire Studio.
Bevor du loslegst, lies kurz die Hinweise zum Ausprobieren der Beispiele weiter unten. Oder spring direkt zur Übersicht und fang an.
Inhalt
| # | Kapitel | Beschreibung |
|---|---|---|
| 0 | Überblick | Diese Seite |
| 1 | Einführung | Kurzer Überblick über Lua mit ein paar zusätzlichen Hinweisen. |
| 2 | Grundlagen | Die grundlegenden Bausteine von Lua. |
| 3 | Operatoren | Mit Operatoren rechnest du, vergleichst Werte und verknüpfst Bedingungen. |
| 4 | Typen | Lua kennt Zahlen, Zeichenketten, Tabellen, Wahrheitswerte und sogar Funktionen als Typen. |
| 5 | Tabellen | Tabellen gehören zu den wichtigsten Bausteinen von Lua. |
| 6 | Schleifen | Schleifen wiederholen Code für jeden Eintrag einer Tabelle oder solange eine Bedingung erfüllt ist. |
| Funktionen | Funktionen verarbeiten Daten und geben Ergebnisse zurück. Sie sparen Arbeit, weil du sie immer wieder verwenden kannst. |
Beispiele ausprobieren
Alle Beispiele dieser Anleitung kannst du ohne zusätzliche Software ausprobieren: Lege im Skriptbereich von Visionaire Studio ein Skript an, füge den Code ein und starte das Spiel. Ausgaben von print erscheinen in der Logdatei und in der Konsole des Players (im Testmodus mit der Taste Tab ein- und ausblenden).
Wenn du Lua lieber außerhalb von Visionaire testen möchtest, führt die Online-Demo auf lua.org reines Lua direkt im Browser aus. Code-Editoren wie Visual Studio Code mit einer Lua-Erweiterung helfen zusätzlich mit Syntaxhervorhebung und Fehlerhinweisen. Beachte, dass Visionaire-Befehle wie getObject nur innerhalb der Engine funktionieren.
Einführung
Was ist Lua?
Lua ist eine schlanke, plattformunabhängige Skriptsprache. Ursprünglich wurde sie entwickelt, um bestehende Programmiersprachen zu erweitern. Weil sie leicht zu lernen ist und sich einfache Abläufe, Funktionen und Tabellen damit schnell umsetzen lassen, ist sie heute in vielen Game Engines die erste oder zweite Skriptsprache.
Mehr Informationen findest du auf lua.org und bei Wikipedia.
Was bedeutet der Name Lua?
Richtig geschrieben heißt es nichtLUA, sondern Lua. Der Name ist keine Abkürzung, sondern einfach das portugiesische Wort für Mond.
Welchen Sprachen ähnelt Lua?
Lua ähnelt Programmiersprachen wie C, C#, C++ oder Java, ist aber deutlich einfacher. Zum Beispiel musst du beim Anlegen einer Variable keinen Typ angeben.
Warum Lua lernen?
Warum solltest du überhaupt Lua lernen? Visionaire Studio bringt so viele fertige Aktionen und Abfragen mit, dass du damit fast ein komplettes kommerzielles Spiel bauen kannst. Wie gut es wird, liegt an dir und deinem Team.
Die Antwort ist einfach: Warum nicht? Mit Lua erweiterst du die vorhandenen Aktionen und Abfragen oder baust ganz neue Funktionen, die Visionaire Studio von Haus aus nicht mitbringt.
Lua ist leicht zu lernen. Wer schon ein wenig programmiert hat, und sei es nur einfaches HTML, findet sich schnell zurecht. Für manche Dinge brauchst du Lua sogar, zum Beispiel wenn Spieler Screenshots erstellen sollen, wenn dein Spiel die gewählten Optionen beim nächsten Start wieder kennen soll oder wenn du über die eingebauten Möglichkeiten der Engine hinausgehen willst.
Lern zumindest die Grundlagen. Was du hier lernst, hilft dir auch in anderen Skript- und Programmiersprachen. Vielleicht entdeckst du dabei sogar Spaß am Programmieren und wagst dich später an Sprachen wie C# oder C++, die in Engines wie Unity oder Unreal Engine zum Einsatz kommen.
Grundlagen
Hier geht es um einige Grundbausteine von Lua, die keine eigene Seite brauchen. Du begegnest ihnen in den Beispielen dieser Anleitung immer wieder.
Mit print schreibst du Meldungen in die Logdatei oder in die Lua-Konsole. Das hilft dir beim Testen und bei der Fehlersuche in deinen Skripten.
print("hello world") -- prints "hello world" into the log/console (ah yes how cliché of me, but it had to be done)
Variablen
Variablen sind Namen, unter denen du Daten speicherst und wieder abrufst. In Lua können Variablen lokal oder global sein. Anders als in vielen anderen Sprachen gibst du beim Anlegen keinen Typ an, und du kannst eine Variable jederzeit mit neuen Daten überschreiben.
a = 1
Verkettung
Verkettung bedeutet, zwei oder mehr Zeichenketten aneinanderzuhängen. Dafür schreibst du zwei Punkte: ..
a = "hello"
b = "world"
print(a .. " " .. b) -- prints "hello world" - we had to add " " to create a space between the 2 words
Return
Mit return gibst du Daten aus einem Skript oder einer Funktion zurück, damit ein anderes Skript oder eine andere Funktion sie weiterverwenden kann.
function hello()
return "hello world!"
end
print( hello() ) -- prints "hello world!"
Global oder lokal
Global und lokal betrifft Variablen, Tabellen und Funktionen gleichermaßen. Lokales gilt nur innerhalb des Skripts oder der Funktion, in der es angelegt wurde. Globales kannst du in allen Skripten verwenden.
Global verwendest du meist für Funktionen, Tabellen und Variablen, auf die mehrere Skripte oder verschiedene Stellen zugreifen müssen.
local a = 1 -- only accessible in this script
a = 1 -- can be accessed from anywhere
function return_n(n)
local a = n -- only valid inside of this function but can be returned outside of function
return a
end
| Hinweis: Achte bei globalen Namen darauf, dass du denselben Namen nicht in einem anderen Skript erneut vergibst. Sonst überschreibst du die vorhandenen Daten der Variable oder Funktion, und dein Skript funktioniert nicht mehr. |
Kommentare
Einzeilige Kommentare
Stehen entweder in einer eigenen Zeile oder am Ende einer Zeile.
-- this is a single line comment
i = 10 -- comment placed after working code
-- comment place before code; i = 10 -- notice how the code is also commented out?
Mehrzeilige Kommentare
Können überall im Skript stehen und über mehrere Zeilen gehen.
--[[
this is a multiple line comment
I can go on & on & on
& on & on
& on.
]]
local i = 2 * --[[ this is a comment ]] 2
print(i) -- would print 4 to the log (2x2)
Verschachtelte mehrzeilige Kommentare
Damit kommentierst du ganze Codeblöcke aus, auch wenn sie bereits mehrzeilige Kommentare enthalten. Die vorhandenen Kommentare beenden den äußeren Kommentar dann nicht vorzeitig.
--[=[
this is a nested comment
see how --[[ we can include ]]
a multi-line comment inside of it?
]=]
--[[
this is what would happen if we were to use
a regular multi-line --[[ comment ]]
i = 10
]]
Typen
Lua kennt mehrere Typen. Welchen Typ eine Variable, Funktion oder Tabelle hat, ergibt sich automatisch aus ihrem Wert.
Typen
| boolean | Ein Wahrheitswert: true (wahr) oder false (falsch). |
| function | Eine Funktion enthält meist eine Folge von Anweisungen und kann Werte berechnen und zurückgeben. |
| nil | Kommt kein Wert zurück, ist das Abgefragte leer oder existiert nicht. Es ist dann nil. |
| number | Eine ganze Zahl oder eine Kommazahl. |
| string | Eine Zeichenkette, also Text oder Zahlen in "Anführungszeichen" oder 'Hochkommas'. |
| table | Eine Liste oder mehrere verschachtelte Listen mit Daten unterschiedlicher Typen. |
Boolean
Function
Nil
Number
String
Table
| gibt 1, 2, 3, 4, 5, 6, 7, 8 aus | |
|---|---|
local a = {1,1+1,1*3,2*2,20/4,"6",3.5*2,10-2}
print( a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], type(a) )
|
![]() |
Operatoren
Mit Operatoren rechnest du, vergleichst Werte und verknüpfst Bedingungen.
Bedingungen
| if | Prüft, ob eine Bedingung erfüllt ist. |
| else | Führt etwas anderes aus, wenn die Bedingung nicht erfüllt ist. |
| elseif | Prüft eine weitere Bedingung, wenn die vorherige nicht erfüllt ist. |
| end | Schließt Abfragen und Funktionen ab. Zu jedem if gehört genau ein end. Ein elseif braucht kein eigenes end. |
if
else
| wenn die Bedingung nicht erfüllt ist, dann else | |
|---|---|
local a = false
if a then
print("a = true")
else
print("a = false")
end
|
![]() |
elseif
| wenn die Bedingung nicht erfüllt ist, dann elseif | |
|---|---|
local a = false
if a then
print("a = true")
elseif a == false then
print("a = false")
end
|
![]() |
Logische Operatoren
| and | Prüft mehrere Bedingungen in einer einzigen Abfrage. |
| or | Fügt einer Abfrage eine alternative Bedingung hinzu. |
| not | Prüft, ob eine Bedingung falsch ist. |
and
| wenn Bedingung a wahr und Bedingung b falsch ist | |
|---|---|
local a = true
local b = false
if a == true and b == false then
print("a = true", "b = false")
end
|
![]() |
or
| wenn die eine oder die andere Bedingung wahr ist | |
|---|---|
local a = true
if a or a == true then
print("a = true")
end
|
![]() |
not
Vergleichsoperatoren
| == | Gleich. |
| ~= | Ungleich. |
| >= | Größer oder gleich. |
| > | Größer. |
| <= | Kleiner oder gleich. |
| < | Kleiner. |
gleich
ungleich
größer oder gleich
größer
kleiner oder gleich
kleiner
Rechenoperatoren
| + | Addieren |
| - | Subtrahieren oder Vorzeichen umkehren |
| * | Multiplizieren |
| / | Dividieren |
| ^ | Potenz |
| % | Rest einer Division |
addieren
subtrahieren
Vorzeichen umkehren
| Umkehrung von 3 = -3 | |
|---|---|
local a = 3
local result = -a
print( "original value: " .. a, "inversed value: " .. result )
|
![]() |
multiplizieren
dividieren
Potenz
Rest
Tabellen
Tabellen machen Lua so flexibel und einfach: Du legst sie mühelos an und kannst Daten einfügen, entfernen und sortieren. Eine Tabelle besteht meist aus Einträgen mit einem Schlüssel oder einer Indexnummer und einem Wert. Auf die Einträge kannst du auf verschiedene Arten zugreifen.
Tabellen anlegen
Hier siehst du, wie du verschiedene Arten von Tabellen anlegst.
Indextabellen
Schlüsseltabellen
Indexwerte mit Untertabellen
| automatisch vergebene Indexeinträge mit Untertabellen, die Schlüssel enthalten | |
|---|---|
local t = {
{x = 100, y = 300},
{x = 200, y = 111}
}
print("x = " .. t[1].x .. ", y = " .. t[1].y)
|
![]() |
Schlüssel mit Untertabellen
Weitere Methoden und Tabellenfunktionen
Hier findest du Tabellenfunktionen und fortgeschrittene Methoden für die Arbeit mit Tabellen.
Tabelleneinträge verketten
| Einträge ohne Trennzeichen verketten (nur Indextabellen) | |
|---|---|
local t = {1, 2, 3, 4}
print( table.concat(t) )
|
![]() |
| Einträge mit Trennzeichen verketten (nur Indextabellen) | |
|---|---|
local t = {1, 2, 3, 4}
print( table.concat(t, ", ") )
|
![]() |
| Einträge mit Trennzeichen und festgelegtem Indexbereich verketten (nur Indextabellen) | |
|---|---|
local t = {1, 2, 3, 4}
print( table.concat(t, ", ", 2, 4) )
|
![]() |
Einträge einfügen
| Hinweis: Technisch kannst du Schlüssel und Indexwerte in einer Tabelle mischen. Übersichtlicher ist es aber, wenn du es nicht tust. Indexwerte in Untertabellen einer Schlüsseltabelle oder Schlüssel in Untertabellen einer Indextabelle sind dagegen kein Problem. |
Einträge entfernen
| Hinweis: Wenn du in eine Indextabelle einen Eintrag einfügst oder einen entfernst, passt Lua die Indexwerte aller folgenden Einträge automatisch an. |
Tabellen sortieren
Hinweis: Tabellen mit gemischten Daten führen bei table.sort zu einem Fehler. Die Tabelle muss entweder nur Zeichenketten oder nur Zahlen enthalten. Als Ausweg kannst du Zahlen als Zeichenketten einfügen.
|
Einträge zählen
Schleifen
Daten in einer Schleife zu durchlaufen, um sie zu lesen oder zu ändern, spart beim Skripten enorm viel Zeit. Lua bietet dafür Zählschleifen mit for, for-Schleifen über Tabellen sowie while- und repeat-Schleifen.
Hinweis: Eine Schleife läuft komplett durch, bevor die nächste Zeile danach ausgeführt wird. In Visionaire heißt das auch: Solange eine Schleife läuft, kann das Spiel kein neues Bild zeichnen. Verwende deshalb nie eine Schleife, um auf etwas zu warten (einen Wert, einen Klick, einen Timer). Nimm dafür einen Event-Handler für die Hauptschleife, setDelay oder das Aktionsteil „Pause“. |
Zählschleife
Zählt von einem Startwert bis zu einem Endwert. Ein optionaler dritter Wert legt die Schrittweite fest.
local t = {"Hi,", "my", "name", "is", "Barry."}
local str = ""
for i = 1, #t do -- for variable equals 1 to table total entries do
str = str .. t[i] -- insert string from table based on current index value into the str variable
if i < #t then str = str .. " " end -- if i is less than table total then insert white space after each word
end
print(str) -- prints: Hi, my name is Barry.
for i = 10, 1, -2 do -- count down from 10 to 1 in steps of 2
print(i) -- prints 10, 8, 6, 4, 2
endipairs: Indextabellen
ipairs durchläuft eine Indextabelle der Reihe nach ab Index 1 und stoppt beim ersten leeren Eintrag.
local fruit = {"apple", "banana", "cherry"}
for i, name in ipairs(fruit) do
print(i .. ": " .. name) -- prints 1: apple, 2: banana, 3: cherry
endpairs: Schlüsseltabellen
pairs durchläuft alle Einträge einer Tabelle, auch die mit Schlüsseln. Die Reihenfolge ist dabei nicht festgelegt.
local player = {name = "Barry", coins = 12, hasKey = true}
for key, value in pairs(player) do
print(key .. " = " .. tostring(value))
endwhile
Wiederholt einen Block, solange eine Bedingung wahr ist. Die Bedingung wird vor jedem Durchlauf geprüft.
local n = 1
while n < 100 do
n = n * 2
end
print(n) -- prints 128repeat … until
Wie while, nur wird die Bedingung nach jedem Durchlauf geprüft. Der Block läuft also mindestens einmal.
local roll
repeat
roll = math.random(1, 6)
until roll == 6
print("finally a six")break
break beendet die aktuelle Schleife sofort.
local t = {3, 8, 15, 4}
for i = 1, #t do
if t[i] > 10 then
print("first value above 10 is at index " .. i) -- prints 3
break
end
endSchleifen über Visionaire-Objekte
Listen aus der Datenstruktur, zum Beispiel die Objekte einer Szene oder die Items eines Charakters, kannst du wie eine Indextabelle durchlaufen.
local objects = game.CurrentScene.Objects
for i = 1, #objects do
print(objects[i]:getName()) -- prints the name of every object of the current scene
end
for i, item in ipairs(game.CurrentCharacter.Items) do
print(item:getName()) -- prints every item the current character carries
endFunktionen
Funktionen sind sehr nützlich: Sie verarbeiten oder berechnen große Datenmengen und geben das Ergebnis zurück. Mit Eingabeparametern kannst du dieselbe Funktion immer wieder verwenden. Das spart Arbeit und macht deine Skripte übersichtlicher.
Funktionen anlegen
Hier siehst du, wie du eigene Funktionen anlegst.















































