3. Utilisation de la programmation réactive: le jeu

Figure 2. Captures d'écran du jeu réalisé

3.1. Ce projet n'est pas un " n-ième jeu en 3D" 

Pour avoir les idées claires sur le véritable but recherché lors de l'élaboration de ce jeu, il est indispensable de préciser deux choses:

3.2. Pourquoi un tel jeu ?

Le postulat servant de point de départ à la réflexion repose sur l'idée qui la conception d'un jeu de billard est intéressant pour mettre en application le modèle de programmation réactive.

En effet, l'avantage notoire de ce type de jeu est qu'on évite de mettre en oeuvre des algorithmes trop évolués comme la gestion avancée d'animation d'objets ou de personnages, les détections de collisions avec des surfaces géométriques complexes, etc... ce qui n'est pas le but du projet. En effet, dans l'absolu, simuler un billard consiste uniquement à faire évoluer des boules (formes primitives) dans un environnement suffisamment simple et restreint. Il est ainsi possible de se focaliser entièrement sur l'objectif principal du projet, à savoir contrôler de manière simple l'évolution d'entités dans un jeu, et non pas de parfaire l'aspect visuel ou ludique de ce dernier.

Important

Le choix de faire un billard est donc judicieux: grâce au nombre de boules qu'il met en jeu, il permet de tester les facultés de synchronisation permises par la programmation réactive. De plus, les différents types de collisions pouvant intervenir au cours de la partie (avec des boules, avec les bords du billard, ...), qui impliquent autant d'algorhitmes différents à concevoir, permet de bien se rendre compte de l'étendu des facilités qu'offre le langage pour résoudre des problèmes concrets.

Si l'on réfléchit à la manière de simuler un billard, on s'aperçoit que toutes les interactions du jeu sont déclenchées par les boules, et ont pour effet de modifier le " comportement"  d'autres boules.

Note

On entend par comportement la faculté de modifier l'état d'une boule à un instant donné, en fonction des différents scénarios susceptibles de se produire durant la partie.

On peut ramener le comportement général d'une de ces boules à la composition de plusieurs comportements de base:

  • le déplacement,

  • L'inertie induite par le billard,

  • La collision entre deux boules,

  • La collision avec un des bords du billard,

  • La chute dans un des trous du billard

Quel est l'avantage d'une telle vision de l'architecture d'un billard ? Cela permet de mettre en exergue certaines propriétés communes aux boules:

3.3. Comparaison des possibilités d'implémentation

Note

D'un point de vue algorithmique, la détection de collision entre n boules est un algorithme polynomial d'ordre O(n2) en temps.

Après les caractérisations de la section précédente, on voit bien qu'il aurait été dommage de procéder à une implémentation brutale consistant à imbriquer des boucles pour détecter toutes les collisions. Cela aurait exhibé les passes nécessaires au fonctionnement de l'algorithme, rendant du coup le code source plus dur à déchiffrer. De plus, il aurait fallu connaître à l'avance le nombre de boules pour effectuer les tests, ce qui aurait rendu le code encore plus diffus et difficile à maintenir.

Une autre solution aurait consisté à mettre en oeuvre une implémentation à base de thread. Cette solution semble mieux convenir aux propriétés extraites du modèle comportemental d'un billard. Les propriétés d'encapsulation des comportements d'une balle aurait pu être respectées beaucoup plus facilement, et une même fonction de test de collision aurait pu être utilisée pour chaque boule, faisant disparaître une imbrication de boucle dans la routine principale.

Mais cette possible implémentation reste très théorique, puisque les contraintes d'ordonnancement des thread aurait rendu la gestion des collisions quasi ingérable. En effet, il faut que toutes les boules puissent bouger de manière précise et puissent avoir connaissance des positions exactes de chaque boule à chaque instant. Dans la pratique, ce genre de tests a déjà été effectué par Frédéric Boussinot, l'auteur de Junior, et il a été démontré que de telles exigeances étaient impossible à assurer. Or, la gestion de collision exige un ordonnancement parfait entre tous les thread pour fonctionner, et il est impossible de pour contrôler l'ordre d'activation ou même le temps d'éxécution des thread. Enfin, le point le plus défavorable de cette technique provient du fait qu'il aurait fallu rendre l'algorithme de collision très complexe pour éviter tous les problèmes de dead-locks occasionnés par la communication entre les boules.En résumé, cette implémentation est bien trop contraignante pour être retenue.

L'approche de la programmation réactive semble conjuguer tous les avantages de l'architecture cloisonnée (objet), sans subir les contre coûts de la programmation concurrente classique. Les problèmes de synchronisation sont résolvables intrinsèquement grâce aux facilités de communication offertes par la bibliothèque réactive.

Si l'on se remémore la description proposée précédemment du modèle d'un jeu de billard, on se rend compte que les idées fortes sont bien la réaction, en communiquant à l'aide d'événements et de manière cloisonnée. Ce type de modèle est donc précisément le domaine algorithmique où la programmation réactive propose des solutions simples et efficaces à implémenter.

3.4. Jugement du postulat initial

Il apparaît donc que ce jeu se positionne dans le bon créneau: il est suffisamment évolué pour poser des problèmes coûteux en terme de complexité en temps, et le nombre d'entités à gérer simultanément est suffisamment important pour avoir affaire à des problèmes de synchronisation non triviaux.

A posteriori, la plupart des points sensibles de la simulation du billard on effectivement trouvé une solution de conception simple, rapide à implémenter, et souvent bien plus courte que ce qui avait été envisagé lors de la phase de réflexion initiale de développement. En particulier, ce jeu a réellement permit d'utiliser toute la palette d'expressions qui découle de la dualité programmation réactive + lambda calcul, à travers le moteur Senior 2.0.