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.
Visionaire Studio bringt eine eigene Skriptumgebung mit. Sie besteht aus Lua und dem Visionaire-Objektmodell. Über das Objektmodell greifst du bequem auf die Datenstruktur von Visionaire zu. Fast alles in Visionaire ist ein Objekt (zum Beispiel Szene, Charakter, Interface), und du kannst jedes davon per Skript auslesen und verändern.
Lua
Visionaire Studio verwendet derzeit Lua in Version 5.4.
Wenn du mehr über die Sprache lernen möchtest, hilft dir die offizielle Dokumentation auf der Lua-Website oder eines dieser Tutorials:
- Referenzhandbuch: https://www.lua.org/manual/5.4/
- Programming in Lua: https://www.lua.org/start.html
- Lua-Tutorial: https://www.tutorialspoint.com/lua/index.htm
- Lua in 15 Minuten: https://tylerneylon.com/a/learn-lua/
Eine Einführung in Lua von unserem Community-Mitglied AFRLme findest du auch hier im Wiki:
Das Visionaire-Objektmodell
Jedes Visionaire-Projekt wird in einer hierarchischen Datenstruktur gespeichert. Jedes Objekt dieser Datenstruktur ist ein „VisionaireObject“ (TVisObj). Alle Objekte desselben Typs (zum Beispiel Szenen oder Buttons) liegen in einer gemeinsamen Tabelle (zum Beispiel „Scenes“ oder „Buttons“).
Auf die Eigenschaften eines Objekts greifst du über die Felder zu, die für die jeweilige Tabelle festgelegt sind. Ein Feld kann einen einzelnen Wert enthalten (zum Beispiel eine Zahl oder einen Text), eine Tabelle mit Werten, einen Link auf ein anderes VisionaireObject oder eine Liste solcher Links. Alle Objekte und ihre Felder sind unter Datenstrukturen beschrieben. Die verschiedenen Feldtypen findest du weiter unten.
Auf Objekte und Felder zugreifen
Die Tabellen der Datenstruktur sind global verfügbar. Objekte in den Tabellen sprichst du meist über ihren Namen an, du kannst aber auch den Index der Tabelle verwenden. Das Objekt „game“ steht in keiner Tabelle, sondern ist direkt verfügbar.
-- Examples of accessing a VisionaireObject by (a unique) name
local char = Characters["hero"]
local coins = Values["coins"]
-- The following syntax is also possible, but be aware that it only works for object names which don't contain
-- special characters or whitespaces (only A-Z, a-z, 0-9 and underscore allowed) and start with a letter
local char = Characters.hero
-- Access a VisionaireObject by table index: get the first object in the "Characters" table
local char = Characters[1]
Auf die Eigenschaften eines Objekts greifst du über seine Felder zu:
-- Example of accessing a property of a VisionaireObject
local char = Characters["hero"]
local pos = char.Position
-- This leads to the same result
local pos = Characters["hero"].Position
-- Get the integer value ("Int" field) of the "Value" object called "coins"
local num_coins = Values["coins"].Int
-- The "game" object is directly accessible
local scr_pos = game.ScrollPosition
Sind in einer Eigenschaft andere VisionaireObjects verknüpft, kannst du den vollständigen Objektpfad angeben. Das hilft besonders, wenn Objektnamen nicht eindeutig sind und du sie nicht allein über den Namen erreichst:
-- Let's say each character has a value property called "coins"; it is not possible to use 'Values["coins"]'
-- because the name is not unique; now access the different values by using the object path
local hero_num_coins = Characters["hero"].Values["coins"].Int
local villain_num_coins = Characters["villain"].Values["coins"].Int
local cur_num_coins = game.CurrentCharacter.Values["coins"].Int
-- Object paths can be even longer
local door_state = Scenes["kitchen"].Objects["door"].Conditions["door_closed"]
-- If the condition name "door_closed" is unique in the project, the following leads to the same result
local door_state = Conditions["door_closed"]
Einen Feldwert zu schreiben ist genauso einfach. Allerdings lassen sich nicht alle Felder der Datenstruktur per Skript ändern. Welche es sind, steht unter Datenstrukturen:
-- Lower the brightness of a scene to 80%
Scenes["kitchen"].Brightness = 80
-- Make the villain the playable character
game.CurrentCharacter = Characters["villain"]
-- Set a condition to true
Conditions["door_closed"].Value = true
-- Change the integer value of a "Value" object
Characters["hero"].Values["coins"].Int = 47
Felder, die jedes VisionaireObject hat
Die folgenden Felder hat jedes VisionaireObject. Sie lassen sich nur lesen (außer „name“, das du mit der Methode „setName“ ändern kannst):
- id: Die interne ID des Objekts (Ganzzahl).
- name: Der interne Name des Objekts aus dem Editor (Text). Nicht zu verwechseln mit der Eigenschaft „Name“ (mit großem „N“), die es bei manchen Objekten gibt und die den mehrsprachigen Namen im Spiel enthält.
- parent: Gibt das übergeordnete Objekt zurück (TVisObj).
- tableId: Die ID der Datenstruktur-Tabelle, zu der das Objekt gehört (Ganzzahl).
Feldtypen
Die Feldtypen der Datenstruktur entsprechen diesen Lua-Typen:
| Feldtyp | Lua-Typ/Struktur | Beschreibung | |
|---|---|---|---|
| t_bool | boolean | true oder false | |
| t_int | number | Ganzzahl | |
| t_float | number | Kommazahl | |
| t_string | string | ||
| t_path | string | Dateipfad | |
| t_point | table | x (int) | x-Koordinate |
| y (int) | y-Koordinate | ||
| t_rect | table | x (int) | x-Koordinate der linken oberen Ecke |
| y (int) | y-Koordinate der linken oberen Ecke | ||
| width (int) | Breite des Rechtecks | ||
| height (int) | Höhe des Rechtecks | ||
| t_sprite | table | path (str) | relativer Pfad zur Bilddatei |
| position (t_point) | Versatz des Sprites, wenn es in einer Animation verwendet wird | ||
| transparency (int) | |||
| transpcolor (int) | Transparenzfarbe | ||
| pause (int) | Pause in Millisekunden, wenn das Sprite in einer Animation verwendet wird | ||
| t_text | table | text (str) | |
| sound (str) | Dateipfad zu einer Sounddatei für diesen Text | ||
| language (int) | ID der Sprache dieses Textobjekts | ||
| t_link | string | ein Link auf ein VisionaireObject (TVisObj); beim Lesen bekommst du das Objekt zurück, beim Setzen übergibst du ein Objekt | |
| t_links | table | eine Liste von Links auf VisionaireObjects (TVisObj), die du über Nummern und über die Namen der Objekte durchlaufen kannst | |
| t_vint | table | Tabelle mit Ganzzahlen | |
| t_vfloat | table | Tabelle mit Kommazahlen | |
| t_vstring | table | Tabelle mit Texten | |
| t_vpath | table | Tabelle mit t_path-Einträgen | |
| t_vpoint | table | Tabelle mit t_point-Einträgen | |
| t_vrect | table | Tabelle mit t_rect-Einträgen | |
| t_vsprite | table | Tabelle mit t_sprite-Einträgen | |
| t_vtext | table | Tabelle mit t_text-Einträgen | |
Die alte Langschreibweise
Empfohlen ist die Schreibweise aus dem Abschnitt „Auf Objekte und Felder zugreifen“. Es gibt aber noch einen zweiten Weg, VisionaireObjects anzusprechen. Er stammt aus den Anfängen der Skripte in Visionaire, und du triffst ihn noch in älteren Skriptbeispielen an. Man nennt ihn die „Langschreibweise“, im Gegensatz zur viel einfacheren Kurzschreibweise von oben.
Mit dem globalen Befehl getObject holst du dir ein VisionaireObject, mit den Objektbefehlen liest und setzt du seine Felder:
-- Example of accessing a VisionaireObject by (a unique) name
local char = getObject("Characters[hero]")
-- Example of accessing a VisionaireObject by passing a tuple:
-- get the object with id=1 from the table with id=0 (characters table).
local char = getObject("(0,1)")
-- Note that in the object path, VisionaireObject names need to be prefixed with the (singular) table name
local door_state = getObject("Scenes[kitchen].SceneObjects[door].ObjectConditions[door_closed]")
-- If you want to get/set a field you need the appropriate object method and have to use the field constants.
-- A field constant starts with a "V" followed by the field name (including the aforementioned table prefix)
local is_closed = door_state:getBool(VConditionValue)
door_state:setValue(VConditionValue, true)
Ein Skript anlegen

Skripte legst du im Bereich „Skripte“ des Editors an. Für jedes Skript legst du über die Option oberhalb des Skripteditors fest, ob es ein Definitionsskript oder ein Ausführungsskript ist (siehe Bild). Ein Definitionsskript läuft automatisch beim Spielstart, ein Ausführungsskript muss ausdrücklich aufgerufen werden.
In deinen Aktionen nutzt du Skripte über die Aktionsteile „Call script“ und „Execute a script“. Beim ersten wählst du eines deiner Ausführungsskripte aus, beim zweiten gibst du direkt Lua-Code ein. Mit dem Aktionsteil „If Lua result“ baust du eine Wenn/Sonst-Abfrage mit Lua-Code. Außerdem kann eine Lua-Abfrage Teil einer kombinierten Bedingung sein.
