GameMaker
← Bring content into your game
GameMaker · GML (struct_get / struct_exists)
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
Add story.json as an Included File. Create obj_dialogue and place one instance in the first room. Paste the code into Create. Add a Draw GUI event containing draw_text_ext(24, 24, dialogue_text, -1, 700);. This entry uses desktop file access.
story.json · Export files explained
2 · Show the first text
// obj_dialogue: Create event. story.json is an Included File.
dialogue_text = "Cannot read story.json";
var file = buffer_load(working_directory + "story.json");
if (file >= 0) {
var raw = buffer_read(file, buffer_text);
buffer_delete(file);
try {
story = json_parse(raw);
var locale = "en";
var id = "fd7b61a3-8233-4ba7-8f77-b88b119a91bf";
var record = struct_get(story.content.texts, id);
var message = record.sourceMessage;
if (struct_exists(story.content.translations, locale)) {
var translations = struct_get(story.content.translations, locale);
if (struct_exists(translations, id)) message = struct_get(translations, id).message;
}
dialogue_text = "";
for (var i = 0; i < array_length(message.segments); i++) {
var segment = message.segments[i];
if (segment.kind != "text") throw "Text-only example";
dialogue_text += segment.text;
}
} catch (error) { dialogue_text = "Cannot read this story text"; }
}
// Put the following line in the same object's Draw GUI event, not Create:
// draw_text_ext(24, 24, dialogue_text, -1, 700);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.
Draw name/dialogue in Draw GUI. Use button instances carrying an option ID for answers. End: set a dialogue_open variable to false and gate drawing/input on it. Do not call game_end().
- 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.
// After story was loaded successfully.
var choice = struct_get(story.execution.nodes, "42edfff8-b8fe-46bf-ae0d-9e2347b6e726");
for (var i = 0; i < array_length(choice.optionOrder); i++) {
var option_id = choice.optionOrder[i];
var option = struct_get(choice.options, option_id);
show_debug_message(option_id + " " + option.text.textRef);
// Resolve text; keep option_id on your answer button instance.
}
var branch = struct_get(story.execution.nodes, "c1c3c372-0a73-4cd0-851d-ede59d5709bb");
var gold = 10; // Repeat with 2.
var next_step = gold >= branch.condition.right.value.value ? branch.whenTrue : branch.whenFalse;
show_debug_message(next_step.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.
// Import mira.png as sprite spr_mira. In Create:
portraits = {};
struct_set(portraits, "807b2957-7bab-4a28-83a4-1f3d1589bbc2", spr_mira);
// In Draw GUI, with node holding the current dialogue struct:
if (struct_exists(portraits, node.speakerRef)) {
draw_sprite(struct_get(portraits, node.speakerRef), 0, 96, 180);
}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
Include the file for your selected build target. Read ID keys with struct_get; names containing hyphens are not dot properties. Adapt and test the file-loading path separately for browser targets.
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: