Dendry est un moteur de jeux à choix, basé sur le principe des narramiettes. Il a été développé par Ian Millington entre 2014 et 2015 puis repris par Autumn Chen en 2020, qui l’a utilisé pour créer de nombreux jeux très bien reçus du public et de la critique. Il s’inspire fortement de Varytale un moteur de fiction interactive commercial maintenant disparu.
Ce tutoriel va vous apprendre à créer un jeu très simple basé sur les narramiettes. Histoire de vous donner une idée de là où nous allons, le jeu final est jouable à l’adresse suivante https://smwhr.github.io/dendry-tutorial/
Mise en place du projet (10min)
Si vous êtes un expert de JavaScript et que vous voulez créer un jeu Dendry en local, des instructions existent en anglais : Full project setup
Pour les autres, il existe un “starter pack”, un projet déjà tout fait à dupliquer, que vous pouvez utiliser en ligne, tout ce qu’il vous faut, c’est un compte GitHub. Pour la suite, vous devez être identifié sur GitHub.
La première chose à faire est de dupliquer le projet (repository). Rendez-vous sur
https://github.com/smwhr/dendry-starter-pack/
puis cliquez, en haut à droite, sur
et choisissez “create a new repository”.
Donnez lui un nom (par exemple ile-au-tresor
)
Seconde étape, activer la page github qui hébergera le jeu terminé.
Dans les Settings, partie Pages, section Build and deployment choisissez “GitHub Actions”.
(ne choisissez aucun des choix proposés en dessous, le projet contient déjà une Action prédéfinie)
Pour modifier les fichiers, pas besoin de logiciel, GitHub fourni tout ! Depuis l’onglet “Code” appuyez simplement sur la touche .
de votre clavier : l’éditeur se lance !
Le premier fichier à modifier est info.dry
: changez le nom du projet et l’auteur par le vôtre
# info.dry title: Ile au Trésor author: Super Auteur ifid: 12345ABC-67DE-F8A9-B01C-234567890CDE
Pour sauvegarder les fichiers modifiés, rendez-vous sur l’icône de gestion des versions
et, après avoir renseigné un message (il est obligatoire et permet d’historiser les changements, mais vous n’êtes pas obligé de vous torturer si vous ne trouvez rien à dire, un bête “ok” suffit), cliquez sur “Commit & Push”
À chaque sauvegarde (commit), le jeu va être automatiquement compilé et republié à l’adresse https://VOTREUSERNAME.github.io/NOM-DU-PROJET
Vous pouvez suivre l’avancement de ceci dans l’onglet Actions sur la page GitHub (pas dans l’éditeur)(cela prend en général un peu moins d’une minute)
C’est également à cet endroit qu’apparaîtront les rapports d’éventuelles erreurs dans le code que vous avez écrit.
Premier concept : une scène et quelques choix (15min)
Le premier concept important dans un projet Dendry est celui de scene
.
Concrètement, une scène, est un fichier nommé nom_de_la_scene.scene.dry
. Il faut l’envisager comme une brique de contenu du jeu (on peut facilement l’assimiler à un passage dans twine, ou a un noeud en ink). Le nom du fichier sert d’identifiant à la scène, on évitera donc les espaces, accents et caractères spéciaux.
Dans sa plus simple expression, une scène possède un titre (title
) et du contenu.
# root.scene.dry title: Bienvenue sur l'Île au Trésor new-page: true Une île mystérieuse, bordée de falaises abruptes, de plages de sable et d'une mer turquoise. Des maisons de bois bordent le rivage, ornées de drapeaux multicolores. C'est ici que se retrouvent pirates et chasseurs de trésor pour échanger leurs histoires et trouvailles à propos d'un fabuleur trésor.
Le fichier root.scene.dry
est le point d’entrée du jeu, il est obligatoire. Le mot-clé new-page
signifie, lorsqu’il est renseigné à true
(vrai), que le contenu précédent sera effacé pour afficher le nouveau passage. Dans le cas contraire, le contenu est simplement rajouté à la suite.
Publiez le jeu, vous verrez le nouveau passage apparaître suivi du message suivant :
Si vous utilisez les GitHub Pages, vos changements peuvent ne pas apparaître immédiatement, même si l’Action s’est terminée, il est alors nécessaire de recharger la page avec un hard refresh. Comment faire un hard refresh ?
Et pour cause, il n’y a nulle part où aller depuis cette première scène d’intro ! Créons une seconde scène, la Capitainerie.
# capitainerie.scene.dry title: Capitainerie new-page: true La Capitainerie est une petite hutte en bois installée sur le rivage, là où les bateaux vont et viennent. D'apparence simple, son toit est en tôle ondulée. À l'intérieur, vous trouvez une grande table sur laquelle une carte de l'île est déroulée.
Il s’agit maintenant de dire à Dendry que la Capitainerie est accessible depuis la scène d’intro.
Pour cela, nous allons rajouter un choix à la suite du contenu de la scène d’intro.
# root.scene.dry leurs histoires et trouvailles à propos d'un fabuleur trésor. # les choix - @capitainerie: Visiter la capitainerie
Les lignes commençant par un #
sont des commentaires et seront ignorées au moment de l’affichage du jeu.
Le choix “Continue…” a été automatiquement rajouté par Dendry parce que la scène d’intro est toujours accessible (on verra ce que cela signifie plus tard) et qu’il n’y a aucun autre choix possible. Si vous voulez faire de la Capitainerie une impasse, il suffit d’ajouter la métadonnée game-over: true
en haut de la scène de la Capitainerie.
Collecter plusieurs choix : tags et conditions (15min)
Imaginons que nous ayons plusieurs destinations où nous rendre depuis la place principale de l’île. La manière la plus évidente d’exprimer cela pourrait être de simplement ajouter des choix les uns à la suite des autres, manuellement.
- @chantier_naval: Visiter le chantier naval - @taverne: Visiter la taverne - @marche: Visiter le marché
Mais plus la liste s’allonge, plus cela devient fastidieux. Pire, si il nous prend de vouloir faire en sorte que tous ces lieux soient accessibles les uns des autres, on se retrouve à copier plusieurs fois cette liste et bonne chance pour ne pas oublier un choix ici ou là !
Heureusement, nous avons pour ça des tags
.
Les tags sont une manière de catégoriser les scènes, et Dendry est construit sur un système astucieux qui lui permet de retrouver tous les éléments qui seraient taggés d’une certaine manière.
Ajoutons des tags dans la scène de la Capitainerie.
# capitainerie.scene.dry title: Capitainerie new-page: true tags: port
Informons la scène d’intro qu’elle a besoin de collecter toutes les scènes qui ont un tag port
et de les présenter sous forme de choix (vous pouvez supprimer le choix précédent)
# root.scene.dry leurs histoires et trouvailles à propos d'un fabuleur trésor. - #port
Profitez en pour rajouter quelques autres destinations !
Publions et voyons ce que ça donne :
Parfait ! Dendry a collecté toutes les scènes possédant le tag port
et a créé les choix correspondants. Les intitulés de ces choix sont les title
des scènes liées.
J’ai également ajouté une métadonnée subtitle
à la scène passage_secret.scene.dry
qui permet l’affiche d’une description supplémentaire.
OH ! MAIS ATTENDEZ ! Je ne veux pas afficher le passage secret tant que la joueuse n’a pas examiné la carte dans la Capitainerie !!!
Ajoutons une condition à la scène en question pour cacher ce choix.
# passage_secret.scene.dry title: Passage secret subtitle: Un passage secret vers la forteress tags: port view-if: connaissance_carte = "vue" Dominant l'Île, une forteresse de pierre se dresse sur les hauteurs. D'allure imprenable, décorée de drapeaux flottant au vent, on y distingue les gardes de la garnisons qui protège l'île des dangers venus de la mer.
Republions le jeu : le passage secret a maintenant disparu de la liste des choix. Tant mieux ! La variable connaissance_carte
s’appelle, dans Dendry, une quality
(qualité). Les qualités peuvent être des nombres, des textes ou des valeurs booléennes (true
, false
)
Par défaut une qualité vaut “0”, nous allons donc la passer à “vue” lorsque la joueuse examine la carte dans la Capitainerie :
# capitainerie.scene.dry title: Capitainerie new-page: true tags: port La Capitainerie est une petite hutte en bois installée sur le rivage, là où les bateaux vont et viennent. D'apparence simple, son toit est en tôle ondulée. À l'intérieur, vous trouvez une grande table sur laquelle une carte de l'île est déroulée. -@examiner_carte: Examiner la carte @examiner_carte view-if: connaissance_carte != "vue" on-arrival: connaissance_carte = "vue" C'est une carte du port et de ses environs. Vous remarquez qu'un **passage secret** est indiqué qui mène directement à **la forteresse** !
Examinons un peu le code que je viens de rajouter. J’ai créé une sous-scène dans la capitainerie
que j’ai appelée examiner_carte
. Les noms des sous-scènes commencent par un @
.
Ensuite, j’ai rajouté un choix à la fin du contenu principal.
La sous-scène possède deux métadonnées :
view-if
pour l’empêcher d’être disponible si vous avez déjà examiné la carteon-arrival
définit l’instruction à déclencher lorsque l’on affiche une scène (une instruction similaireon-departure
se déclenche au moment où l’on quitte une scène, et dans le cas qui nous occupe, on aurait pu mettre l’une ou l’autre, ce n’est pas important)
Désormais, lorsque vous retournez sur la place principale après avoir examiné la carte dans la Capitainerie, le choix de suivre le passage secret devient disponible !
Ajoutons une dernière subtilité : un choix peut être visible sans pour autant être disponible. Dans la description au moment de l’examen de la carte, ajoutons l’indice qu’il faudra une clé pour y accéder.
# capitainerie.scene.dry C'est une carte du port et de ses environs. Vous remarquez qu'un **passage secret** est indiqué qui mène directement à **la forteresse** ! Le symbole d'une **clé** est dessiné juste à côté du passage.
Une syntaxe simplifiée permet d’ajouter du formattage simple aux textes :
*en italique*
en italique**en gras**
en gras> indentation
= titre
Il ne nous reste plus qu’à rajouter quelques métadonnées dans la scène passage_secret.scene.dry
:
# passage_secret.scene.dry title: Passage secret subtitle: Un passage secret vers la forteress tags: port view-if: connaissance_carte = "vue" **choose-if: possede_cle = true unavailable-subtitle: Vous n'avez pas la clé nécessaire pour y accéder**
Désormais, le choix est grisé lorsque vous revenez sur la place principale :
Les qualités et leur affichage (20min)
Une qualité est grosso modo une variable.
Si vous essayez d’utiliser une qualité que vous n’avez pas préalablement définie, elle est initialisée à 0.
Pour définir une qualité au démarrage du jeu, il est possible de la définir dans un fichier nommé ma_qualite.quality.dry
# age_du_capitaine.quality.dry name: age_du_capitaine initial: 54
Une bonne pratique consiste à regrouper les scènes dans un dossier scenes
et les qualités dans un dossier qualities
mais ce n’est en aucun cas obligatoire. Si votre jeu a de plus en plus de scènes et de qualité, ou si plusieurs auteurs collaborent, il peut être opportun de choisir une structure plus adéquate.
Les qualités sont très pratiques pour suivre l’évolution d’une valeur numérique.
Nous allons essayer avec la faim
de notre personnage.
name: faim initial: 3 min: 0 max: 5
Au départ du jeu, le personnage débarque sur l’île avec un niveau de faim de 3. Vous ne pouvez jamais dépasser 5. Après un bon repas, vous serez à 1 et si vous reprenez du dessert, vous atteindrez 0.
On peut afficher ce niveau de faim lorsque la joueuse visite la Taverne.
# taverne.scene.dry title: Taverne new-page: true tags: port La Taverne de l'Île au Trésor est un endroit où les pirates peuvent se retrouver pour manger, boire un coup et discuter. C'est aussi un lieu de rencontre pour les pirates qui cherchent à recruter de nouveaux membres pour leur équipage. Votre niveau de faim est de [+ faim +].
Définissons maintenant deux sous-scènes pour montrer ce que le personnage peut accomplir :
@manger
pour diminuer le niveau de faim@insulter
qui augmente le niveau de faim après avoir déclenché une bagarre dans la taverne
# taverne.scene.dry recruter de nouveaux membres pour leur équipage. Votre niveau de faim est de [+ faim +]. - @manger : Manger un bout - @insulter : Insulter un pirate @manger new-page: false choose-if: faim > 0 unavailable-subtitle: Vous n'avez pas faim on-departure: faim -= 1 go-to: @fin-activite Vous mangez un bout, ça vous cale un peu. @insulter new-page: false choose-if: faim < 5 unavailable-subtitle: Vous avez trop faim pour ça on-departure: faim += 1 go-to: @fin-activite Vous insultez un pirate au hasard. Cette bagarre vous a donné un peu faim. @fin-activite - @taverne : Continue...
Cet exemple est volontairement un peu touffu pour montrer plusieurs possibilités offertes par Dendry
- Les sous-scènes peuvent avoir une métadonnée
new-page: false
(on a déjà vu ce comportement lorsque l’on examine la clé dans la capitainerie) - Les scènes (et sous-scènes) peuvent avoir une métadonnée
go-to: @nom_scene
: Dendry va alors afficher le contenu textuel de la scène puis ignorer tous les choix avant de rediriger vers la scène spécifiée. Cego-to
peut être conditionné par une condition sur une qualité, par exemple@scene_a if ma_quality > une_autre_qualite
: si la condition échoue, la scène se comporte comme d’habitude. - Les opérateurs
+= n
(augmenter de n) et-= n
(diminuer de n) sont disponibles.
Afficher le niveau de faim sous forme numérique n’est pas très satisfaisant, après tout, nous sommes des auteurs de jeux textuels et nos joueuses espèrent mieux de nous que des chiffres balancés tous nus ! Entrent en jeu les qdisplay (quality display = afficheur de qualité). Il s’agit du dernier type de fichier possible, de la forme nom_du_display.qdisplay.dry
.
# niveau_faim (-1..0) : écœuré (0..1) : repu (1..2) : en appétit (2..3) : affamé (3..4) : en inanition (4..5) : prêt à tout pour de la nourriture
En raison d’un bug, les fichiers de qdisplay doivent commencer par une ligne vide (ici entre le commentaire et la liste)
Il ne reste plus qu’à modifier la scène de la Taverne :
Dans taverne.scene.dry
Remplacez :
Votre niveau de faim est de [+ faim +].
Par :
Vous êtes [+ faim : niveau_faim +].
Quelques sources publiques de jeux
Les jeux publiés le sont pour le moment uniquement en anglais. Mais peut-être bientôt le vôtre ?
- Bee, écrit par Emily Short, porté vers Dendry par Autumn Chen
- Jeux écrits par Autumn Chen
Pour en savoir plus
- Les narramiettes dans Twine par Hugo Labrande
- Beyond Branching: Quality-Based, Salience-Based, and Waypoint Narrative Structures par Emily Short
- Writing for Varytale par Emily Short
- New Year’s Eve 2019 : The Postmortem par Autumn Chen
30 septembre 2023 at 11 h 29
Super article.
J’ai deux petites questions :
Comment est déterminé l’ordre d’affichage des choix quand on utilise un tag ?
Est-ce qu’il est possible de limiter le nombre de choix à afficher ?
3 octobre 2023 at 10 h 05
Super article !
L’auteur original Ian Millington semble avoir repris un peu de la terminologie et des concepts de son vieux moteur Undum (les qualités, les conditions…).
28 août 2024 at 17 h 55
Une question : est-il possible de rendre dynamique la propriété « title » d’une scène selon certaines conditions ?