50 Hz sur STe : le bug qui n'apparaissait qu'avec des ennemis
Le scroll matériel du STe me donne enfin le 50 Hz. Je croyais le moteur acquis. Le jour où j'ai lâché des ennemis qui rôdent jusqu'aux bords de l'écran, un bout de décor s'est mis à apparaître au mauvais endroit. Récit d'un piège qui était resté en suspens depuis des mois
Le 50 Hz, et ce qu'il coûte
Pour ce jeu vu de dessus, je veux un scroll vraiment plein, à 50 images par seconde, sur STe. La bonne nouvelle, c'est que cette machine sait décaler son affichage sans recopier l'image : elle se contente de pointer ailleurs dans sa mémoire. La caméra suit le héros, le décor file, et le processeur ne s'épuise jamais à recopier un écran entier. C'est le seul moyen d'avoir à la fois la fluidité et assez de marge pour faire vivre le gameplay.
Le prix à payer, c'est la mémoire. La façon la plus simple de faire glisser l'image serait de garder le monde entier en mémoire, et ça ne tient pas sur une machine d'un mégaoctet, une fois qu'on y a logé les sprites, la musique, le code et les niveaux. J'utilise donc une disposition mémoire astucieuse, empruntée à la scène demo, qui ne garde qu'une étroite bande du monde à la fois et la redessine au fur et à mesure que la caméra avance. Ça tient dans un mégaoctet, et ça donne le scroll matériel à 50 Hz. La contrepartie ... je l'apprendrai plus tard.
Le héros, lui, n'a jamais eu de problème
Le héros est toujours au centre de l'écran. Pour le dessiner, je sauve le décor sous lui, je l'affiche, puis à l'image suivante je remets le décor en place. Ça fonctionne depuis longtemps, fluide, sans la moindre bavure. Je pensais le moteur OK.
Le jour où les ennemis bougent
J'ai branché les ennemis du niveau, des Rock Men à la Chaos Engine, qui poursuivent le héros et lui jettent des rochers. Eux ne sont pas centrés : ils rôdent sur toute la largeur de l'écran, jusqu'aux bords. Et là, un rectangle de décor s'est mis à apparaître au mauvais endroit, un bout de paroi rocheuse plaqué sur le sol gris, surtout quand je revenais sur mes pas.
Tant que tous les ennemis restent entièrement à l'écran, je peux balayer la caméra à gauche et à droite sans le moindre défaut. Le décalage n'apparaît qu'au moment où j'allais un peu vite et qu'au moins un ennemi disparaissait d'un bord. La disparition d'un sprite, voilà le déclencheur.
Pour voir le défaut sans être embetté par le vrai décor, j'ai remplacé chaque colonne de tuiles par une couleur unie, une par colonne, en cycle. Le décor est devenu des barres verticales colorées, et la couleur d'une barre déplacée trahissait d'où elle venait. Le verdict était net : un morceau de décor s'affichait à un endroit, mais montrait le contenu d'un autre, situé bien plus loin.
Pourquoi le bord, et pas le centre
La disposition mémoire qui me fait tenir dans un mégaoctet a une particularité : elle se replie sur elle-même. Au-delà d'une certaine largeur, deux endroits du monde finissent par se partager la même case mémoire. Tant qu'on dessine au cœur de la bande visible, ce repli tombe toujours hors de l'écran, invisible et inoffensif. C'est exactement pour ça que le héros, toujours centré, n'a jamais rien révélé : il est au milieu, loin des bords où le repli mord.
Un ennemi collé au bord, lui, déborde juste assez pour que son empreinte tape dans la zone repliée. Le décor qu'on redessine sous lui finit alors recopié sur le bord opposé, hors caméra, là où on ne le nettoie jamais. La corruption s'installe en coulisses, et saute aux yeux dès qu'on revient sur ses pas. Le proto d'origine, qui n'avait qu'un héros centré, ne pouvait tout simplement pas faire surgir ce piège.
Le correctif, sans lâcher le 50 Hz
L'idée du correctif tient en une phrase : ne jamais faire confiance à une copie d'écran, toujours repartir de la source propre. Plutôt que de sauver puis restaurer les pixels sous chaque ennemi, ce qui finissait par recopier en boucle la moindre bavure déjà présente, je redessine le décor sous chaque sprite directement depuis le niveau, à chaque image. La source est toujours saine, il n'y a plus rien à propager.
J'y ai ajouté une sorte de garde fou aux bords : un ennemi trop près du bord est retiré de l'écran un poil plus tôt qu'avant. À l'œil ça ne se voit quasiment pas, mais ça garantit que son empreinte ne déborde plus jamais dans la zone piégée. Et quand un ennemi sort de l'écran, je nettoie soigneusement la trace qu'il laissait, en m'assurant que ce nettoyage lui-même ne déborde pas à son tour. Le serpent ne se mord plus la queue.
Le bilan
Le scroll matériel tient le 50 Hz sur STe, décor, foyers de peste, héros et jet de lanterne compris, et le décor reste stable, sans rectangle fantôme, même en revenant sur ses pas à pleine vitesse avec les Rock Men et leurs rochers qui rôdent jusqu'aux bords.
Une réserve honnête, mesurée manette en main : quand le combat se densifie pour de bon, trois Rock Men qui chargent en lançant leurs rochers tous en même temps, le framerate descend un peu le temps que cette grosse fournée de sprites passe. Le coût, ce ne sont ni les foyers ni l'intelligence des ennemis, ce sont ces gros sprites affichés d'un coup. Hors de ces pics, c'est du 50 Hz franc. Le même binaire bascule en scroll logiciel sur STf, détecté au démarrage.
La même mécanique, redessiner depuis la source et rester loin des bords, sert ensuite à tout le reste que le scroll matériel ne savait pas encore afficher : les foyers de peste, posés derrière le héros comme du décor de fond, et le jet de la lanterne, ces chevrons que le héros projette devant lui (et que je vais devoir refaire faire par un designer ;) ). Chacun repart du niveau propre, donc aucun ne ramène de salissure à l'écran.
La morale rejoint celle du parallax : sur Atari ST, les astuces mémoire qui font tenir l'impossible dans un mégaoctet ont toujours une contrepartie cachée. Ici, gagner à la fois la fluidité et la place imposait une mémoire qui se replie sur elle-même. Il a suffi d'un héros toujours centré pour masquer le piège pendant des mois, et d'un seul ennemi qui sort de l'écran pour le faire apparaître.
La version courante du jeu est téléchargeable ici en disquette .st. Monte-la comme disquette A dans Hatari, en mode STe pour le scroll matériel 50 Hz, ou en mode STf pour le scroll logiciel : c'est le même fichier, il détecte la machine au boot. Pour la version courante du jeu, voir aussi la page d'accueil.
Laisser un commentaire