MonoGame
MonoGame 3.8 · DesktopGL · C# / .NET
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
Beginne mit einem MonoGame DesktopGL-Projekt. Lege story.json unter Content/ ab und kopiere sie als rohe Datei ins Ausgabeverzeichnis (siehe Projektdatei unten). Ergänze ReadWelcome in Game1. Erstelle im Content Pipeline Tool eine SpriteFont namens DialogueFont, baue den Content und lade sie mit Content.Load
story.json · Exportdateien erklärt
2 · Den ersten Text anzeigen
<ItemGroup>
<None Update="Content/story.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>In Game1 Felder SpriteFont _dialogueFont; und string _dialogueLine = ""; anlegen. In LoadContent: _dialogueFont = Content.Load
// Game1.cs: add using System.IO; using System.Text.Json; using System.Text;
// Place this method inside the existing Game1 class.
private string ReadWelcome(string locale)
{
using var stream = TitleContainer.OpenStream("Content/story.json");
using var document = JsonDocument.Parse(stream);
var content = document.RootElement.GetProperty("content");
const string id = "fd7b61a3-8233-4ba7-8f77-b88b119a91bf";
var message = content.GetProperty("texts").GetProperty(id).GetProperty("sourceMessage");
if (content.GetProperty("translations").TryGetProperty(locale, out var table)
&& table.TryGetProperty(id, out var translation))
message = translation.GetProperty("message");
var line = new StringBuilder();
foreach (var segment in message.GetProperty("segments").EnumerateArray())
{
if (segment.GetProperty("kind").GetString() != "text")
throw new InvalidDataException("Text-only example");
line.Append(segment.GetProperty("text").GetString());
}
return line.ToString();
}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: SpriteBatch.DrawString innerhalb Begin/End. Für längere Texte Zeilenumbruch und passende Schriftzeichen selbst berücksichtigen. Auswahlrechtecke und Klick-/Tastaturauswertung gehören zum Spiel; IDs statt übersetzter Texte speichern. Ende: Anzeige und Eingabe über dialogueOpen = false abschalten, nicht Game.Exit().
- Weiter und Ende: Verbindungen verfolgen, Textbox schließen
- Choices: Antwort-ID, Reihenfolge und ausgewählter Ausgang
- Conditions und Variablen: zehn oder zwei Goldstücke
- Sprache: dieselben IDs, neu aufgelöste Inhalte
- Command: Gegenstand geben oder einen Shop öffnen
- 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 ReadWelcome while document is alive; inspect data before returning.
var nodes = document.RootElement.GetProperty("execution").GetProperty("nodes");
var choice = nodes.GetProperty("42edfff8-b8fe-46bf-ae0d-9e2347b6e726");
foreach (var idToken in choice.GetProperty("optionOrder").EnumerateArray())
{
string optionId = idToken.GetString();
var option = choice.GetProperty("options").GetProperty(optionId);
System.Console.WriteLine(optionId + " " + option.GetProperty("text").GetProperty("textRef").GetString());
}
var branch = nodes.GetProperty("c1c3c372-0a73-4cd0-851d-ede59d5709bb");
int gold = 10; // Repeat with 2.
int minimum = branch.GetProperty("condition").GetProperty("right").GetProperty("value").GetProperty("value").GetInt32();
var next = branch.GetProperty(gold >= minimum ? "whenTrue" : "whenFalse");
System.Console.WriteLine(next.GetProperty("nodeRef").GetString());
// Copy strings/values you need later before disposing JsonDocument.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.
// Game1 class field, so both LoadContent and Draw can access it:
private readonly System.Collections.Generic.Dictionary<string, Texture2D> portraits = new();
// Inside LoadContent(): import/build mira.png as portraits/mira.
portraits["807b2957-7bab-4a28-83a4-1f3d1589bbc2"] = Content.Load<Texture2D>("portraits/mira");
// Inside a SpriteBatch Begin/End in Draw; speakerId comes from speakerRef:
if (portraits.TryGetValue(speakerId, out var portrait))
_spriteBatch.Draw(portrait, new Vector2(24, 120), Color.White);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
JSON wird hier nicht durch Content.Load geladen. TitleContainer öffnet die unverarbeitete Datei; die csproj sorgt für deren Kopie. SpriteFont und Texturen werden dagegen über die Content Pipeline gebaut. Den Einstieg zunächst auf DesktopGL verwenden; andere Plattformen separat prüfen.
Dein Ergebnis prüfen
- Der englische und deutsche Begrüßungstext erscheinen korrekt; eine nicht vorhandene Sprache fällt auf Englisch zurück.
- Beim Ergänzen des Ablaufs: beide Antworten, Gold 10/2, Rückkehr aus der Untergeschichte und Ende ausprobieren.
- 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: