đŸ Archived View for blog.flozz.fr âș 2018 âș 11 âș 19 âș developpement-gameboy-5-creer-des-tilesets captured on 2023-09-08 at 16:00:57. Gemini links have been rewritten to link to archived content
âŹ ïž Previous capture (2023-04-19)
-=-=-=-=-=-=-
2018-11-19
Dans le précédent article on a abordé le systÚme vidéo de la GameBoy de maniÚre générale, cette fois-ci l'article sera plus ciblé : on va voir comment créer des tuiles utilisables par nos applications.
On va commencer par regarder comment doivent ĂȘtre encodĂ©es les images pour pouvoir ĂȘtre copiĂ©es dans la mĂ©moire vidĂ©o. On verra ensuite comment convertir les images avec un petit outil nommĂ© img2gb.
--------------------------------------------------------------------------------
đïž Note:
--------------------------------------------------------------------------------
Cet article fait partie d'une série sur le développement GameBoy en C avec le compilateur SDCC et la bibliothÚque gbdk-n. Cette série est toujours en cours et de nouveaux articles paraissent de temps à autre.
Articles de la série :
--------------------------------------------------------------------------------
Dans la derniÚre partie du précédent article, on avait vu rapidement comment afficher des tuiles à l'écran de la GameBoy... tellement rapidement que je n'avais pas pris le temps d'expliquer comment on passe d'une image comme celle-ci :
Tileset issue du jeu zZNAKE (zoom x10)
Ă un tableau d'octets comme celui-lĂ Â :
const UINT8 TILESET[] = { // Tile 00: Blank 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Tile 01: Block 0xff, 0x01, 0x81, 0x7f, 0xbd, 0x7f, 0xa5, 0x7b, 0xa5, 0x7b, 0xbd, 0x63, 0x81, 0x7f, 0xff, 0xff, // Tile 02: Snake Body 0x7e, 0x00, 0x81, 0x7f, 0x81, 0x7f, 0x81, 0x7f, 0x81, 0x7f, 0x81, 0x7f, 0x81, 0x7f, 0x7e, 0x7e, // Tile 03: Boulder 0x3c, 0x00, 0x54, 0x2a, 0xa3, 0x5f, 0xc1, 0x3f, 0x83, 0x7f, 0xc5, 0x3f, 0x2a, 0x7e, 0x3c, 0x3c, // Tile 04: Cherry 0x04, 0x04, 0x04, 0x04, 0x0a, 0x0a, 0x12, 0x12, 0x66, 0x00, 0x99, 0x77, 0x99, 0x77, 0x66, 0x66, };
On va donc regarder Ă©tape par Ă©tape comment encoder chaque pixel d'une image pour qu'elle puisse ĂȘtre utilisĂ©e dans nos applications. Ătant donnĂ© que ce sera toujours la mĂȘme chose pour chaque tuile, on va se concentrer sur une seule. On va donc prendre la tuile reprĂ©sentant des cerises comme exemple (parce que je l'aime bien et que c'est moi qui dĂ©cide đïž) :
La fameuse tuile représentant des cerises
La premiÚre chose à faire, c'est de faire correspondre chaque pixel à l'une des couleurs de la palette de la GameBoy (on verra plus tard qu'il y a en fait plusieurs palettes, et qu'on peut les modifier, mais on ne va pas s'en préoccuper pour le moment), sachant qu'à chaque couleur correspond un numéro :
Conversion des couleurs en numéro issue de la palette
Ensuite, il faut convertir les numéros des couleurs en binaire (2 bits par pixels) :
Conversion des numéro de couleur en binaire
Enfin, il faut regrouper les bits obtenus en octets, c'est la partie la plus compliquée car l'encodage n'est pas forcément des plus intuitifs :
Si vous arrivez jusqu'ici en ayant tout compris du premier coup, bravo, sinon c'est normal... c'est pas quelque chose d'évident à expliquer à l'écrit... c'est pourquoi j'ai fait un « joli » dessin qui devrait beaucoup faciliter la compréhension :
Regroupement des bits en octets
Au final on a plus qu'Ă convertir nos octets en C, en Ă©criture hexadĂ©cimale car c'est quand mĂȘme plus court. Notre image de cerises devient donc :
const UINT8 cherry = { 0x04, 0x04, 0x04, 0x04, 0x0a, 0x0a, 0x12, 0x12, 0x66, 0x00, 0x99, 0x77, 0x99, 0x77, 0x66, 0x66, };
Comme vous pouvez vous en rendre compte, ce n'est pas si compliqué, mais si on devait faire ça à la main ce serait trÚs répétitif et ça prendrait énormément de temps... C'est pourquoi on va voir comment automatiser la conversion dans la suite de cet article.
img2gb est un petit logiciel en Python que j'ai développé pour automatiser la conversion d'une image en tileset et en tilemap utilisables sur GameBoy. ConcrÚtement, ça prend en entrée une image dans un format courant (PNG, JPEG,...) et en sortie ça génÚre des fichiers .c / .h.
Le logiciel devrait fonctionner sur n'importe quel OS oĂč un environement Python (2.7 ou 3.x) est disponible et sa seule dĂ©pendance est Pillow (une bibliothĂšque de manipulation d'image). On va donc commencer par l'installer afin de pouvoir l'utiliser (il vous faudra probablement des droits root sous Linux) :
pip install img2gb
--------------------------------------------------------------------------------
đïž Note:
--------------------------------------------------------------------------------
NOTE pour les utilisateurs de Windows : Comme Python n'est pas installé de base sur cet OS, je vous ai compilé tout ça dans un executable pour vous éviter d'avoir trop de trucs à installer et à configurer. Vous pouvez télécharger la derniÚre version de img2gb.exe sur la page de release du projet sur Github.
la page de release du projet sur Github
Pas la peine d'essayer de double-cliquer dessus, il n'y a pas d'installer ni d'interface graphique pour le moment : il s'utilise en ligne de commande (exemple : img2gb.exe -h pour afficher l'aide).
--------------------------------------------------------------------------------
Une fois installĂ© (ou copiĂ© dans votre rĂ©pertoire courant pour le .exe), la commande img2gb devrait ĂȘtre disponible... et c'est ce que l'on va essayer tout de suite. đïž
Pour notre exemple, on va convertir l'image suivante et écrire un peu de code pour l'afficher sur une GameBoy :
On va supposer que notre répertoire de travail est le suivant :
+-- test-project/ | +-- src/ | | | +-- main.c | +-- img.png
Pour arriver à nos fins, on va avoir besoin de deux étapes :
Pour commencer, on va donc utiliser img2gb pour convertir img.png en tileset :
img2gb tileset \ --output-c-file=src/tileset.c \ --output-header-file=src/tileset.h \ --output-image=src/tileset.png \ --deduplicate \ ./img.png
Prenons le temps de détailler un peu les arguments de la commande :
En suite, il nous faut générer la tilemap qui nous permettra de reconstituer l'image :
img2gb tilemap \ --output-c-file=src/tilemap.c \ --output-header-file=src/tilemap.h \ src/tileset.png \ ./img.png
Encore une fois, détaillons les arguments :
Une fois ces commandes exécutées, notre répertoire de travail devrait ressembler à ça :
+-- test-project/ | +-- src/ | | | +-- main.c | | | +-- tilemap.c | | | +-- tilemap.h | | | +-- tileset.c | | | +-- tileset.h | | | +-- tileset.png | +-- img.png
On va jeter un petit coup d'Ćil aux fichiers .h gĂ©nĂ©rĂ©s :
src/tileset.h :
// This file was generated by img2gb, DO NOT EDIT #ifndef _TILESET_H #define _TILESET_H extern const UINT8 TILESET[]; #define TILESET_TILE_COUNT 97 #endif
Ici, on peut voir qu'une variable TILESET est disponible, c'est elle qui contient toutes les tuiles extraites de l'image.
On voit également qu'une macro TILESET_TILE_COUNT a été générée et qu'elle contient le nombre de tuiles (on a donc 97 tuiles différentes pour afficher notre image).
src/tilemap.h :
// This file was generated by img2gb, DO NOT EDIT #ifndef _TILEMAP_H #define _TILEMAP_H extern const UINT8 TILEMAP[]; #define TILEMAP_WIDTH 20 #define TILEMAP_HEIGHT 18 #endif
Dans ce fichier, on trouve la variable TILEMAP et les macros TILEMAP_WIDTH et TILEMAP_HEIGHT. Elles contiennent respectivement, la tilemap permettant de recomposer notre image, la largeur de ladite tilemap et sa hauteur.
Maintenant qu'on a converti notre image en C, et qu'on a toutes les informations nécessaires, on peut écrire un petit programme pour l'afficher sur l'écran d'une GameBoy. Voici le contenu du fichier main.c :
#include <gb/gb.h> #include "tileset.h" #include "tilemap.h" void main(void) { set_bkg_data(0, TILESET_TILE_COUNT, TILESET); set_bkg_tiles(0, 0, TILEMAP_WIDTH, TILEMAP_HEIGHT, TILEMAP); SHOW_BKG; }
Il ne nous reste plus qu'à compiler tout ça, ce qui peut se faire soit avec les commandes suivantes sous Linux (ou leur équivalent sous Windows) :
./gbdk-n/bin/gbdk-n-compile.sh src/main.c ./gbdk-n/bin/gbdk-n-compile.sh src/tileset.c ./gbdk-n/bin/gbdk-n-compile.sh src/tilemap.c ./gbdk-n/bin/gbdk-n-link.sh *.rel -o graphics2.ihx ./gbdk-n/bin/gbdk-n-make-rom.sh graphics2.ihx graphics2.gb
Soit en récupérant le fichier Makefile (pour Linux) ou Make.bat (pour Windows) dans l'un des exemples que j'ai publiés sur Github, et en l'exécutant à l'aide de la commande suivante (pour Linux ou Windows avec CMD.exe) :
exemples que j'ai publiés sur Github
make
--------------------------------------------------------------------------------
đïž Note:
--------------------------------------------------------------------------------
NOTEÂ : si vous avez des soucis avec la compilation de l'exemple, je vous invite Ă relire les instructions du premier article. đïž
les instructions du premier article
--------------------------------------------------------------------------------
à ce stade, il ne nous reste plus qu'à lancer la ROM générée avec l'émulateur de notre choix. Si tout s'est bien passé, vous devriez voir un résultat similaire à celui-ci :
Vous retrouverez bien sur le code complet de l'exemple ci-dessus sur Github :
https://github.com/flozz/gameboy-examples/tree/master/05-graphics2
Ă prĂ©sent qu'on sait comment convertir des images en tiles utilisables sur la GameBoy, il ne nous reste plus qu'Ă dĂ©couvrir toutes les façons de s'en servir dans un jeu. On abordera donc les diffĂ©rentes couches (Background, Window et Sprites) dans les prochains articles afin de pouvoir commencer Ă dĂ©velopper de vrais jeux. đïž
--------------------------------------------------------------------------------
Edit 04/02/2019 : J'ai mis à jour la section « Convertir des images avec img2gb » afin que les instructions qui s'y trouvent fonctionnent avec img2gb 1.0 (la branche 0.x étant obsolÚte aujourd'hui).
Edit 18/09/2019 : J'ai mis à jour les commandes pour compiler le programme suite au changement de la chaßne de compilation. Lisez le nouvel article d'introduction de la série pour plus d'informations.
nouvel article d'introduction de la série
--------------------------------------------------------------------------------