Ça ne  »scalera » pas ton affaire!

C’est la première chose que mon frère m’a dite en voyant le code de mon premier petit projet, un clone de Pong.  J’étais assez fier que mon code compile, et qu’en plus, le jeu fasse à peu près ce qu’il devait faire.  Mais là, mon code ne scalait pas?  Merde, je ne comprenais même pas ce que ça voulait dire.

Pour nous mettre en contexte, mon frère est programmeur de métier, ce qui fait de lui mon espèce de mentor.  Mentor qui me jette des répliques de ce genre et qui me laisse me démerder pour régler le problème 🙂  Est-ce que Aristote faisait ce genre de coup à Alexandre?  J’en doute…

Comme mon Pong était vaguement terminé, je le mis de côté, malgré qu’il lui manqua la vertu de scaler adéquatement, et je me mis à mon projet suivant, le super-super célèbre Fraisinette.  Ce jeu était plus ambitieux.  Il devait contenir plusieurs niveaux, une carte du monde, un tilemap, un engin de particules, de la musique, et j’en passe.

C’est là, après m’être empêtré quelques semaines dans tout ça, que j’ai compris ce qu’il voulait dire.  Apprendre un langage de programmation, les if et les float, les for et les semicolons, c’est une chose.  On lit, on réfléchit, on s’entraîne et ça entre, tranquillement.  Apprendre à architecturer du code pour qu’il ne devienne pas un immense spaghetti inextricable, c’est un art.  Et je ne dis pas ça légèrement.  On sort de la science des Sciences Informatiques et on entre dans l’Art informatique.

Donc, le terrible scaler veut dire que je dois structurer mon code pour que je puisse faire grandir le projet tout en :

a) évitant de tout briser ce qui est déjà fait.

b) tentant de garder le tout compréhensible / lisible.

c) s’assurant que je puisse ajouter des nouveaux trucs (features) simplement, sans avoir à réécrire des pans entiers de la machine.

Ok, alors je me mets au travail et je passe plusieurs mois à construire Fraisinette avec ces beaux préceptes en tête, et il me semble que ça se déroule pas mal.  Le jeu fait ce qu’il doit faire et mon petit Aristote de frère à même l’air de trouver ça pas pire.  Alors que le jeu est très avancé (pas mal dans son état actuel pour être franc – trois niveaux jouables), il jette un oeil sur mon repo (sur mon code) et… ça ne scalera pas ton affaire!

ARRRGG!

Bon, je ne suis pas complètement découragé.  J’ai appris beaucoup de chose en fabriquant Fraisinette (pour preuve, je sais de quoi il parle cette fois!), et somme toute, le programme fait ce que je lui demande de faire, ce qui est l’objectif principale d’un programme, non?  Mais il a un peu raison.  J’ai poussé le concept de l’orienté objet beaucoup plus loin cette fois, mais les classes ont beaucoup trop de responsabilités et il y a moyen de rendre les objets plus interchangeables, évidement.

En m’attaquant à One man’s, je savais que le défi allait en croissant et que le code de ce jeu avait un potentiel d’inflation immense.  Je me devais donc d’écrire chaque classe, chaque méthode, en ayant la scalabilité (est-ce que je pousse trop la francisation là?) en tête.

À chaque instant.

Je me suis donc appliqué à diviser les choses.  Le code pour le héros, du code pour chaque tableau, le code pour le premier ennemi, etc.  Mais là, il faut que je me rende à l’évidence. La classe qui gère mon héros est trop longue, contient trop de gestion d’états et de gestion d’animations.  Ça devient risqué de changer quelque chose.  La classe de l’ennemi est partie pour être tout aussi bordélique, avec la gestion de l’AI en plus.  Et la classe qui gère le premier niveau s’occupe de l’effet parallaxe et du brouillard, ça n’a pas de sens…

Alors, cette fois je me le dis moi-même : ça ne scalera pas mon affaire 🙂

Je me retrousse les manches, et je refactor et brasse la soupe pour améliorer le tout, et bientôt, il y aura un combat entre moi et ce boche, vous allez voir.

Ah oui, vraiment un art…

Penser en 16,7 millièmes de seconde

Lors d’une discussion avec un camarade indie développeur (!) il y a quelques temps, nous abordions le sujet de la  »game loop » et comment elle nous avait obligé à changer notre façon de penser.  Ou plutôt, comment nous avions eu une certaine difficulté à changer notre façon de penser!

Le code d’un jeu vidéo est une seule et immense boucle.  Dans le meilleur des mondes, cette boucle sera répétée 60 fois à toutes les secondes.  Cela signifie que le processeur repassera à travers tout le code, et dessinera tous les éléments du jeu présents à l’écran à tous les 16,7 millièmes de seconde.  La vitesse à laquelle un processeur pour digérer de l’information est astronomique et donne un peut le tournis.  À tous les 16,7 millièmes de seconde, l’ordinateur vérifie la position des éléments du jeu, vérifie s’il y a des  »inputs » provenant du clavier, de la souris ou de la manette de jeu, il s’assure que le son adéquat sort des hauts-parleurs, et redessine aussi les éléments à l’écran en fonction des règles établies par l’engin (sprites, effets, particules, ombres et lumières, éléments de l’interface de jeu tel le pointage et barres d’énergie).  Et étrangement, ça fonctionne…

Tout ça va tellement vite, qu’un humain ne peut tenter de raisonner toutes ces commandes en temps réel.  Le développeur doit faire exactement le contraire pour parvenir à s’y retrouver.  Il faut ralentir le tempo, il faut penser en 16,7 millièmes de seconde.  Il faut penser un seul tour de boucle, un seul cycle, et s’assurer qu’il ne se contredise pas et qu’il couvre tous les angles, toutes les possibilités.

Et là réside la difficulté.  Il faut se sortir de la peau du joueur qui voit le spectacle en mouvement, et s’installer confortablement dans un monde statique et figé.  Une seule  »frame » des fameuses  »frames per seconde ».

Un cas classique, à titre d’exemple (et qui était justement la base de notre discussion d’il y a quelques temps) : je veux déplacer le héros de mon jeu vers la droite.  Je programme donc le jeu pour qu’il déplace le personnage d’une petite distance vers la droite lorsque la flèche droite du clavier se fait enfoncer.  On démarre le jeu et… le héros ne bouge pas d’un iota, ou pire, il disparaît!  Je vérifie, et oui, je demande effectivement au héros de se déplacer.  Ça veut dire que quelque part, dans mon programme qui ne dure que quelques millièmes de seconde, je contredis cette commande et ramène le personnage à son emplacement initial!  Et ça va tellement vite que ça ne parait pas à l’écran.

Bordel…

Reste à déboguer maintenant.  Tranquillement.

À 16,7 millièmes de seconde …