Avec la publication de la version 0.9 de Briques Stellaires, ma contribution à la Game Jam « Retro Programmers United for Obscure Systems » session PHC-25 est l'occasion de revenir sur cette session et ma proposition.
Vu les caractéristiques modestes mais sympathiques du PHC-25, j'ai eu envie de faire un jeu plutôt action. Exercice toujours délicat pour ces machines peu utilisées dont les émulateurs sont très très perfectibles, pour ne pas dire à côté de la plaque. Mais ayant eu un accès temporaire à la machine, je ne me suis dit que... allez pourquoi pas.
J'étais parti sur un twist du classique casse-brique. Au final, le temps passant toujours à sa proverbiale vitesse, le jeu est... un casse-brique tout ce qu'il y a de plus standard.
Mais voyons un peu les détails potentiellement intéressants du développement.
L'environnement de développement
Je suis parti pour cette contribution sur un développement en assembleur Z80. Je le regretterai plus d'une fois, quand il m'a fallu mettre au point la routine de rebond. Mais comme je savais que cela serait potentiellement compliqué avec des regressions très probables, j'ai cherché dès le début un environnement me permettant de faire des tests unitaires.
J'avais déjà mis en place des tests unitaires pour le jeu sur VG5000, cependant, ils devaient être lancés en même temps que l'exécutable principal. Puis c'était un bricolage rapide qui manquait de fonctionnalités.
Je suis donc parti sur un environnement déjà fait : DeZog. C'est un environnement intégré à Visual Code, initialement fait et spécialisé pour le ZX Spectrum, mais qui peut être utilisé comme environnement Z80 générique. DeZog supporte l'exécution de tests unitaires, avec de nombreuses assertions, le tout pouvant tourner dans un émulateur interne.
DeZog implémente aussi un lien de debuggage avec différents émulateurs, dont MAME. Parfait pour la mise au point.
Les choix pour le PHC-25
Il y a plusieurs modes graphiques sur le PHC-25, qui utilise comme VDP un clone du MC6847 avec le maximum de RAM vidéo supportée. On peut considérer qu'il y a deux grandes classes de modes graphiques : des modes alpha-numérique/semi-graphique, et des modes bitmap, avec des variations dans les contraintes.
Pour le jeu, j'ai choisi un mode alpha-numérique/semi-graphique qui permet d'avoir une résolution en « gros pixels » de 68x48. C'est suffisant pour un casse-brique.
Pas de son ni de joystick, car le PHC-25 a besoin d'une extension pour cela. Et puis... le temps, toujours le temps.
Liste d'affichage
Sur le PHC-25, le MC6847 utilise pour RAM vidéo une mémoire directement accessible par le bus du Z80. Et lorsqu'il y a arbitrage, c'est le Z80 qui gagne. Ainsi, des accès à la mémoire vidéo pendant le rafraîchissement de l'écran provoquent des parasites bien visibles.
Il faut donc absolument éviter d'accéder à la mémoire vidéo pendant le rafraîchissement. C'est d'ailleurs ce que fait la ROM du PHC-25 où les commandes graphiques sont appliquées progressivement pendant l'interruption (INT), branchée sur VBLANK.
Et c'est aussi ce que je fais dans Briques Stellaires. Après avoir passé le Z80 en mode d'interruption IM2 (il n'y a pas de possibilité prévue par le système pour s'accrocher à l'interruption en IM1), je déroule des listes d'affichages au moment de l'interruption. Ces listes d'affichages sont elles-mêmes construites pendant le reste du temps, par des accès en RAM normale exclusivement.
Ces listes d'affichages sont de type : afficher une brique, effacer une brique, effacer et afficher la balle,...
Le traitement de l'affichage du contour de jeu ainsi que des pages de titre et de score est un peu différent : je prépare l'affichage dans un buffer auxiliaire de la taille de l'écran, puis je copie ce buffer en RAM vidéo pendant le VBLANK, petit à petit.
L'affichage de la raquette est similaire : il est fait dans le buffer auxiliaire, puis la ligne correspondante est copiée en RAM vidéo pendant le VBLANK systématiquement. C'est un choix que j'ai fait assez tôt car je ne savais pas trop à quelle vitesse la raquette allait bouger et je voulais un système simple, avec un temps fixe pendant la VBLANK.
La physique
Voilà qui m'a pris plus de temps que prévu. Je savais que cela allait être délicat, avec des rebonds particuliers et des vitesses non entières. En effet, les coordonnées de la balle sont en virgule fixe, 8 bits pour la partie entière, 8 bits pour la partie fractionnaire. Là encore, c'est un choix que j'ai fait assez tôt, car je ne savais pas quelle vitesse de balle allait être intéressante. Et avec la résolution de l'écran, des vitesses entières allaient donner des mouvements bien trop rapides.
Pour les collisions, je trace une ligne entre la position précédente et la position actuelle de la balle, point par point, en testant les collisions avec les briques, la raquette et les bords. La ligne ne fait rarement plus de deux pixels, mais là encore, cela permet de gérer différentes vitesses, donc des vitesses supérieures à 1 par axe.
Par contre, j'ai simplifié : une collision arrête immédiatement la trajectoire. Je ne cherche pas à compléter le mouvement restant après le rebond. Aux vitesses utilisées au final par le jeu, la différence est imperceptible.
La gestion de variables
Puisque le jeu est sur cassette, il est toujours intéressant de minimiser la taille des données encodées. Pour gagner de la place, j'ai implémenté avec le système de STRUCT et de macros de sasmjsplus qui permet de « déclarer » des variables près du code, mais qui sont toutes regroupées à la fin du code lors de l'assemblage.
Au démarrage du programme, je fixe toute la zone à zéro. Un peu à la manière d'une section BSS
dans un programme C.
J'avais envisagé d'utiliser un système de compression, surtout pour les niveaux. Mais le manque de temps et finalement la taille relativement modeste du programme (moins de 3ko) m'ont fait abandonner cette idée.
Conclusion
Briques Stellaires est un casse-brique très rudimentaire. Et autant que je puisse m'en souvenir, c'est la première fois que je programme un casse-brique. Je me suis perdu dans la gestion de collisions et malgré les tests unitaires qui m'ont gardé sur les rails, j'y ai passé beaucoup de temps. Un peu avant la date limite de la jam, j'ai coupé dans toutes mes idées un peu originales pour me concentrer sur l'essentiel : un jeu auquel on peut jouer.