Intégrer le contenu à votre jeu
VNLE exporte les textes, les traductions et le déroulement que vous avez créé. Votre jeu lit ces données, affiche la boîte de dialogue et relie les actions à ses propres systèmes. Utilisez vos scripts ou une intégration communautaire. Ces exemples expliquent les données sans nécessiter de gestionnaire VNLE.
Fichiers, JSON et points d'entrée
Export → Comprendre les fichiers et le JSON → Rechercher les règles de flux
Tous les exemples utilisent l’export réel de The Harbour Key. Ses longs identifiants appartiennent à ce projet. Remplacez-les par ceux de votre export ; les noms et les textes traduits ne servent pas de clés de référence.
story.json · story-index.json · Exemple de projet modifiable
Choisissez votre moteur
Chaque page explique le chargement et l’affichage dans le moteur concerné. Le parcours ci-dessous présente les règles communes aux données. D’autres moteurs peuvent utiliser le même contrat JSON ; cela ne signifie pas qu’un plugin prêt à l’emploi est fourni.
1 · Afficher un texte à partir du JSON
Commencez par « Welcome to the harbour. I am Mira. ». Un dialogue contient un textRef, pas directement une chaîne de caractères. La table des textes contient des segments. Cet extrait JavaScript suppose que story.json a déjà été lu dans story ; les pages des moteurs expliquent le chargement et l’affichage.
// story is the parsed story.json. This excerpt reads text-only messages.
const locale = 'en';
const textRef = 'fd7b61a3-8233-4ba7-8f77-b88b119a91bf';
const record = story.content.texts[textRef];
const translation = story.content.translations[locale]?.[textRef];
const message = translation ? translation.message : record.sourceMessage;
const text = message.segments.map(segment => {
if (segment.kind !== 'text') throw new Error('This example needs text-only segments');
return segment.text;
}).join('');
console.log(text);Le premier test utilise un identifiant de texte fixe. Ne confondez pas une traduction vide avec une traduction absente : une traduction vide, présente et valide peut rester vide.
2 · Démarrer, poursuivre et terminer une conversation
Le joueur parle à Mira. Votre jeu choisit l’entrée correspondante dans story-index.json, ouvre sa boîte de dialogue et résout le premier nœud de cette entrée. Suivez les références, jamais l’ordre des propriétés du JSON.
const entryRef = '5e6b2e12-1ac1-4c46-8221-1a051e87370a';
const entry = story.execution.entries[entryRef];
const node = story.execution.nodes[entry.nodeRef];
console.log(node.kind, node.text.textRef);
// Read this dialogue's text; wait for the player's Continue action.
// node.continuation describes the next step, not the next array element.Après Continue, suivez continuation. kind: node utilise nodeRef pour désigner le nœud suivant ; kind: end termine la conversation. Un nœud dont kind vaut end produit le même effet. Le jeu ferme alors la boîte de dialogue et rétablit les commandes. VNLE ne quitte pas l’application et ne termine pas automatiquement le niveau.
{
"continuation": {
"kind": "node",
"nodeRef": "7c804744-b002-4136-9a7c-703fcf2d0880"
},
"flowRef": "1f69a7b6-1bdc-4dff-b8ee-9b2819b35168",
"id": "d789af84-d51d-4b97-b564-86a6756e2f2e",
"kind": "dialogue",
"speakerRef": "807b2957-7bab-4a28-83a4-1f3d1589bbc2",
"text": {
"bindings": {},
"textRef": "cbe1a637-991f-4857-81d1-6cc053d68927"
}
}Dans cet extrait, « Maybe later » mène au nœud End. La salutation de l’exemple mène d’abord à Call Substory. Un script limité aux dialogues et à End doit s’arrêter à cet endroit avec une explication tant que Call/Return n’est pas pris en charge.
3 · Proposer des réponses
Mira propose « Buy the key (5 gold) » et « Maybe later ». optionOrder définit leur ordre ; options contient leurs données. Chaque bouton conserve l’identifiant de son option. Au clic, appliquez uniquement les effets et la suite de la réponse choisie.
// Read this exact choice from the Harbour story. No condition on these two options.
const choice = story.execution.nodes['42edfff8-b8fe-46bf-ae0d-9e2347b6e726'];
for (const optionId of choice.optionOrder) {
const option = choice.options[optionId];
console.log(optionId, option.text.textRef, option.continuation);
}
// Each answer button must retain its optionId.
// On click: check availability, apply that option's effects once,
// then follow that option's continuation.Si option.condition est présent, il détermine si la réponse est proposée. À cet endroit, l’export du port comporte deux réponses sans condition propre ; la vérification de l’or se trouve dans le nœud branch suivant. Si aucune réponse n’est disponible, suivez whenEmpty : une suite définie ou une erreur expliquée.
4 · Vérifier des conditions et modifier des valeurs
Avec dix pièces d’or, le joueur peut acheter la clé ; avec deux, il ne le peut pas. La condition figure déjà dans le JSON. Le jeu fournit la quantité d’or actuelle. Cet extrait montre la comparaison gte ; les autres opérateurs et les conditions imbriquées sont décrits dans la référence du déroulement.
// This excerpt evaluates the Harbour purchase check: Gold >= 5.
const branch = story.execution.nodes['c1c3c372-0a73-4cd0-851d-ede59d5709bb'];
const condition = branch.condition;
const gold = 10; // Supply the current value from your game's saved state.
const minimum = condition.right.value.value; // 5, from the exported typed literal.
const continuation = gold >= minimum ? branch.whenTrue : branch.whenFalse;
console.log(story.execution.nodes[continuation.nodeRef].kind);
// Repeat with gold = 2: the next node is a dialogue explaining the price.
// The full condition grammar is documented in Flow rules.Champs JSON réels de la condition et de la modification
{
"condition": {
"kind": "compare",
"left": {
"kind": "variable",
"variableRef": "a547610e-661f-4b8d-a25b-21d042f1a2d5"
},
"operator": "gte",
"right": {
"kind": "literal",
"value": {
"type": "integer",
"value": 5
}
}
},
"flowRef": "1f69a7b6-1bdc-4dff-b8ee-9b2819b35168",
"id": "c1c3c372-0a73-4cd0-851d-ede59d5709bb",
"kind": "branch",
"whenFalse": {
"kind": "node",
"nodeRef": "eaffd4b0-397d-40b7-abc6-404a0a801e0e"
},
"whenTrue": {
"kind": "node",
"nodeRef": "242b2fd4-8101-4a7f-9306-17b789508bdc"
}
}{
"continuation": {
"kind": "node",
"nodeRef": "500c28a1-ed85-4c36-9a38-bedacce1c6b7"
},
"effects": [
{
"kind": "subtract",
"value": {
"kind": "literal",
"value": {
"type": "integer",
"value": 5
}
},
"variableRef": "a547610e-661f-4b8d-a25b-21d042f1a2d5"
},
{
"kind": "set",
"value": {
"kind": "literal",
"value": {
"type": "boolean",
"value": true
}
},
"variableRef": "76407a53-5ce1-408e-a8c6-a31c10f69ca5"
}
],
"flowRef": "1f69a7b6-1bdc-4dff-b8ee-9b2819b35168",
"id": "242b2fd4-8101-4a7f-9306-17b789508bdc",
"kind": "action"
}Change Variable est exporté sous forme d’action avec des effects. Ici, il retire cinq pièces d’or et passe QuestAccepted à true. Initialisez les variables depuis execution.variables uniquement pour un nouveau contexte de jeu ; charger une sauvegarde restaure les valeurs enregistrées. Si l’or existe aussi dans l’inventaire, définissez une seule source de vérité et coordonnez les mises à jour.
5 · Changer de langue
L’export complet conserve les traductions dans content.translations. Il ne nécessite pas de charger un fichier JSON distinct pour chaque langue. Utilisez content.translations[locale][textRef].message s’il existe, sinon content.texts[textRef].sourceMessage. Récupérez locale dans les paramètres du jeu.
Lors d’un changement de langue, résolvez à nouveau le dialogue courant, le nom du personnage et les réponses proposées. Conservez la position, les réponses choisies et les variables. Ne réexécutez ni les commandes ni les modifications de variables. Réutilisez les valeurs des paramètres de substitution capturées à l’affichage de la réplique actuelle.
Paramètres de substitution : « Il vous reste 5 pièces d’or » · Maintenez les traductions dans VNLE
6 · Nom, dialogue et portrait dans une barre de dialogue
- Texte du dialogue : résolvez node.text.textRef.
- Personnage qui parle : recherchez content.characters[node.speakerRef] et traduisez nameTextRef. Sans speakerRef, le texte peut être une narration sans personnage.
- Portrait dans l’export complet : utilisez celui de l’émotion demandée s’il existe, sinon defaultPortraitRef. Chargez content.assets[assetRef].relativePath depuis le dossier contenant story.json. Le JSON contient le chemin, pas les octets de l’image PNG.
- Réponses : créez un bouton par identifiant d’option disponible. Pour un dialogue simple, proposez Continue.
- À End, fermez toute la barre de dialogue, désactivez les boutons de réponse et rétablissez les commandes du joueur si nécessaire.
Si vous utilisez vos propres images dans le moteur ou si l’export ne contient pas d’association de portraits, définissez cette association dans le jeu. Le lien identifiant de personnage → ressource image reste stable après un changement de nom ou de langue. Pour les émotions, incluez leur identifiant.
// The game owns this mapping. These are real Harbour character IDs.
const portraits = {
'807b2957-7bab-4a28-83a4-1f3d1589bbc2': 'assets/portraits/mira.png'
};
const node = story.execution.nodes['ffa7141b-97ed-44c1-a346-8bba7e26d94f'];
const file = portraits[node.speakerRef];
// Load file using your engine's image loader; show a placeholder if absent.
// Optional emotion variants: portraits[characterId][emotionId].
// Do not index by the translated character name.Les pages des moteurs illustrent ces associations avec des textures, sprites ou images d’atlas importés. L’export VNLE ne sélectionne pas les images selon la langue. Si une image manque, retirez le portrait précédent et affichez éventuellement une image de remplacement.
Flux avancé au besoin
Saut · Appeler une sous-histoire / Revenir · Commande · Sauvegardes et cas d’erreur
La personne qui écrit le récit en définit le déroulement. Le développeur implémente une fois le fonctionnement des nœuds et relie les commandes convenues au jeu. Les modifications ultérieures de l’histoire suivent ensuite leurs connexions exportées.