URL: https://linuxfr.org/news/je-cree-mon-jeu-video-e12-interfaces-physiques-et-graphiques Title: Je crée mon jeu vidéo E12 : interfaces physiques et graphiques Authors: rewind ZeroHeure, Benoît Sibaud, bubar🦥 et Nÿco Date: 2014年08月20日T15:53:44+02:00 License: CC By-SA Tags: gamedev et jeux_linux Score: 52 «Je crée mon jeu vidéo» est une série d'articles sur la création d'un jeu vidéo, depuis la feuille blanche jusqu'au résultat final. On y parlera de tout : de la technique, du contenu, de la joie de voir bouger des sprites, de la lassitude du développement solitaire, etc. Vous pourrez suivre cette série grâce au [tag gamedev](http://linuxfr.org/tags/gamedev/public). Dans l'[épisode 11](http://linuxfr.org/news/je-cree-mon-jeu-video-e11-generation-procedurale-de-carte-partie-2), on a décoré notre carte, et même si elle n'est pas encore dans un état jouable, elle constitue une bonne base pour la suite. Pour ce retour de vacances, on va s'intéresser aux interfaces physiques et graphiques du jeu. ---- [Akagoria, la revanche de Kalista](http://www.akagoria.org/) [Le tag gamedev](http://linuxfr.org/tags/gamedev/public) [jnuit, simple GUI toolkit for LWJGL or PlayN videogames](https://github.com/devnewton/jnuit) [SUIT, SFML User Interface Toolkit](https://github.com/jube/libsuit) ---- # Introduction Contrairement à ce que j'avais espéré, les vacances n'ont pas été très productives pour mon jeu. Je comptais passer du temps dessus de manière à avoir des avancées significatives, mais il n'en a rien été. J'ai seulement pu faire quelques tests dont je parlerai sans doute dans un prochain épisode. C'est très frustrant ce genre de situation. Ça ne m'empêche pas de continuer mes réflexions (et mes bouts de code) et de les partager. Aujourd'hui on va discuter des interfaces : - les interfaces physiques, celles qui permettent de commander les actions dans le jeu (_input_), - et les interfaces graphiques, celles qui rendent compte d'élements du jeu (_output_). Et comme [d'autres y ont réfléchi avant moi](http://devnewton.bci.im/fr/node/89), je me suis largement inspiré de `jnuit`, créé par [devnewton](http://linuxfr.org/users/devnewton) pour ses jeux en Java. # Les interfaces physiques À la base, je ne savais pas trop quoi utiliser pour l'interface physique. Quand on pense RPG, on imagine que ça se manipule à la souris et/ou au clavier. Mais avec les RPG sortis sur console, ce n'est plus le cas. Et puis bon, il y a [devnewton qui veut jouer à la manette](http://linuxfr.org/news/je-cree-mon-jeu-video-e02-le-jeu-et-ses-challenges#comment-1488142). Du coup, allons-y, essayons de contenter tout le monde. SFML gère les principales interfaces physiques rencontrées dans la nature : clavier, souris, manettes. Donc, de ce côté là, on n'aura pas trop de problème. Le seul problème est de trouver un moyen de gérer tous ces périphériques de manière à peu près commune et de s'éviter [de longs `switch` redondants et désagréables](http://sfml-dev.org/tutorials/2.1/window-events.php), c'est-à-dire trouver le bon niveau d'abstraction. Pour les interfaces physiques, on trouve deux notions dans `jnuit` que j'ai reprises. Celle de [contrôleur](https://github.com/devnewton/jnuit/blob/master/core/src/main/java/im/bci/jnuit/controls/Control.java) et celle d'[action](https://github.com/devnewton/jnuit/blob/master/core/src/main/java/im/bci/jnuit/controls/Action.java). ## Contrôleur Un contrôleur, c'est juste l'abstraction d'une interface physique. Dans `jnuit`, le contrôleur fournit une valeur qui indique son état. Le contrôleur est alors couplé à un [détecteur](https://github.com/devnewton/jnuit/blob/master/core/src/main/java/im/bci/jnuit/controls/ControlActivatedDetector.java) qui va superviser cet état et dire si le contrôleur est actif ou pas. L'inconvénient (à mon sens) dans `jnuit` est qu'on est en mode _polling_, c'est-à-dire qu'on va demander l'état du contrôleur à chaque tour (par exemple : « est-ce que le bouton droit de la souris est appuyé ? »). L'autre mode, c'est le mode événement, c'est-à-dire qu'on regarde les événements qui se sont produits (comme par exemple un appui sur un bouton de souris) et on enregistre le nouvel état à ce moment là. J'ai une nette préférence pour le mode événement que je trouve plus naturel, mais c'est une question de goût. SFML n'est pas casse-pied et propose les deux modes de toute façon. L'autre chose qui me chagrinait dans l'approche de `jnuit`, c'est cette distinction entre le contrôleur et son détecteur. La différence est très subtile mais trop subtile pour moi, alors j'ai fusionné les deux notions dans une seule : un contrôleur dit s'il est actif ou pas. Et il met à jour son état en scrutant les événements renvoyés par SFML. ## Action Une action est une abstraction d'une... action qui peut être déclenchée par le joueur -- par exemple « sauter ». Une action est provoquée par un ou plusieurs contrôleurs (comme le bouton droit de la souris ou la lettre `J` du clavier). Comme pour les contrôleurs, il existe aussi un [détecteur](https://github.com/devnewton/jnuit/blob/master/core/src/main/java/im/bci/jnuit/controls/ActionActivatedDetector.java) qui va se charger de vérifier si l'action est active ou pas, suivant l'état des contrôleurs associés. La règle est simple, il suffit d'un seul contrôleur activé pour activer l'action. Outre le fait que la différence entre l'action et son détecteur soit une fois de plus trop subtile pour moi, j'ai trouvé qu'il manquait un élément important dans cette abstraction. En effet, une action peut être continue ou pas. Prenons deux exemples pour voir la différence. Quand j'appuie sur une flèche, je souhaite que mon personnage avance tant que j'appuie sur la flèche : c'est ce que j'appelle une action continue. En revanche, quand j'appuie sur `J`, je veux que mon personnage saute une fois, même si je continue d'appuyer sur la touche : c'est ce que j'appelle une action instantanée (non-continue). C'est le même contrôleur (une touche de clavier), mais la manière de le gérer est différente. Dans un cas, je veux que l'action soit active tant que le contrôleur est actif, et dans l'autre cas, je veux que l'action soit active une seule fois même si le contrôleur reste actif. ## Et avec tout ça... Une fois qu'on a des contrôleurs pour tous les périphériques, on peut alors définir des ensembles d'action, dont certains qu'on va retrouver à peu près partout. L'exemple le plus classique est l'ensemble d'actions qui permet de naviguer dans une interface graphique : haut, bas, gauche, droite, accepter. En tout cas, cette double notion contrôleur/action est très pratique et offre le niveau d'abstraction suffisant pour définir l'interaction entre le joueur et le jeu. Du coup, ajouter la gestion de la manette, c'est juste ajouter un contrôleur à une action existante et rien d'autre ne change. C'est simple et ça répond au besoin initial. # Les interfaces graphiques Pourquoi les interfaces graphiques de jeux vidéos sont-elles particulières ? Il y a deux raisons : 1. Premièrement, à cause du mode de fonctionnement de l'affichage. Dans une interface graphique de bureau, l'affichage est mis à jour de temps en temps en fonction d'événements. Dans un jeu vidéo, on affiche une frame tous les soixantièmes de seconde et on la redessine à chaque fois, on doit donc redessiner notre interface complètement. 1. Deuxièmement, à cause des interfaces physiques. Une interface graphique de bureau classique est prévue pour être utilisée avec une souris. Dans un jeu vidéo, la souris n'est pas obligatoire, il faut donc pouvoir piloter l'interface graphique avec toutes les interfaces physiques possibles -- essentiellement le clavier et la manette. Évidemment, je ne suis pas le premier à avoir réfléchi à tout ça ; il existe donc déjà une tétrachiée de bibliothèques d'interfaces graphiques pour SFML (de qualités inégales, d'ailleurs) : - [SFGUI](http://sfgui.sfml-dev.de/) - [TGUI](http://tgui.eu/) - [Primitive GUI](http://primitivegui.sourceforge.net/) - [SFUI (Simple and Fast User Interfaces)](https://code.google.com/p/sfui/) J'ai décidé de réaliser ma propre bibliothèque d'interface graphique. Pour deux raisons. La première raison, c'est que les bibliothèques existantes intègrent complètement la gestion des événements. Or, sachant que j'ai déjà mes contrôleurs et mes actions, je veux les utiliser comme bon me semble et ne pas dépendre des choix faits par la bibliothèque. La deuxième raison, qui se rapproche de la première, c'est que ces bibliothèques intègrent complètement le dessin des widgets, parfois à l'aide d'un langage du genre CSS. Vous devez vous dire que je suis un peu idiot de refuser qu'une bibliothèque de widgets dessine ses widgets. En fait, le fait de découpler les widgets de leur affichage n'est pas si idiot : il permet de customiser l'affichage pour chaque jeu. Avoir un interpréteur de CSS juste pour afficher quelques widgets, ça fait un peu trop usine à gaz à mon goût. L'intérêt d'avoir sa propre bibliothèque, c'est qu'on peut piquer une excellente idée de `jnuit`, à savoir offrir les widgets standard des jeux, et notamment [celui qui gère la résolution de l'écran](https://github.com/devnewton/jnuit/blob/master/core/src/main/java/im/bci/jnuit/widgets/VideoConfigurator.java). Ça permet aussi de voir comment on programme ce genre de logiciel assez particulier qu'est une interface graphique. On en vient à se poser [les mêmes questions que ses prédécesseurs](http://linuxfr.org/users/natir/journaux/les-artistes-ce-fleau-ou-l-invasion-des-profanateurs-de-gui) et au final y apporter les mêmes réponses. Bref, c'est un exercice assez sympathique que tout le monde devrait avoir fait au moins une fois dans sa vie (comme écrire un compilateur), même si ça s'éloigne beaucoup du jeu vidéo au final. # lisuit, SFML User Interface Toolkit Je vous présente donc [SUIT (SFML User Interface Toolkit)](https://github.com/jube/libsuit) (ou lisuit suivant mon humeur) qui est le résultat de toutes ces réflexions. SUIT vient avec la [documentation de l'API](http://jube.github.io/libsuit/modules.html), une [micro documentation générale](https://github.com/jube/libsuit/blob/master/doc/SUIT.md) et quelques exemples (nommés respectivement `spade`, `heart`, `diamond` et `club`, hahaha) et qui permettent de voir quelques fonctionnalités de la bibliothèque. `club` notamment montre le widget de configuration de la vidéo.  # Autres nouvelles en vrac ## La documentation des API de mes bouts de code Comme vous avez pu le voir plus haut, j'ai mis en ligne [la documentation des API des bibliothèques que j'ai écrites pour ce jeu](http://jube.github.io/), sur l'espace mis à ma disposition par github. Ça concerne libes (la bibliothèque pour faire de l'entités-composants-systèmes), libtmx (la bibliothèque pour lire les fichiers TMX produit par Tiled), et libsuit donc. ## Un canal IRC pour parler de jeux libres J'ai rejoint il y a peu le canal IRC #jeuxlibres sur Freenode. Ce canal doit exister depuis un moment mais il n'était pas très connu. Après avoir reçu une invitation, j'ai rejoint ce canal avec quelques autres personnes et au final, ce canal est maintenant assez animé. Nous sommes une grosse dizaine et il y a de temps en temps des débats assez intéressants. Si vous aimez les jeux libres, n'hésitez pas à venir nous rejoindre ! ## Message personnel Enfin, je profite de cette nouvelle pour passer un petit message personnel, une fois n'est pas coutume. En fait, cet été, quelqu'un s'est aperçu que j'étais « le rewind de linuxfr ». Il me connaissait depuis des années via ce biais, et [IRL](http://fr.wikipedia.org/wiki/Vraie_vie) depuis moins longtemps par les hasards de la vie, et il a fait le lien cet été avec des yeux ébahis. C'était très drôle à voir. Donc, coucou à Gérald (qui n'a pas voulu me révéler son compte linuxfr) ;)