Les entrées utilisateur sous Allegro

Un article de Mangue.org, l'encyclopéde libre.


Actuellement, nous savons afficher sprites et dessins à l'écran. Mais cela ne suffit bien evidemment pas dans un jeu, il nous faut aussi permettre aux utilisateurs d'influencer le déroulement du jeu, par des entrées au clavier ou à la souris. Nous allons donc voir comment utiliser ces trois périphériques.


Sommaire

Le Clavier - première partie

Dans la programmation de jeux, le périphériques d'éntrée le plus utilisé est bien sûr le clavier. Allegro permet d'utiliser facilement le clavier, comme illustré dans cet exemple :

install_keyboard();
 
if(keypressed())
{
	int touche=readkey();
	if(touche>>8 == KEY_UP) { /*executer le code correspondant*/ }
	if(touche>>8 == KEY_DOWN) { /*executer le code correspondant*/ }
	if(touche>>8 == KEY_LEFT) { /*executer le code correspondant*/ }
	if(touche>>8 == KEY_ESC) { /*executer le code correspondant*/ }
}

Pour utiliser le clavier dans un programme Allegro, il ne faut surtout pas oublier d'appeller la fonction install_keyboard() au début du programme, pour ainsi initialiser le gestionnaire de clavier d'Allegro.

La fonction keypressed() permet de savoir si une touche est pressée. Ainsi, celle-ci renvoie true si une touche est enfoncée, ou bien false si aucune touche n'est enfoncée.

Dans Allegro, les touches du clavier sont repérées par ce qui est appellé le scancode. Le scancode d'une touche est un numéro attribué par Allegro à cette touche du clavier pour pouvoir la repérer plus facilement. Or, il n'est pas facile pour le programmeur de se rappeller de tous les scancodes. Donc Allegro définit un certain nombre de constantes qui permettent de remplacer les scancodes "numériques". Ainsi, voici la liste des scancodes d'allegro (ceux-ci sont assez explicites pour pouvoir se passer d'explications) :

KEY_A ... KEY_Z,
KEY_0 ... KEY_9,
KEY_0_PAD ... KEY_9_PAD,
KEY_F1 ... KEY_F12,
 
KEY_ESC, KEY_TILDE, KEY_MINUS, KEY_EQUALS,
KEY_BACKSPACE, KEY_TAB, KEY_OPENBRACE, KEY_CLOSEBRACE,
KEY_ENTER, KEY_COLON, KEY_QUOTE, KEY_BACKSLASH,
KEY_BACKSLASH2, KEY_COMMA, KEY_STOP, KEY_SLASH,
KEY_SPACE,
 
KEY_INSERT, KEY_DEL, KEY_HOME, KEY_END, KEY_PGUP,
KEY_PGDN, KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN,
 
KEY_SLASH_PAD, KEY_ASTERISK, KEY_MINUS_PAD,
KEY_PLUS_PAD, KEY_DEL_PAD, KEY_ENTER_PAD,
 
KEY_PRTSCR, KEY_PAUSE,
KEY_ABNT_C1, KEY_YEN, KEY_KANA, KEY_CONVERT, KEY_NOCONVERT,
KEY_AT, KEY_CIRCUMFLEX, KEY_COLON2, KEY_KANJI,
 
KEY_LSHIFT, KEY_RSHIFT,
KEY_LCONTROL, KEY_RCONTROL,
KEY_ALT, KEY_ALTGR,
KEY_LWIN, KEY_RWIN, KEY_MENU,
KEY_SCRLOCK, KEY_NUMLOCK, KEY_CAPSLOCK

Après ces quelques explications, ils ne nous reste plus qu'une fonction à voir pour comprendre l'exemple précèdent, et ainsi maîtriser l'entrée utilisateur par le clavier. Cette fonction est la fonction readkey. Cette fonction attend que l'on appuie sur une touche, et renvoie une référence vers cette touche, qui peut être soit le scancode de la touche appuyée, soit son code ASCII, ou bien encore le rang de la touche dans l'alphabet, comme illustré ici :

// (readkey() & 0xff) renvoie le code ASCII de la touche appuyée
// ici le code est exécuté lorsque l'utilisateur appuie sur la touche d
if ((readkey() & 0xff) == 'd')
	//Code à exécuter
 
// (readkey() >> 8) renvoie le SCANCODE de la touche appuyée
// ici le code est exécuté lorsque l'utilisateur appuie sur la touche ECHAP
if ((readkey() >> 8) == KEY_ESC)
	//Code à exécuter
 
// (readkey() & 0xff) renvoie la position de la lettre préssée si l'utilisateur appuie en même temps sur Ctrl
// ici le code est exécuté lorsque l'utilisateur appuie sur la combinaison Ctrl+c
if ((readkey() & 0xff) == 3)
	//Code à exécuter
 
// ici le code est exécuté lorsque l'utilisateur appuie sur la combinaison Alt+F1
if (readkey() == (KEY_F1 << 8))
	//Code à exécuter
Astuce
Lorsque l'on appuie sur une touche, cet appuie est stocké dans ce qui est appellé le tampon (buffer en anglais). Ainsi, readkey lit directement dans le tampon pour savoir si une touche est appuyée. Or, ce tampon ne s'efface pas automatiquement, il faut donc appeller la fonction clear_keybuf() dans le programme pour qu'un appuie sur une touche ne soit pas détecté plusieurs fois par readkey().
Danger
N'oubliez jamais qu'Allegro utilise le clavier QWERTY !


Le Clavier - seconde partie

Tout de même, la technique de lecture du clavier décrite ci-dessus posséde un inconvénient : sa lenteur relative. Ainsi, Allegro propose une autre technique de lecture du clavier, plus rapide, et qui est donc à préférer pour la boucle principale du jeu.

Allegro propose un tableau dans lequel est stocké l'état de chacune des touches. Ce tableau est key[SCANCODE], où SCANCODE représente l'un des scancodes listés ci-dessus. Par exemple, pour savoir si l'utilisateur presse la touche fléche droite du pavé directionnel, il suffit de faire cela :

if(key[KEY_RIGHT]) { /*Code à exécuter*/ }

Par contre, par opposition à la technique précèdente, dans ce cas là l'état des touches n'est pas stocké dans le tampon mais dans un tableau. Donc au lieu de vider le tampon au moyen de la fonction clear_keybuf(), il faudra écrire une fonction maison pour réinitialiser l'état des touches. Voici cette fonction :

//Met chaque entrée du tableau key[] à 0
for(int i=0;i<128;i++) key[i]=0;

Voilà maintenant un exemple complet qui montre en action les deux façons de sondage du clavier :

#include <allegro.h>
 
BITMAP* buffer;
 
void vide_tableau_key()
{
	int i;
	for(i=0;i<128;i++)
		key[i]=0;
}
 
int main()
{
	//Initialisations
	install_allegro(SYSTEM_AUTODETECT,&errno,atexit);
	install_keyboard();
	set_color_depth(16);
	if(set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) < 0)
	{
		set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
		allegro_message("This program can not be initialized\n");
		exit(1);
	}
 
	//Crée le bitmap
	buffer=create_bitmap(640,480);
 
	//Clavier - premiére partie
	//Execute la boucle tant que la touche echap n'est pas appuyée
	while(!key[KEY_ESC])
	{
		//Efface 'buffer'
		clear_bitmap(buffer);
 
		textout_ex(buffer,font,"Gestion clavier - premiere partie - appuyez sur A ou Ctrl+A ou Alt+A",10,10, makecol(255,255,255), -1);
		
		if(keypressed())
		{
			//Variable dans laquelle est stockée le résultat de readkey()
			int touche=readkey();
			//Test si la touche A est enfoncée (clavier en QWERTY)
			if((touche & 0xff) == 'q')
				textprintf_ex(buffer,font,10,40,makecol(255,255,255),-1, "Vous appuyez sur : 'A'");
			//Test si la combinaison Ctrl+A est pressée
			if((touche & 0xff) == 17)
				textprintf_ex(buffer,font,10,80,makecol(255,255,255),-1,"Vous appuyez sur : Ctrl+A");
			//Test si la combinaison Alt+A est pressée
			if(touche == KEY_Q<<8)
				textprintf_ex(buffer,font,10,120,makecol(255,255,255),-1,"Vous appuyez sur : Alt+A");
		}
 
		//Affiche buffer à l'écran
		blit(buffer,screen,0,0,0,0,640,480);
	}
	//Vide la tableau key[]
	//Si l'on n'appelle pas cette fonction, le seconde boucle while n'est pas exécutée
	vide_tableau_key();
	//Clavier - seconde partie
	//Execute la boucle tant que la touche echap n'est pas appuyée
	while(!key[KEY_ESC])
	{
		//Efface 'buffer'
		clear_bitmap(buffer);
		textout_ex(buffer,font,"Gestion clavier - seconde partie - appuyez sur A",10,10,makecol(255,255,255),-1);
		if(key[KEY_Q])
			textprintf(buffer,font,10,40,makecol(255,255,255),"Vous appuyez sur : 'A'");
 
		//Affiche buffer à l'écran
		blit(buffer,screen,0,0,0,0,640,480);
	}
 
	return 0;
}
END_OF_MAIN();


Interroger le clavier

En temps normal, Allegro lit l'entrée clavier automatiquement de maniére asynchrone. Malheureusement, sur certaines plate-formes, ce fonctionnement n'est pas rendu possible, et c'est donc au programme d'interroger explicitement l'entrée clavier. Pour cela, il nous faut utiliser la fonction poll_keyboard(), qui met à jour les variables relatives au clavier. Allegro fournit d'ailleurs la fonction keyboard_needs_poll() qui renvoie 0 si l'utilisation de la fonction poll_keyboard() est inutile, ou sinon 1. Il est aussi à noter que seul l'accés au clavier par le tableau key[] necessite de prendre en compte l'interrogation du clavier, car la fonction readkey() appelle poll_keyboard() d'elle même.


La souris

Comme pour le clavier (et comme tout module d'Allegro), la premiére chose à faire est d'initialiser le gestionnaire de souris en appellant la fonction install_mouse().

Le plus dur est pratiquement fait. Maintenant il ne nous reste plus qu'à voir les variables suivantes pour être capable d'utiliser la souris :

  • mouse_x : cette variable contient la position de la souris sur x
  • mouse_y : cette variable contient la position de la souris sur y
  • mouse_b : cette variable contient l'état des boutons de la souris
  • mouse_pos : cette variable contient la coordonnée x en partie haute et la coordonnée y en partie basse

Après cela, il ne reste plus que quelques fonctions secondaires à connaître pour parachever cet enseignement :

  • show_mouse(bitmap) : affiche la souris sur le bitmap 'bitmap' (pour l'effacer, appellez show_mouse(null))
  • position_mouse(x,y) : affiche le pointeur de la souris au point (x;y)
  • set_mouse_range(x1,y1,x2,y2) : définit la zone de la souris sur le bitmap, dont celle-ci ne pourra pas sortir
  • set_mouse_sprite(sprite) : définit le bitmap 'sprite' comme pointeur de la souris
  • set_mouse_sprite_focus(x,y) : définit le point du pointeur qui représente les coordonnées x et y de la souris

Voilà, nous savons utiliser la souris dans nos programmes. Voici un petit exemple d'utilisation de la souris :

#include <allegro.h>
 
BITMAP* buffer;
BITMAP* mouse;
 
int main()
{
	//Initialisations
	install_allegro(SYSTEM_AUTODETECT,&errno,atexit);
	install_keyboard();
	install_mouse();
	set_color_depth(16);
	if(set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0)<0)
	{
		set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
		allegro_message("This program can not be initialized\n");
		exit(1);
	}
 
	//Crée les deux bitmaps
	buffer=create_bitmap(640,480);
	mouse=create_bitmap(12,12);
	//dessine le pointeur
	clear_to_color(mouse,makecol(255,0,255));
	circle(mouse,6,6,5,makecol(255,0,0));
	putpixel(mouse,6,6,makecol(240,0,0));
	
	//Met comme curseur le bitmap 'mouse'
	set_mouse_sprite(mouse);
	//Définit comme point 'actif' le point central du pointeur
	set_mouse_sprite_focus(6,6);
	//Ordonne à la souris de ne pas sortir de la zone grise
	set_mouse_range(100,100,539,379);
	//Met la souris au centre de l'écran
	position_mouse(320,240);
 
	//Execute la boucle tant que la touche echap n'est pas appuyée
	while(!key[KEY_ESC])
	{
		//Efface 'buffer'
		clear_bitmap(buffer);
		//Dessine la zone grise
		rectfill(buffer,100,100,539,379,makecol(128,128,128));
 
		//Dessine un bouton
		rectfill(buffer,240,230,400,250,makecol(192,192,255));
		textout_centre(buffer,font,"Click here !",320,240,makecol(0,0,250));
 
		//Vérifie si le pointeur est au dessus du bouton
		if(mouse_x>240 && mouse_x<400 && mouse_y>230 && mouse_y<250)
		{
			textout_ex(buffer,font,"La souris est au dessus du bouton",10,10,makecol(255,255,255),-1);
			//Vérifie si le bouton gauche est appuyé
			if(mouse_b & 1)
				textout(buffer,font,"Vous etes vraiment naif !",10,30,makecol(255,255,255),-1);
			//Vérifie si le bouton droit est appuyé
			if(mouse_b & 2)
				textout(buffer,font,"Pas avec le bouton droit !",10,30,makecol(255,255,255),-1);
		}
 
		//Affiche la souris sur le bitmap 'buffer'
		show_mouse(buffer);
		//Affiche buffer à l'écran
		blit(buffer,screen,0,0,0,0,640,480);
	}
 
	return 0;
}
END_OF_MAIN();


Interrogation de la souris

La lecture de l'état de la souris est géré par Allegro de la même maniére que la lecture du clavier, ainsi sur certaines plate-formes, il faudra au programmeur appeller la fonction poll_mouse(), qui fonctionne de la même façon que poll_keyboard. De même, Allegro fournit la fonction mouse_needs_poll(), qui posséde les même caractéristiques que son homologue keyboard_needs_poll().

Outils personels