Encore un outil de fiction interactive ? Pour quoi faire ?
Quand il s’agit de choisir son outil pour développer des fictions interactives, on n’a que l’embarras du choix : inklewriter, Twine, Inform, Moiki, Donjon.fi… On peut aussi préférer travailler dans un moteur généraliste et écrire ses dialogues à l’aide d’un plugin dédié, voire faire sa planification dans un outil professionnel spécialisé qui prend en charge variables, objets, personnages et les 8563 fins possibles de votre magnum opus ! Mais si on a juste envie de manipuler facilement des éléments graphiques pour illustrer ses écrits, vers quoi peut-on se tourner ?
Et bien il y a par exemple Narrat, une solution équilibrée se présentant sous la forme d’un petit moteur open-source inspiré par Disco Elysium, qui se veut…
- léger : on oublie le gameplay temps réel au profit d’illustrations et de sprites simples
- centré sur les technologies web : outre la possibilité d’exporter son jeu en version web pour itch.io par exemple, HTML CSS et JS permettent nativement de personnaliser l’aspect de son jeu et d’enrichir ses mécaniques
- modulable : on peut sélectivement ignorer les systèmes pré-embarqués selon notre vision…
- extensible : …ou créer les nôtres ! Le langage de scripting est de prime abord très linéaire et semble peu ou prou limité à ce que permettent un ink ou un yarnspinner, mais un peu d’expérience vous fera voir le côté “programmation orientée objet” qui se cache sous la surface. On peut même coder ses propres plugins pour soulever le capot du moteur (wink wink) selon notre bagage technique !
OK, je me lance. Mais… il est où, l’éditeur visuel ?
Narrat est un programme sans interface graphique ; cela veut dire qu’il faut l’installer avec une ligne de commande puis écrire son jeu avec un éditeur comme Visual Studio Code. Si vous avez eu l’occasion d’utiliser Tweego pour écrire vos jeux Twine, il s’agit du même principe.
Installation
- Installer Node.js
- Sélectionner un dossier pour votre futur jeu
- Ouvrir un terminal dans ce dossier (clic droit dans ce dernier si vous êtes sous windows), puis entrer la commande
npm create narrat@latest
- Suivre les instructions (pour les besoins de ce tutoriel, nous allons créer une copie du jeu de démo, plutôt que lancer un projet de zéro)
- Ouvrir le dossier dans l’éditeur de code de votre choix (ici, Visual Studio Code)
- (Optionnel mais recommandé) installer l’extension Narrat Language qui améliorera la lisibilité de vos scripts grâce à sa coloration syntaxique.
Les bases du développement sous Narrat
Narrat permet de tester le jeu en cours de développement via un serveur local : il vous suffit d’entrer npm start
dans le terminal pour que ce dernier soit lancé, puis d’appuyer sur o
pour l’ouvrir dans un onglet de navigateur. Celui-ci appliquera en temps réel vos changements, et vous donnera accès à un petit menu spécial de débogage pour inspecter vos variables, lancer des événements spécifiques à volonté, etc.
Maintenant que tout est en place, comprenons bien comment fonctionne l’architecture interne d’un jeu Narrat, et quels sont les fichiers qui vont se révéler importants.
- Les fichiers de scripts sont ceux qui contiennent la narration et la logique de votre jeu. Ils sont douillettement blottis dans le dossier
/src/scripts
; pour les besoins de notre tutoriel, celui qui va nous intéresser (vous pouvez en créer d’autres selon vos besoins) estdemo.narrat
. Celui-ci est importé par le moteur via le fichierindex.ts
. - Vos assets graphiques et musicaux se trouvent par défaut dans le dossier
public
. Vous y trouverez des sous-répertoires pour vos musiques et sons d’interface, vos polices d’écriture personnalisées et vos images. Notez qu’il est tout à fait possible de revoir cette organisation à votre convenance ; il suffira simplement de spécifier le chemin correct d’accès aux fichiers que vous utiliserez. - Enfin, les fichiers de configuration sont regroupés dans
/src/config
. Ils se terminent par l’extensionyaml
. C’est là que sont déclarés les assets (avoir un fichier ne suffit pas, il faut lui assigner un nom pour pouvoir l’utiliser, ainsi que certaines options spécifiques) ; c’est également dans ce dossier que sont paramétrés un certain nombre d’éléments abstraits utiles tout au long du jeu comme les items, les personnages, les quêtes et les tests de compétences. Pas d’inquiétude, rien ne vous oblige à utiliser ces fonctionnalités si vous ne le souhaitez pas, même si elles sont paramétrées dans votre dossier d’installation !common.yaml
est un fichier particulièrement important qui regroupe tout un ensemble de paramètres généraux liés à la présentation de votre jeu : est-ce que le panneau de texte doit se superposer aux assets utilisés comme fond d’écran ou y être accolé, est-ce que les caractères de vos paragraphes doivent apparaître les uns après les autres ou tous en même temps, quelles sont les dimensions des portraits de vos personnages… Vous verrez que les intitulés de ces réglages sont plutôt explicites.
Pour l’instant, prenons le fichier demo.narrat
évoqué plus haut et supprimons-en tout le contenu pour y voir plus clair.
Comme Tweego qui exige que soient déclarés les passages via une syntaxe spéciale, Narrat s’attend à lire des labels dénotés par une suite de caractères sans espace suivis par deux points. Le premier d’entre eux doit être main:

Le contenu d’un label doit être indenté à l’aide d’une tabulation. De façon générale, du contenu des choix aux instructions exécutées seulement si une condition est vérifiée, l’indentation est reine pour déterminer la hiérarchie dans votre script.
Affichons donc un simple texte pour commencer ; la commande "Ceci est un texte narré."
, entre guillemets, affiche du texte sans que celui-ci soit énoncé par un personnage en particulier. Il s’agit en réalité d’un raccourci pour la commande complète narrate "Ceci est un texte narré"
, qui est, vous le devinez, dédiée aux descriptions.

Et dans notre navigateur :

Notez au passage qu’en utilisant la configuration du jeu de démo, le fond d’écran default
, un rideau rouge, est utilisé, et que des hud stats
sont affichées en haut. Par ailleurs, le panneau de texte est en mode superposition (contrairement par exemple à Disco Elysium, dans lequel il est en permanence visible à droite de l’écran de gameplay).
Bon ; c’est bien beau tout ça, mais notre scène manque de vie. Servons-nous donc de nos personnages pour écrire un dialogue.
Dans characters.yaml
, on trouve un certain nombre de personnages déjà définis avec leurs sprites et des attributs CSS relatifs à leurs répliques respectives. Le premier d’entre eux est game
, qui désigne le texte des descriptions. Inutile de réinventer la roue, contentons-nous de changer les noms des personnages player
et cat
:

Et retournons dans demo.narrat
pour écrire :

La commande talk
requiert au moins trois arguments : le nom du personnage qui parle, la pose utilisée (pour savoir quel sprite afficher), et le texte de la réplique. On peut optionnellement y adjoindre un nombre qui désigne le nombre de millisecondes à attendre avant de servir la ligne suivante, et la mention true
ou false
pour indiquer si le joueur va devoir appuyer sur le bouton continuer pour ce faire.
Notre script a pour l’instant pour résultat :

Premiers choix
Voyons maintenant quelques autres fonctionnalités essentielles. Après tout, comment pourrais-je écrire mon chef-d’œuvre sans choix et variables dignes de ce nom ?
La commande choice
, sans grande surprise, donne au joueur l’occasion de choisir entre plusieurs options pour répondre à un intitulé. La syntaxe à utiliser est la suivante (attention aux indentations !):

La première ligne correspond à l’intitulé, les lignes suivantes sont les options cliquables par le joueur.
Problème : ces options ne mènent pour l’instant à rien, et le moteur n’aime pas ça !

Nous allons donc faire réagir le personnage secondaire, et en stockant notre choix dans une variable (par convention et lisibilité au sein de l’objet data
).


Notez que :
- sélectionner une option de choix la fait apparaître dans le flow de la conversation, comme si elle avait été prononcée à haute voix.
- la commande
set
est immédiatement suivie du chemin de la variable créée, suivie de la valeur à stocker. Inutile de spécifier le type de la variable, le moteur la reconnaît immédiatement.
La ligne jump suite
indique au moteur qu’il faut passer au label suite
, sans exécuter les instructions restantes dans le label main
. Maintenant, servons-nous de la variable data.pastry
.
Changement de fonds d’écran conditionnel

Cela fait un certain nombre de lignes supplémentaires, mais le script reste très simple : le chat nous demande simplement s’il peut afficher une image de l’option choisie pour s’assurer qu’il n’y a pas d’erreur. Si nous refusons, nous sommes directement amenés à nous dire adieu. Mais si nous acceptons, la commande run displayPastry
entre en jeu ; comme jump
, cette dernière nous fait quitter le label en cours pour en rejoindre un autre, à ceci près que run
nous ramène où nous en étions après coup. Dans cet exemple précis où le label displayPastry
n’est utilisé qu’à cette seule occasion, sans que son contenu ou les variables utilisées ne puissent être altérés, il reviendrait au même de placer les instructions qu’il contient en lieu et place de run displayPastry
. run
est très utile pour se servir de labels comme de fonctions, car on peut en imbriquer un très grand nombre si nécessaire, ce qui facilite les abstractions.
Vous aurez remarqué le conditionnel if
utilisé à deux reprises dans displayPastry
. Comme dans tout autre moteur, if
n’exécute les instructions qu’il contient si et seulement si la condition qui le suit est vérifiée. Dans Narrat, cette condition peut soit prendre la forme d’une variable booléenne, soit la forme d’une expression logique qui est vérifiée à la volée ; dans le cas présent, nous vérifions si la valeur stockée dans data.pastry
correspond aux suites de caractères “pain au chocolat” ou “chocolatine”, l’équivalence étant dénotée par l’opérateur ==
en début d’expression. Nous aurions aussi bien pu remplacer le second if
par un else
, mais c’est une question de bonne pratique que de ne pas se barrer la route à une éventuelle troisième option que nous pourrions ajouter plus tard à notre choix de viennoiserie.
En parlant de data.pastry
: un peu plus tôt, nous avons fourni à la commande set
le chemin de cette variable afin d’enregistrer notre choix, tandis que nous avons ajouté un symbole $
devant ce chemin pour accéder à sa valeur . Si vous avez des notions de programmation, pensez à data.pastry
comme étant un pointeur.
Bon, et alors, quel est le résultat produit par displayPastry
?


Le moteur a bien effectué le changement de fond d’écran initié par set_screen wow
(dont j’avais préalablement importé le fichier dans /img/backgrounds
et que j’avais déclaré dans backgrounds.yaml
), mais mon sprite de pain au chocolat est bien trop grand…
Le problème, c’est que contrairement au fond d’écran que j’ai importé à la bonne taille (celle du jeu de démo est réglé sur 1280×720, information que l’on trouve dans common.yaml
), j’ai seulement spécifié les coordonnées où afficher mon sprite.
Pour régler ce petit souci, je vais ajouter une ligne qui va ajuster la taille de mon sprite, en exploitant la propriété scale
(à la fin du label, hors des if
statements).


Une autre solution, bien sûr, aurait été de changer la taille de painAuChocolat.png
pour la réduire ; mais il aurait alors été compliqué de changer la résolution finale du jeu dans common.yaml
pour la faire passer à du 1920×1080, par exemple, sans une perte de qualité visible. Avec une image originale de grande taille, il suffit d’ajuster la propriété scale
et on en garde tous les détails.
Tout ça pour un pain au chocolat ? Je prends mes affaires et je rentre à ma maison retourne sur ink
Ce n’est que le début des possibilités du langage, mais cela pose une bonne base pour commencer ! Pour un prochain tutoriel, nous pourrions complexifier un peu notre code en nous servant de labels comme de fonctions acceptant des arguments, enregistrer nos propres commandes pour facilement exécuter en une seule ligne un grand nombre d’instructions, créer une interface de jeu rudimentaire avec des boutons lançant des labels, acquérir et utiliser des objets…
Pour creuser la question tout·e seul·e :
Et vos questions éventuelles, en commentaire ou DM trouveront évidemment une réponse rapide de ma part !
Laisser un commentaire
Vous devez vous connecter pour publier un commentaire.