VNLEWIKIGeschichten entwickeln. Welten verbinden.English
VNLE Handbuch

Defold

← Inhalte ins Spiel einbauen

Defold · Lua · GUI

Beginne mit einem sichtbaren Satz. Dieses kleine Beispiel liest direkt den echten Harbour-Export; es ist kein vollständiger Dialogplayer. Anschließend verbindest du die Daten mit deiner Spieloberfläche.

1 · Dateien und Szene vorbereiten

Kopiere story.json in /story/. Trage /story in game.project unter project → custom_resources ein. Erstelle eine GUI mit einem Textknoten dialogue, wähle dafür eine Font-Ressource und füge die GUI dem Spielobjekt hinzu. Weise der GUI first_text.gui_script zu und starte das Projekt.

story.json · Exportdateien erklärt

2 · Den ersten Text anzeigen

-- first_text.gui_script: attach to a GUI containing a text node named dialogue.
function init(self)
    local raw, error = sys.load_resource("/story/story.json")
    if not raw then
        gui.set_text(gui.get_node("dialogue"), "Cannot load story.json")
        return
    end
    local ok, story = pcall(json.decode, raw)
    if not ok then
        gui.set_text(gui.get_node("dialogue"), "Invalid JSON")
        return
    end
    local locale = "en"
    local id = "fd7b61a3-8233-4ba7-8f77-b88b119a91bf"
    local content = story.content
    local translation = (content.translations[locale] or {})[id]
    local message = translation and translation.message or content.texts[id].sourceMessage
    local parts = {}
    for _, segment in ipairs(message.segments) do
        assert(segment.kind == "text", "Text-only example")
        parts[#parts + 1] = segment.text
    end
    gui.set_text(gui.get_node("dialogue"), table.concat(parts))
end

Erwartet: „Welcome to the harbour. I am Mira.“ Mit locale = "de" beziehungsweise dem Sprachparameter de: „Willkommen im Hafen. Ich bin Mira.“ Fehlt die Sprache, wird der Quelltext verwendet. Das Beispiel unterstützt Textsegmente; Platzhalter werden absichtlich nicht stillschweigend übersprungen.

3 · Von einem Satz zum Gespräch

Die feste Text-ID oben dient dem ersten Test. Im Spiel wählst du flowRef/entryRef aus story-index.json, liest execution.entries[entryRef].nodeRef und dann execution.nodes[nodeRef]. Der aktuelle Dialog liefert text.textRef und speakerRef. Fortsetzungen hängen vom Knotentyp ab.

Name/Dialog: gui.set_text. Antworten: GUI-Knoten, Input Focus und gui.pick_node im on_input; Options-ID separat speichern. Ende: gemeinsame GUI-Elternnode mit gui.set_enabled(node, false) ausblenden und Eingabefokus zurückgeben.

  1. Weiter und Ende: Verbindungen verfolgen, Textbox schließen
  2. Choices: Antwort-ID, Reihenfolge und ausgewählter Ausgang
  3. Conditions und Variablen: zehn oder zwei Goldstücke
  4. Sprache: dieselben IDs, neu aufgelöste Inhalte
  5. Command: Gegenstand geben oder einen Shop öffnen
  6. Call/Return: Untergeschichte aufrufen und zurückkehren
Antworten und Goldprüfung in dieser Sprache nachvollziehen

Die Daten einer Entscheidung lesen

Füge diesen Ausschnitt dort ein, wo story nach erfolgreichem Laden verfügbar ist (bei RPG Maker: const story = $gameTemp.vnleExample.story;). Er gibt IDs zum Nachvollziehen aus. Die Anzeige ersetzt du durch deine Antwortbuttons. Er ist auf die zwei Harbour-Antworten und deren nachfolgende Goldprüfung begrenzt, kein allgemeiner Interpreter.

-- Inside a function where the decoded story table is available.
local choice = story.execution.nodes["42edfff8-b8fe-46bf-ae0d-9e2347b6e726"]
for _, option_id in ipairs(choice.optionOrder) do
    local option = choice.options[option_id]
    print(option_id, option.text.textRef)
    -- Resolve the text; retain option_id for the corresponding GUI button.
end
local branch = story.execution.nodes["c1c3c372-0a73-4cd0-851d-ede59d5709bb"]
local gold = 10 -- Repeat with 2.
local next_step = branch.whenFalse
if gold >= branch.condition.right.value.value then next_step = branch.whenTrue end
print(next_step.nodeRef)

Mit 10 Gold verweist next auf „Pay five gold“, mit 2 auf „Not enough gold“. Beim tatsächlichen Spielen führst du die Prüfung erst aus, wenn der gewählte Pfad diesen Knoten erreicht. Jede ausgewählte Antwort liefert dafür ihre eigene continuation.

4 · Eigene Bilder zuordnen

Dieses Ergänzungsstück setzt einen aktuellen dialogue-Knoten namens node und die im Kommentar genannten UI-Elemente voraus. Bei C++ und MonoGame ist speakerRef bereits als SpeakerId beziehungsweise speakerId ausgelesen. Der Schlüssel ist Miras tatsächliche Charakter-ID; der Bildname und sein Ablageort gehören deinem Spiel. Füge die Zeilen an den angegebenen Stellen ein.

-- Add mira.png to an atlas and register that atlas as portraits in the GUI Textures.
local portraits = { ["807b2957-7bab-4a28-83a4-1f3d1589bbc2"] = "mira" }
local portrait = gui.get_node("portrait") -- GUI Box node using the portraits texture
local animation = portraits[node.speakerRef]
gui.set_enabled(portrait, animation ~= nil)
if animation then gui.play_flipbook(portrait, hash(animation)) end

Sprechernamen über content.characters[speakerRef].nameTextRef genauso wie Dialogtexte auflösen. Eine fehlende Zuordnung soll das alte Porträt ausblenden oder ein Ersatzbild zeigen. Bilder werden nicht nach Sprache gewählt.

Bildverweise aus dem vollständigen Export verwenden

5 · Dateien mit dem Spiel ausliefern

custom_resources nimmt die rohe JSON ins Bundle auf. Lua-Arrays beginnen bei 1: optionOrder mit ipairs durchlaufen. JSON-ID-Tabellen werden mit table[id] gelesen. Bilder als Atlasressourcen in die GUI aufnehmen.

Dein Ergebnis prüfen

  1. Der englische und deutsche Begrüßungstext erscheinen korrekt; eine nicht vorhandene Sprache fällt auf Englisch zurück.
  2. Beim Ergänzen des Ablaufs: beide Antworten, Gold 10/2, Rückkehr aus der Untergeschichte und Ende ausprobieren.
  3. Den gebauten Spielordner außerhalb deines Projekts starten. JSON, Schriften und Porträts müssen dort ebenfalls vorhanden sein.

Offizielle Dokumentation

API- und Einrichtungsreferenzen für diesen Weg: