Blog ENI : Toute la veille numérique !
🎁 Jusqu'au 31/12, recevez notre
offre d'abonnement à la Bibliothèque Numérique. Cliquez ici
🎁 Jusqu'au 31/12, recevez notre
offre d'abonnement à la Bibliothèque Numérique. Cliquez ici
  1. Livres et vidéos
  2. Langage C
  3. Graphisme et jeux sous Allegro 5
Extrait - Langage C Maîtriser la programmation procédurale (avec exercices pratiques) (2e édition)
Extraits du livre
Langage C Maîtriser la programmation procédurale (avec exercices pratiques) (2e édition)
3 avis
Revenir à la page d'achat du livre

Graphisme et jeux sous Allegro 5

Introduction

Nous proposons d’entrer dans un environnement de programmation graphique pour le multimédia et les jeux vidéo en C et C++. Nous avons opté pour la bibliothèque Allegro. Cette bibliothèque est caractérisée par un grand nombre de fonctions de dessin ainsi que de multiples possibilités d’affichage pour les images. Ces deux atouts, finalement assez rares, la distinguent avec un potentiel de créativité peu commun.

Deux versions de cette bibliothèque existent simultanément : Allegro 4 et Allegro 5. Nous avons choisi la version la plus récente, également la plus complète et la plus puissante, Allegro 5. Les deux versions sont très différentes et totalement incompatibles entre elles.

En musique, Allegro signifie "rapide, vivant, vif" et fournit pour la bibliothèque l’acronyme récursif "Allegro Low LEvel Game ROutine". C’est une bibliothèque qui à l’origine provient de la programmation des jeux Atari. Shawn Hargreaves en a commencé le développement en 1990 et depuis elle est soutenue par une communauté très active, internationale, mais malheureusement essentiellement anglophone.

Allegro 5 supporte les systèmes Unix/Linux, Windows, Mac OS X, iOS et Android.

Ses fonctionnalités couvrent l’affichage graphique, éventuellement sur plusieurs écrans, les événements souris, clavier, joystick, le son, le multithread, les minuteurs (timers en anglais), le dessin, etc. Nativement, elle supporte la 2D, mais elle est compatible avec OpenGL, Direct3D et d’autres bibliothèques 3D. Sa conception est modulaire et de nombreux modules sont optionnels. Par exemple, si l’on préfère ne pas utiliser le module audio de la bibliothèque, mais plutôt utiliser une autre bibliothèque comme FMOD, c’est tout à fait possible.

Le module audio de la bibliothèque comprend cependant tout le nécessaire pour gérer du son dans un programme.

La dernière version stable que nous utilisons dans cet ouvrage est Allegro 5.2.7.

Objectifs

Nos objectifs sont les suivants : installer la bibliothèque, expérimenter des fonctions de dessin, expérimenter des fonctions de récupération...

Contrôler la fenêtre

1. Taille et position

La fonction al_resize_display :

bool al_resize_display(ALLEGRO_DISPLAY *display, int width, int height) 

Cette fonction sert à redimensionner la fenêtre. Elle prend en paramètre la fenêtre (pointeur display) concernée, la nouvelle largeur width et la nouvelle hauteur height. Elle retourne vrai en cas de succès.

La fonction al_get_display_width :

int al_get_display_width(ALLEGRO_DISPLAY *display) 

Elle retourne la largeur de la fenêtre et prend en paramètre la fenêtre display.

La fonction al_get_display_height :

int al_get_display_height(ALLEGRO_DISPLAY *display) 

Elle retourne la hauteur de la fenêtre et prend en paramètre la fenêtre display.

La fonction al_set_window_position :

void al_set_window_position(ALLEGRO_DISPLAY *display,int x,int y) 

Elle permet de positionner la fenêtre n’importe où dans l’écran. Elle prend la fenêtre en paramètre ainsi que la position horizontale x et la position verticale y souhaitées.

La fonction al_get_window_position :

void al_get_window_position(ALLEGRO_DISPLAY *display,int*x,int*y) 

Elle récupère la position à l’écran de la fenêtre display via deux variables passées par référence aux pointeurs x pour l’horizontale et y pour la verticale.

2. Attribut de redimensionnement

Toutes les fenêtres que nous avons vues jusqu’à maintenant ont une taille fixe décidée avec al_create_display(). Cette taille est éventuellement modifiable dans le code avec la fonction al_resize_display(). Mais l’utilisateur ne peut pas la changer en tirant sur un bord ou un coin ni en double-cliquant dans la barre de transport. Pour que le redimensionnement de la fenêtre par l’utilisateur soit possible, il faut le spécifier avant la création de la fenêtre avec la fonction void al_set_new_display_flags(int flags).

Cette fonction permet d’activer différentes fonctionnalités choisies parmi celles qui sont proposées. Le paramètre flags est un tableau de bits. Chacun des bits de l’entier flags correspond à une fonctionnalité. S’il est à 1, la fonctionnalité est activée ; s’il est à 0, elle ne l’est pas. La mise...

Dessiner

1. Couleur, transparence

Le module graphique Allegro met à disposition huit fonctions pour la création de couleurs :

La fonction al_map_rgb :

ALLEGRO_COLOR al_map_rgb( unsigned char r, unsigned char g, unsigned char b) 

Cette fonction retourne une couleur selon les valeurs de rouge r, vert g et bleu b passées en paramètre. Ces valeurs sont dans la fourchette 0-255 compris.

La fonction al_map_rgb_f :

ALLEGRO_COLOR al_map_rgb_f(float r, float g, float b) 

Même fonction que al_map_rgb() mais les valeurs sont établies en float dans la fourchette de 0.0 à 1.0.

La fonction al_map_rgba :

ALLEGRO_COLOR al_map_rgba(unsigned char r, unsigned char g, unsigned char b, unsigned char a) 

Fonction comme al_map_rgb() mais qui ajoute le canal alpha de la transparence. La transparence est réglée de la même façon avec une valeur dans la fourchette 0-255 (0 = pas de transparence).

La fonction al_map_rgba_f :

ALLEGRO_COLOR al_map_rgba_f(float r, float g, float b, float a) 

Identique à al_map_rgba() mais les valeurs sont passées en float entre 0.0 et 1.0.

La fonction al_unmap_rgb :

void al_unmap_rgb(ALLEGRO_COLOR color,unsigned char *r, unsigned char 
*g, unsigned char *b) 

Fonction qui permet de récupérer les valeurs des composantes de rouge, vert et bleu de la couleur color. Les paramètres de sortie sont des variables passées par référence.

La fonction al_unmap_rgb_f :

void al_unmap_rgb_f(ALLEGRO_COLOR color, float *r, float *g, float *b) 

Même fonction que al_unmap_rgb() mais les valeurs sont des valeurs flottantes comprises entre 0.0 et 1.0.

La fonction al_unmap_rgba :

void al_unmap_rgba(ALLEGRO_COLOR color,unsigned char *r, unsigned char 
*g, unsigned char *b, unsigned char*a) 

Fonction qui récupère les composantes de rouge, vert, bleu et de transparence de la couleur color. Les paramètres de sortie sont des variables passées par référence.

La fonction al_unmap_rgba_f :

void al_unmap_rgba_f(ALLEGRO_COLOR color, float *r, float *g, float *b, 
float *a) 

Même fonction mais les résultats sont fournis en valeurs flottantes comprises entre 0.0 et 1.0.

Par ailleurs, Allegro 5 fournit un greffon color addon qui ajoute une vingtaine de fonctions pour la couleur. Ces fonctions permettent d’aborder la couleur autrement qu’en RGB. Ces fonctions nécessitent l’inclusion...

Images

Toutes les images sont des bitmaps dans un programme Allegro. Nous commençons ainsi par présenter la bitmap en mémoire, qui, dans un programme, permet de créer, de composer ou de modifier une image. Ensuite, nous présentons les "images". À la différence des bitmaps en mémoire, ce sont au départ des fichiers externes au programme que l’on peut charger dans le programme. Nous abordons comment afficher ces images, comment les modifier, éventuellement pixel, par pixel et comment les sauvegarder ensuite.

1. Bitmap en mémoire

Une bitmap, littéralement plan ou surface de bits, sert au codage d’une image en mémoire. Le principe est celui d’un tableau d’octets à deux dimensions, un tableau d’unsigned char. Chaque position du tableau correspond à un pixel de l’image et sa valeur code sa couleur.

En 8 bits, dont l’utilisation est de plus en plus rare, la valeur correspond à un indice dans un tableau de 256 couleurs RGB appelé une palette (comme la palette du peintre). En 15, 16, 24 et 32 bits, la valeur du pixel est décomposée en trois sous-valeurs : une pour le rouge, une pour le vert, une pour le bleu. En 32 bits, il y a en plus une valeur de transparence. Chacune de ces sous-valeurs correspond à un nombre de bits.

Par exemple, pour la couleur 16 bits dans l’ancienne version 4 d’Allegro, chaque couleur est codée sur un unsigned short (2 octets) décomposé en 5 bits pour le rouge, 6 bits pour le vert et 5 bits pour le bleu. Actuellement, la couleur est pratiquement toujours codée en 32 bits avec un octet par composante de couleur et un octet pour la transparence.

Il y a deux grands types de bitmaps en mémoire : les bitmaps qui utilisent la RAM, désignées sous le terme de "bitmaps mémoire", et les bitmaps de mémoire vidéo, qui utilisent la mémoire de la carte vidéo. En général, les opérations de dessin et tous les traitements directement en mémoire RAM sont plus rapides. Pour cette raison, il est souvent préférable de faire ses opérations graphiques avec des bitmaps mémoire et d’afficher ensuite ou au fur et à mesure les résultats à l’écran....

Événements

Ce que l’on appelle "événement" dans un programme est en général une action sur quelque chose produite par l’utilisateur du programme : par exemple, bouger la souris, cliquer sur un bouton de la souris, enfoncer une touche du clavier, laisser remonter une touche appuyée, manœuvrer un joystick, redimensionner une fenêtre, etc.

Le programme répond à certaines de ces actions, pas nécessairement à toutes. Par exemple, il peut répondre au clavier sans se préoccuper de la souris ou l’inverse, et nous n’avons jamais utilisé le joystick jusqu’à maintenant. C’est pourquoi au départ il faut indiquer au programme les événements qu’il contrôle ; ensuite, comment le programme capture ces événements ; et, pour finir, associer à chacun d’eux une réponse, à savoir l’action correspondante. Par exemple, si la touche [Echap] est appuyée le programme quitte, ou si on appuie sur une touche flèche le personnage avance, ou encore s’il y a clic sur tel bouton l’action prévue est lancée, etc.

1. Mettre en place une boucle d’événements

Les événements sont stockés dans le programme au fur et à mesure qu’ils arrivent dans une file d’événements. Sous Allegro 5, cette file peut contenir des événements de différentes natures concernant le clavier, la souris, un ou plusieurs joysticks, un ou plusieurs minuteurs, une ou plusieurs fenêtres. Il est possible également d’obtenir des événements créés par l’utilisateur. Chaque nouvel événement détecté s’ajoute dans la file et Allegro propose différentes modalités pour l’attente et la capture des événements :

  • Attente bloquante d’un événement : le programme reste en attente d’un événement et rien ne se passe tant qu’il n’y a pas d’événement.

  • Attente non bloquante chronométrée : si aucun événement n’arrive durant un laps de temps déterminé, l’attente est levée et la suite...

Animation, sprites

1. Introduction

"Sprite" possède plusieurs traductions en français, dont lutins et farfadets. En programmation de jeux, c’est une petite image représentant un personnage, un élément fixe ou mobile dans le jeu. Souvent, il désigne une petite séquence d’animation composée d’un ensemble d’images formant un mini dessin animé, un personnage qui se déplace en marchant, un personnage qui tire au revolver, une figure de combat en arts martiaux, un monstre qui vole, une explosion, etc. Dans la suite de ce chapitre, nous conserverons le terme de sprite sans traduction en français.

2. Un personnage marchant sur place

Pour tester les sprites, nous allons reprendre un ancien exemple de la librairie Allegro : un personnage qui marche sur place. En voici les images :

images/13ri25_im4a.png

Comme nous avons besoin d’images, nous devons inclure la librairie du module spécialisé pour les images :

#include <allegro5/allegro_image.h> 

et sans oublier de l’initialiser dans le main() :

if(!al_init_image_addon())  
    erreur("al_init_image_addon()"); 

Ensuite, le premier point est de récupérer les images de l’animation. Elles sont stockées dans un tableau de pointeurs bitmap assorti d’une constante qui conserve le nombre des bitmaps :

#define NBIMAGES 10 
ALLEGRO_BITMAP* anim[NBIMAGES]; 

Chaque image de l’animation est sur un fichier .bmp à part et l’ensemble est dans un dossier nommé "personnage". La récupération des images est simplifiée si les images portent toutes le même nom avec juste un numéro pour les différencier. Nous avons nommé nos images pers0.bmp, pers1.bmp, pers2.bmp, etc. jusqu’à pers9.bmp. De la sorte, toutes les images de l’animation peuvent être récupérées dans une boucle. L’indice donne le numéro de l’image et le nom complet est reconstitué avec la fonction standard sprintf(). Rappelons que sprintf() fonctionne comme un printf() mais, à la différence de printf(), elle sort une chaîne de caractères dans un tableau de char et non dans la fenêtre console. Notons également que sprintf() est dans stdio.h et qu’il faut inclure...

Modèle de jeu simple

1. Introduction

Voici une base pour la création de jeux d’arcade du type action. Typiquement, une "chose" est déplacée par le joueur avec les flèches du clavier et cette chose doit utiliser contre des ennemis mortels essentiellement des armes de jet : lancés de casseroles, de pommes pourries, de sorts magiques, tirs d’armes à feu, bombes nucléaires... selon l’état d’esprit au moment de la conception.

La maquette est un semblant de scroll horizontal minimaliste. Un vaisseau s’avance de la gauche vers la droite. Des ennemis surgissent à droite et tentent de lui barrer la route. Toute collision détruit le vaisseau, le vaisseau doit les abattre pour continuer et survivre. Nous allons procéder par étape : 1) le joueur seul se déplace, 2) le joueur lance des missiles, 3) des ennemis arrivent, 4) le joueur peut détruire les ennemis. Le code sera ajouté au fur et à mesure.

Le programme résultant est indépendant de toute histoire, il est en quelque sorte tout nu ou réduit à l’essentiel, comme un standard de jazz (morceau de musique fait pour être toujours recréé par des interprétations nouvelles). C’est une bonne base de départ pour l’approche de nombreux jeux. Vous pouvez passer d’un scroll horizontal à un scroll vertical, voire à pas de scroll du tout juste en modifiant les déplacements du joueur et des ennemis ainsi que leur mode d’apparition.

2. Le vaisseau

a. Mouvements du vaisseau

Nous avons un vaisseau et il réagit aux flèches du clavier, comme le rectangle expérimenté dans la section Événements, sauf que cette fois son déplacement est contraint visuellement à aller de la gauche vers la droite. Première question : de quoi est constitué le vaisseau ?

b. Structure de données du vaisseau

Que fait le vaisseau ? Il se déplace, donc il a une position et une vitesse. Il est visible, donc il a une taille et une image. Il marque des points et il peut mourir, donc il conserve un score et un indicateur de son état.

Ainsi, nous avons : une position, un pas de déplacement qui définit aussi sa vitesse, une taille horizontale et verticale, éventuellement...