Unity
← Bring content into your game
Unity 6 · C# · Newtonsoft Json
Start with one visible sentence. This small example reads the real Harbour export directly; it is not a complete dialogue player. Then connect the data to your game UI.
1 · Prepare files and scene
Import story.json into Assets/Story. In Package Manager install Unity package com.unity.nuget.newtonsoft-json. Create Canvas → Text - TextMeshPro and import TMP Essentials if prompted. Attach FirstText.cs to a GameObject. Assign the JSON TextAsset and text object to storyFile and dialogueText in the Inspector. Press Play.
story.json · Export files explained
2 · Show the first text
using System;
using Newtonsoft.Json.Linq;
using TMPro;
using UnityEngine;
public class FirstText : MonoBehaviour
{
[SerializeField] private TextAsset storyFile;
[SerializeField] private TMP_Text dialogueText;
private JObject story;
private void Start()
{
try { story = JObject.Parse(storyFile.text); ShowLanguage("en"); }
catch (Exception error) { dialogueText.text = "Cannot read story.json"; Debug.LogException(error); }
}
public void ShowLanguage(string locale)
{
const string id = "fd7b61a3-8233-4ba7-8f77-b88b119a91bf";
var content = story["content"];
var translation = content["translations"]?[locale]?[id];
var message = translation?["message"] ?? content["texts"][id]["sourceMessage"];
string line = "";
foreach (var segment in message["segments"])
{
if ((string)segment["kind"] != "text") throw new Exception("Text-only example");
line += (string)segment["text"];
}
dialogueText.text = line;
}
}Expected: “Welcome to the harbour. I am Mira.” With locale = "de" or the language parameter de: “Willkommen im Hafen. Ich bin Mira.” A missing language uses source text. This sample supports text segments; it deliberately does not silently discard placeholders.
3 · From one sentence to a conversation
The fixed text ID above is for the first test. In your game choose flowRef/entryRef from story-index.json, read execution.entries[entryRef].nodeRef, then execution.nodes[nodeRef]. The current dialogue supplies text.textRef and speakerRef. Continuations depend on node kind.
Name/dialogue: TMP_Text.text. Answers: Button.onClick; retain each option ID in a separate local variable. End: dialogPanel.SetActive(false). A button can call ShowLanguage with the string de without resetting progress.
- Continue and End: follow connections, close the text box
- Choices: answer ID, order and selected continuation
- Conditions and variables: ten or two gold
- Language: the same IDs, newly resolved content
- Command: give an item or open a shop
- Call/Return: visit a substory and return
Inspect answers and the gold check in this language
Read the data for a choice
Insert this fragment where story is available after loading (for RPG Maker: const story = $gameTemp.vnleExample.story;). It prints IDs for inspection. Replace the output with your answer buttons. It covers the two Harbour answers and their following gold check, not a general interpreter.
// Inside a method after story (JObject) has been loaded.
var choice = story["execution"]["nodes"]["42edfff8-b8fe-46bf-ae0d-9e2347b6e726"];
foreach (var optionIdToken in choice["optionOrder"])
{
string optionId = (string)optionIdToken;
var option = choice["options"][optionId];
Debug.Log(optionId + " " + (string)option["text"]["textRef"]);
// Resolve the text and retain optionId in your Button.onClick listener.
}
var branch = story["execution"]["nodes"]["c1c3c372-0a73-4cd0-851d-ede59d5709bb"];
int gold = 10; // Repeat with 2.
var next = gold >= (int)branch["condition"]["right"]["value"]["value"]
? branch["whenTrue"] : branch["whenFalse"];
Debug.Log((string)next["nodeRef"]);With 10 gold, next refers to “Pay five gold”; with 2 it refers to “Not enough gold”. In the actual game, run the check only when the selected path reaches this node. Each selected answer supplies its own continuation.
4 · Map your own images
This supplementary excerpt expects a current dialogue object named node and the UI elements named in its comments. For C++ and MonoGame, speakerRef has already been read as SpeakerId or speakerId. The key is Mira’s actual character ID; the image name and location belong to your game. Insert the lines at the indicated locations.
// Add inside your own MonoBehaviour. Assign a Sprite and a UI Image in Inspector.
[SerializeField] private Sprite miraPortrait;
[SerializeField] private UnityEngine.UI.Image portrait;
// node is the current JObject dialogue:
portrait.sprite = (string)node["speakerRef"] == "807b2957-7bab-4a28-83a4-1f3d1589bbc2" ? miraPortrait : null;
portrait.enabled = portrait.sprite != null;Resolve speaker names through content.characters[speakerRef].nameTextRef just like dialogue text. Missing mappings should hide the previous portrait or show a placeholder. Images are not selected by language.
Use image references from the complete export
5 · Ship files with the game
The referenced TextAsset is included with the scene. ID tables are JSON objects with dynamic keys; JsonUtility is not a direct replacement for JObject here. This example does not require StreamingAssets file access.
Check your result
- English and German greetings display correctly; an unavailable language falls back to English.
- When adding flow: try both answers, gold 10/2, the return from the substory and End.
- Run the built game outside your project folder. JSON, fonts and portraits must be available there too.
Official documentation
API and setup references for this approach: