Génération procédurale – Part 1

Depuis déjà un moment, je m’intéresse à la création de jeu vidéo ; une notion qui revient souvent en ce moment, et qui me semble particulièrement intéressante, est la génération procédurale. Il s’agit de créer certains éléments du jeu (la map, en ce qui me concerne), de manière automatisée, en se basant sur des mécaniques aléatoires, et sur quelques règles simples. Pause Process l’explique très bien en vidéo, donc je vous confie à ses soins et je vous encourage à voir ses autres vidéos qui sont, pour la plupart, très pédagogiques.

En particulier, j’aimerais créer un miner / base-builder avec un monde généré de manière procédurale. Si vous connaissez Dwarf Fortress, vous voyez de quoi je parle (mais dans un style bien spécifique que je ne souhaite pas imiter) ; sinon, regardez Rimworld : c’est plutôt ça l’idée. Au passage, Rimworld est un jeu très incomplet mais très prometteur que je vous encourage à essayer. Je trouve qu’il est vendu à un prix indécent pour une version Alpha, mais bon.

J’ai commencé à me renseigner, et je suis tombé sur diverses ressources intéressantes. En particulier, un générateur de donjons, dont le code est disponible en CC-BY-NC. Il est en Perl, un langage sans doute passionnant mais que je ne souhaite pas utiliser : j’aimerais faire mon truc en Python ; mais l’algo est bien expliqué. En parlant de donjons, j’ai découvert un site très complet sur les Rogue-likes et leur développement : RogueBassin. Je ne m’intéresse pas particulièrement aux Rogue-likes, mais c’est le genre qui a le plus utilisé la génération procédurale (pour ne pas dire qu’il l’a inventé – je ne voudrais pas qu’une horde de fans de Elite m’assaille de commentaires déplaisants ; ces gens là ont un ZX Spectrum comme ordinateur de bureau et sont donc particulièrement dangereux). Bref ce site, dans sa section Articles, regorge de liens et de ressources intéressantes : un must-read si vous vous intéressez à ce genre de chose.

Sérieusement, c'est pas vraiment plus moche que Minecraft.

Un Rogue-like, ça ressemble souvent à ça. Mais sinon, c’est bien quand même.

Je suis tombé en particulier sur ce tuto : Complete Roguelike Tutorial, qui est assez bien fait et qui explique l’utilisation du module libtcod. Si vous souhaitez coder un rogue-like en Python, jetez vous dessus aussi fort que vous pouvez : vous ne vous ferez pas mal. Si vous êtes juste curieux et que vous désirez découvrir quelques astuces, c’est une saine lecture.

Le premier truc à faire, est de se créer une structure qui va accueillir les données du jeu : la map, les objets, etc.

Ma première approche, naïve, était de me baser sur une classe map et de tout stocker dedans, dans un tableau à deux dimensions : le terrain, les murs, les objets, le joueur etc. J’ai passé un certain temps à créer une classe map qui soit un tableau à deux dimensions, et surtout qui soit itérable. Je pouvais donc faire : for case in map:. Fantastique ! L’idée était de me servir de cette classe map, pour définir plusieurs couches : une pour les éléments de la map (les murs, le sol etc), une pour les objets, une pour les monstres etc. Chaque case aurait été une liste qui contient tous ces éléments.

wgen1

La Class Américaine

J’ai également tenté d’utiliser le format TMX : une structure qui va bien avec le logiciel Tiled Map Editor. En gros l’idée est de se baser sur un format standardisé (le tmx donc), spécialement adapté aux maps tilées, et qui contient sous forme de xml des layers, chacun contenant des cases, chacune faisant référence à une case d’une un tileset. Intéressant donc, mais un peu trop compliqué pour mon usage : comme je souhaite générer la map de manière procédurale, je n’ai aucun besoin d’aller la lire dans un fichier. Au mieux, je peux me baser sur cette structure, qui a l’avantage d’être standardisée. Pour info, on trouve plusieurs libs pour l’utiliser de manière efficace ; la difficulté étant d’en trouver une qui ne dépende pas lourdement de pygame ; la plus sympa à mon sens étant python-tmx : j’ai pu coder rapidement un petit programme qui importe une map tmx et remplace chaque tile par un objet 3D dans Blender.

tmx

Un tel niveau de sophistication impose le respect ! Et pourtant, ça tourne.

Il m’a fallu quelques essais, et quelques lectures, pour me rendre compte que ces modèles n’était pas efficaces. En effet, est-ce qu’il arrive souvent d’itérer à travers toutes les cases de la map ? Pas vraiment. En revanche, on itère souvent à travers tous les objets qu’elle contient : il me fallait donc une liste des objets (une liste au sens Pyton : maListe = [unObjet, unAutreObjet]), chaque objet embarquant ses coordonnées en x et y ; et un bête tableau représentant la map (un simple tableau à deux dimensions. Ainsi map[x][y] nous renverra le contenu de la case x,y).

J’ai donc besoin de :

  • une classe objet
  • une classe case
  • une liste de chaque objet
  • un tableau à deux dimensions contenant chaque case

Y’a plus qu’à faire ! Promis, dans l’article suivant il y aura un peu de Python. En attendant, je vous invite à lire le blog d’un type qui génère procéduralement des donjons depuis plus de douze ans. Dans le pire des cas, vous penserez que vos skills en algo sont bien peu de choses ; dans le meilleur des cas, vous découvrirez qu’en comparaison, votre vie est passionnante.

Et si comme moi vous avez l’esprit tordu, vous vous demanderez quel développeur perché a conçu l’algo de votre existence ; et comment on a pu y laisser autant de bugs.

2 réflexions au sujet de « Génération procédurale – Part 1 »

  1. Ping : Génération procédurale – Part 1.1 | thibsert

  2. Ping : Novos | thibsert

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *


Time limit is exhausted. Please reload CAPTCHA.