đŸ’Ÿ Archived View for blog.flozz.fr â€ș 2018 â€ș 11 â€ș 19 â€ș developpement-gameboy-5-creer-des-tilesets captured on 2023-04-19 at 22:32:47. Gemini links have been rewritten to link to archived content

View Raw

More Information

-=-=-=-=-=-=-

Développement GameBoy #5 : Créer des tilesets

2018-11-19

Couverture de l'article

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 :

re-Hello World

Utiliser le gamepad

Projet 1 - Tic Tac Toe

Afficher des images

Créer des tilesets

La couche « Background »

Les sprites

La couche « Window »

Les palettes

Projet 2 - Breakout

PARTIE 1

PARTIE 2

PARTIE 3

GĂ©rer et afficher du texte

--------------------------------------------------------------------------------

Encodage des images

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 :

plus tard

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.

Convertir des images avec img2gb

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.

img2gb

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 :

Image Ă  convertir

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 :

Capture d'écran du résultat

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

--------------------------------------------------------------------------------

🏠 Accueil