III. Premier pas▲
III-A. Introduction▲
Les premiers pas que nous proposons consistent à disposer rapidement d'une application en mode fenêtre ou en plein écran capable de capturer le clavier et la souris. Dans notre optique d'exploration, nous en profitons pour expérimenter les fonctions de redimensionnement et de positionnement d'une fenêtre avec les différentes possibilités de plein écran et la capture des résolutions supportées.
Compte tenu du nombre relativement important d'informations nécessaires pour commencer un programme, nous proposons également de réaliser un modèle d'application (template) qui nous évitera d'avoir à tout reprendre pour chaque nouvelle création.
Pour finir, nous apportons quelques précisions d'une part pour un meilleur contrôle du clavier et de la souris et d'autre part pour l'utilisation de la fenêtre console. Allegro dispose en effet d'une fenêtre console native et donc multiplateforme qu'il peut être intéressant d'utiliser en alternative à la console du système.
III-B. Créer une fenêtre▲
Créez un nouveau projet et répétez les opérations vues au chapitre Installation de la bibliothèque Allegro : créer un projet, spécifier les chemins d'accès aux dossiers include et lib de la bibliothèque, relier au projet les modules qui sont utilisés.
Ensuite le code de départ est le suivant :
#include <stdlib.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
// fonction contrôle d'erreur
void
erreur
(
const
char
*
txt)
{
ALLEGRO_DISPLAY*
d;
d=
al_is_system_installed
(
)?al_get_current_display
(
):NULL
;
al_show_native_message_box
(
d,"
ERREUR
"
,txt,NULL
,NULL
,0
);
exit
(
EXIT_FAILURE);
}
/**
***********************************************************
************************************************************
*/
int
main
(
)
{
// pour obtenir une fenêtre
ALLEGRO_DISPLAY *
display;
// 1) initialisation Allegro obligatoire
if
(!
al_init
(
))
erreur
(
"
al_init()
"
);
// 2) créer sa fenêtre
display=
al_create_display
(
800
,600
);
if
(!
display)
erreur
(
"
creation display
"
);
//donner un nom à sa fenêtre
al_set_window_title
(
display, "
Premier programme !
"
);
// petit test : colorer la fenêtre en rouge
al_clear_to_color
(
al_map_rgb
(
255
,0
,0
));
// pour rendre visibles toutes les opérations de dessin ou
// d'affichage il faut basculer le double buffer à l'écran.
// En effet tous les affichages sont faits d'abord dans un
// double buffer, c'est-à-dire une image en mémoire
// invisible à l'écran
al_flip_display
(
);
// temps d'attente en secondes
al_rest
(
5
.0
);
// libérer la mémoire allouée pour la fenêtre
al_destroy_display
(
display);
return
0
;
}
/**
***********************************************************
************************************************************
*/
La structure de données pour obtenir une fenêtre est :
ALLEGRO_DISPLAY *
display ;
L'initialisation de la fenêtre se fait avec la fonction create_display() . Elle prend en paramètre la taille que l'on veut lui donner et retourne un pointeur ALLEGRO_DISPLAY* correctement alloué et NULL sinon :
ALLEGRO_DISPLAY*
al_create_display
(
int
w, int
h)
Nous pouvons lui donner un nom avec la fonction :
void
al_set_window_title
(
ALLEGRO_DISPLAY*
display, const
char
*
title)
Pour tester l'affichage, nous changeons la couleur du fond de la fenêtre avec un appel à la fonction :
void
al_clear_to_color
(
ALLEGRO_COLOR color)
Cette fonction prend une couleur en paramètre. Une couleur est une structure ALLEGRO_COLOR et la fonction :
ALLEGRO_COLOR al_map_rgb
(
unsigned
char
r, // pour le rouge
unsigned
char
g, // pour le vert
unsigned
char
b) // pour le bleu
retourne une couleur initialisée avec une valeur de rouge, de vert, de bleu comprise chacune entre 0 et 255 maximum.
La couleur définie dans l'appel de al_map_rgb(255,0,0) est maximum de rouge, la couleur retournée au paramètre de la fonction al_clear_to_color() est donc rouge vif.
Ensuite, très important, il y a un appel à la fonction :
void
al_flip_display
(
void
)
Cette fonction permet l'affichage à l'écran du double buffer. Le double buffer est une image en mémoire de la taille de l'écran dans laquelle sont faites d'abord toutes les opérations graphiques d'affichage ou de dessin. Une fois ces opérations terminées, pour en voir le résultat il faut les afficher à l'écran, c'est le rôle de cette fonction : elle recopie le double buffer à l'écran (ou opère une bascule double buffer écran).
Nous avons modifié la fonction de contrôle d'erreur parce qu'à partir du moment où il y a des fenêtres dans le programme il est préférable de récupérer le display courant pour la fenêtre message surtout en cas de plein écran (Fullscreen). Sinon elle reste cachée derrière et impossible à atteindre. Elle bloque alors le programme parce qu'on ne peut pas cliquer sur ok pour la fermer.
III-C. Obtenir le clavier▲
Le clavier est en général géré avec une boucle d'événements mais il y a un moyen rapide et simple de pouvoir en disposer.
D'abord appeler la fonction d'initialisation :
bool al_install_keyboard
(
void
)
Cette fonction retourne true sur succès et false sur échec. Ensuite, déclarer une structure d'état du clavier :
ALLEGRO_KEYBOARD_STATE key;
L'état du clavier y est stocké après chaque appel à la fonction :
void
al_get_keyboard_state
(
ALLEGRO_KEYBOARD_STATE *
ret_state)
Cette fonction retourne dûment complétée la structure passée en paramètre par référence (adresse mémoire). Et pour savoir si une touche a été pressée, il faut utiliser la fonction :
al_key_down
(
const
ALLEGRO_KEYBOARD_STATE *
state, int
keycode)
Elle prend en paramètre la structure d'état du clavier passée par référence et une macro constante qui définit une touche du clavier. Pour chaque touche du clavier, il y a une macro constante qui lui correspond ( #define ), le nom de chaque touche commence par le préfixe ALLEGRO_KEY_ puis est ajouté NOMDELATOUCHE , voici les plus importantes :
ALLEGRO_KEY_A … ALLEGRO_KEY_Z |
A à Z |
ALLEGRO_KEY_0 … ALLEGRO_KEY_9 |
0 à 9 |
ALLEGRO_KEY_PAD_0 … ALLEGRO_KEY_PAD_9 |
0 à 9 (pavé numérique) |
ALLEGRO_KEY_F1 … ALLEGRO_KEY_F12 |
F1 à F12 |
ALLEGRO_KEY_ESCAPE |
Échap |
ALLEGRO_KEY_MINUS |
Signe - |
ALLEGRO_KEY_EQUALS |
Signe = |
ALLEGRO_KEY_BACKSPACE |
Retour arrière |
ALLEGRO_KEY_TAB |
Tabulation |
ALLEGRO_KEY_ENTER |
Entrée |
ALLEGRO_KEY_DELETE |
Suppression |
ALLEGRO_KEY_LEFT |
Flèche vers gauche |
ALLEGRO_KEY_RIGHT |
Flèche vers droite |
ALLEGRO_KEY_UP |
Flèche vers haut |
ALLEGRO_KEY_DOWN |
Flèche vers bas |
… |
… |
La liste complète se trouve dans la documentation Allegro consultable en ligne : http://alleg.sourceforge.net/a5docs/5.0.10/
La fonction al_key_down() retourne true si la touche est appuyée et false sinon. Exemple de mise en place :
#include <stdlib.h>
#include <time.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
void
erreur
(
const
char
*
txt)
{
ALLEGRO_DISPLAY*
d;
d=
al_is_system_installed
(
)?al_get_current_display
(
):NULL
;
al_show_native_message_box
(
d,"
ERREUR
"
,txt,NULL
,NULL
,0
);
exit
(
EXIT_FAILURE);
}
/**
***********************************************************
************************************************************
*/
int
main
(
)
{
ALLEGRO_DISPLAY*
display;
ALLEGRO_KEYBOARD_STATE key; // clavier simple
int
fin=
0
;
srand
(
time
(
NULL
));
if
(!
al_init
(
))
erreur
(
"
al_init()
"
);
display=
al_create_display
(
800
,600
);
if
(!
display)
erreur
(
"
create_display(800,600)
"
);
// pour utiliser le clavier
if
(!
al_install_keyboard
(
))
erreur
(
"
al_install_keyboard()
"
);
while
(!
fin){
// récupération de l'état du clavier
al_get_keyboard_state
(&
key);
// si touche [Echap] appuyée fin boucle et quitter
if
(
al_key_down
(&
key,ALLEGRO_KEY_ESCAPE))
fin=
1
;
// si [Entrée] changer de couleur
if
(
al_key_down
(&
key,ALLEGRO_KEY_ENTER))
al_clear_to_color
(
al_map_rgb
(
rand
(
)%
256
,rand
(
)%
256
,rand
(
)%
256
));
al_flip_display
(
);
}
al_destroy_display
(
display);
return
0
;
}
Si l'utilisateur presse [Entrée], la fenêtre change de couleur. Si vous avez le programme sous les yeux, vous pouvez remarquer qu'en fait elle change plusieurs fois de couleur. En effet, un appui sur une touche, même très bref, correspond à plusieurs centaines de boucles et de passages dans le if de la touche [Entrée]. Nous donnons une solution pour contrôler cela à la fin de ce chapitre.
Disons que cette technique de récupération de l'état du clavier est pratique et aisée à mettre en œuvre. Mais pour des projets importants, il est préférable d'utiliser une boucle d'événement avec un minuteur (timer) qui rythme l'exécution des tâches (événements et boucles d'événements sont présentés dans un chapitre à part).
III-D. Obtenir la souris▲
Le même principe existe pour gérer rapidement la souris, sans être obligé d'installer une boucle d'événements.
Première chose, appeler la fonction d'initialisation :
bool al_install_mouse
(
void
)
Cette fonction retourne true sur succès et false sur échec. Ensuite, déclarer une structure d'état de la souris :
ALLEGRO_MOUSE_STATE mouse;
L'état de la souris (position, clic) y est stocké après chaque appel de la fonction :
void
al_get_mouse_state
(
ALLEGRO_MOUSE_STATE *
ret_state)
Cette fonction retourne dûment complétée la structure passée en paramètre par référence (adresse mémoire). Pour connaître la position de la souris, il suffit d'accéder aux champs x et y de la structure :
// position de la souris stockée dans masouris.x et masouris.y
Un champ de bits stocke en une seule variable, la variable buttons, l'état de tous les boutons de la souris. Chaque bit du champ buttons correspond à un bouton et s'il est à un c'est que le bouton est pressé. Pour connaître l'état de chaque bit on utilise l'opérateur bit à bit & (ET). Pour mémoire :
i & 1 donne i (si i vaut 1 ça fait 1 et si i vaut 0 ça fait 0)
i & 0 donne 0
Ensuite, pour accéder à chaque bit séparément, on utilise un masque. Un masque est une variable ou une constante avec sur 0 tous les bits destinés à ne pas être lus et sur 1 tous les bits destinés à être lus. Par exemple :
masque est une valeur entière :
si masque = 1 // en mémoire ...00000001
si masque = 2 // en mémoire ...00000010
si masque = 4 // en mémoire ...00000100
si masque = 8 // en mémoire ...00001000
etc.
Ici masque est toujours une puissance de deux : 2⁰ , 2¹ , 2² , 2³ , 2⁴, etc.
Alors pour connaître l'état d'un bouton ce sont les expressions :
masouris.buttons &
1
// état du bouton gauche
masouris.buttons &
2
// état du bouton droit
masouris.buttons &
4
// état du bouton du milieu
Exemple de mise en œuvre :
#include <stdio.h>
#include <time.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
void
erreur
(
const
char
*
txt)
{
ALLEGRO_DISPLAY*
d;
d =
al_is_system_installed
(
) ? al_get_current_display
(
) : NULL
;
al_show_native_message_box
(
d, "
ERREUR
"
, txt, NULL
, NULL
, 0
);
exit
(
EXIT_FAILURE);
}
/**
***********************************************************
************************************************************
*/
int
main
(
)
{
ALLEGRO_DISPLAY*
display;
ALLEGRO_MOUSE_STATE mouse; // souris simple
int
fin =
0
, oldx =
0
, oldy =
0
;
srand
(
time
(
NULL
));
if
(!
al_init
(
))
erreur
(
"
al_init()
"
);
display =
al_create_display
(
800
, 600
);
if
(!
display)
erreur
(
"
create_display(800,600)
"
);
// pour utiliser la souris
if
(!
al_install_mouse
(
))
erreur
(
"
al_install_mouse()
"
);
while
(!
fin){
// récupération de l'état de la souris
al_get_mouse_state
(&
mouse);
// si mouvement afficher position dans console
if
(
oldx !=
mouse.x ||
oldy !=
mouse.y){
oldx =
mouse.x;
oldy =
mouse.y;
printf
(
"
%d-%d
\n
"
, mouse.x, mouse.y);
}
// si clic gauche changer couleur fenêtre
if
(
mouse.buttons &
1
)
al_clear_to_color
(
al_map_rgb
(
rand
(
) %
256
,
rand
(
) %
256
,
rand
(
) %
256
));
// si clic droit quitter
if
(
mouse.buttons &
2
)
fin =
1
;
al_flip_display
(
);
}
al_destroy_display
(
display);
return
0
;
}
Mais pour ceux qui préfèrent, il y a une fonction qui permet d'obtenir le même résultat :
bool al_mouse_button_down
(
const
ALLEGRO_MOUSE_STATE *
state, int
button)
Cette fonction prend au premier paramètre state une structure d'état de la souris passée par référence. Elle retourne true si le bouton dont le numéro est passé au paramètre button est cliqué et false sinon. Attention les boutons sont numérotés à partir de 1 (et non de 0 comme souvent).
III-E. Éléments de gestion des fenêtres▲
Dans la documentation, la rubrique Displays donne toutes les fonctions disponibles qui permettent d'agir sur une fenêtre. Pour une fenêtre on y trouve :
- les éléments liés à sa création,
- des opérations en relation avec l'affichage dans la fenêtre,
- la possibilité de modifier sa taille et sa position,
- des paramétrages divers comme l'affichage d'un nom et d'une ou de plusieurs icônes, la possibilité de bloquer la mise en veille.
Pour commencer, nous allons tester ce qui a trait à la taille et à la position de la fenêtre. Le plein écran fera l'objet d'une prochaine section.
III-E-1. Dimensionner une fenêtre existante et la positionner à l'écran▲
Voici la liste des fonctions dont nous disposons.
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 , la nouvelle hauteur height . Elle retourne vrai si succès.
La fonction al_get_display_width :
int
al_get_display_width
(
ALLEGRO_DISPLAY *
display)
Retourne la largeur de la fenêtre. Elle prend en paramètre la fenêtre display .
La fonction al_get_display_height :
int
al_get_display_height
(
ALLEGRO_DISPLAY *
display)
Retourne la hauteur de la fenêtre. Elle 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)
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)
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.
Dans le test suivant, nous expérimentons ces fonctions. Dans une boucle sont répétées dix fois de suite dans l'ordre les opérations suivantes :
- Déterminer une taille aléatoire pour la fenêtre.
Si cette taille est acceptable elle est assignée à la fenêtre et :
- La fenêtre est déplacée à une position aléatoire dans l'écran.
- Sa couleur est changée.
- Elle est affichée (bascule al_flip_display du double buffer à l'écran).
- Une fenêtre de dialogue donne ses valeurs de taille et de position.
#include <stdio.h>
#include <time.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
void
erreur
(
const
char
*
txt)
{
ALLEGRO_DISPLAY*
d;
d=
al_is_system_installed
(
)?al_get_current_display
(
):NULL
;
al_show_native_message_box
(
d,"
ERREUR
"
,txt,NULL
,NULL
,0
);
exit
(
EXIT_FAILURE);
}
// une fonction avec chaîne formatée et liste variable de
// paramètres comme printf
void
message
(
const
char
*
format,...)
{
ALLEGRO_DISPLAY*
display;
char
txt[1024
];
va_list args;
// création liste de param
va_start
(
args,format);
// compose la chaîne selon les paramètres et la récupère
// dans le tableau de char txt
vsnprintf
(
txt,sizeof
(
txt),format,args);
// supprime la liste créée
va_end
(
args);
// récupère le diplay s'il existe
display =
al_is_system_installed
(
) ? al_get_current_display
(
) : NULL
;
//affiche une fenêtre de dialogue avec la chaîne
al_show_native_message_box
(
display,"
Message
"
,""
,txt,NULL
,0
);
}
/**
***********************************************************
************************************************************
*/
int
main
(
)
{
ALLEGRO_DISPLAY*
display;
int
i,res,w,h,x,y;
srand
(
time
(
NULL
));
if
(!
al_init
(
))
erreur
(
"
al_init()
"
);
// fenêtre au départ
display=
al_create_display
(
800
,600
);
if
(!
display)
erreur
(
"
create_display
"
);
// 10 fois
for
(
i=
0
; i<
10
; i++
){
// nouvelle taille aléatoire
res =
al_resize_display
(
display,// fenêtre courante
1
+
rand
(
)%
1920
, // largeur
1
+
rand
(
)%
1080
);// hauteur
// récupérer les nouvelles largeur et hauteur
w =
al_get_display_width
(
display);
h =
al_get_display_height
(
display);
// si ok
if
(
res){
// changer la position de la fenêtre
al_set_window_position
(
display,
rand
(
)%(
1920
-
w), // pos x
rand
(
)%(
1080
-
h));// pos y
// récupérer la position de la fenêtre
al_get_window_position
(
display, &
x, &
y);
// changer sa couleur
al_clear_to_color
(
al_map_rgb
(
rand
(
)%
256
,// rouge
rand
(
)%
256
,// vert
rand
(
)%
256
));// bleu
al_flip_display
(
);
// afficher sa taille et sa position
message
(
"
%4d par %4d
\n
pos : (%d,%d)
"
,w,h,x,y);
}
else
{
message
(
"
%4d par %4d : echoue
\n
"
,w,h);
exit
(
EXIT_FAILURE);
}
}
al_destroy_display
(
display);
return
0
;
}
À noter dans ce programme l'utilisation d'une fonction avec une liste variable d'arguments, c'est la fonction message qui permet à la fenêtre de dialogue d'avoir un affichage avec une chaîne formatée comme dans un printf() .
La liste d'arguments associés à la chaîne de caractères formatée est transformée en une chaîne ordinaire grâce à la fonction standard vsnprintf() :
vsnprintf
(
char
*
, int
, const
char
*
, va_list);
Cette fonction stocke la chaîne finale au paramètre p1 avec une taille maximum donnée au paramètre p2 à partir de la chaîne formatée donnée au paramètre p3 et de la liste standard d'arguments passée au paramètre p4.
Sous Visual C++ cette fonction est jugée « unsafe », ce qui provoque une erreur à la compilation et il est suggéré d'utiliser plutôt une version sécurisée non standard de Microsoft :
vsnprintf_s
(
char
*
, int
, const
char
*
, va_list);
A priori tout ce qui change à l'utilisation est le suffixe _s à ajouter à la fin.
Afin de garder son code propre et portable, tout en évitant les erreurs de compilation sous Visual C++, il est possible d'ajouter :
#define _CRT_SECURE_NO_WARNINGS
au début du code, pour désactiver la vérification de Visual C++.
III-E-2. Activer le contrôle 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. Mais l'utilisateur ne peut pas la changer en tirant sur un bord ou un coin, ni en double cliquant dans la barre de titre. 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 à 1 d'une fonctionnalité est obtenue à l'aide d'une macro constante #define spécifique qui définit le bit voulu à 1. Les macros constantes qui nous intéressent ici sont :
- ALLEGRO_WINDOWED pour spécifier un mode fenêtré.
- ALLEGRO_RESIZABLE pour indiquer une fenêtre redimensionnable (nous verrons d'autres fonctionnalités plus tard).
La réunion de ces deux propriétés s'obtient avec l'opérateur bit à bit de mise à 1 de la façon suivante :
ALLEGRO_WINDOWED |
ALLEGRO_RESIZABLE
Ainsi l'appel :
al_set_new_display_flags
(
ALLEGRO_WINDOWED |
ALLEGRO_RESIZABLE);
signifie que le bit pour mode fenêtré et le bit pour redimensionnement sont mis à 1. Ces deux propriétés sont ainsi activées lors de la création de la fenêtre qui suit. Le programme suivant permet de le constater :
#include <stdio.h>
#include <time.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
void
erreur
(
const
char
*
txt)
{
ALLEGRO_DISPLAY*
d;
d=
al_is_system_installed
(
)?al_get_current_display
(
):NULL
;
al_show_native_message_box
(
d,"
ERREUR
"
,txt,NULL
,NULL
,0
);
exit
(
EXIT_FAILURE);
}
/**
***********************************************************
************************************************************
*/
int
main
(
)
{
ALLEGRO_DISPLAY*
display;
ALLEGRO_KEYBOARD_STATE key; // clavier simple
int
fin=
0
;
srand
(
time
(
NULL
));
if
(!
al_init
(
))
erreur
(
"
al_init()
"
);
// paramétrage fonctionnalités fenêtre avant sa création
al_set_new_display_flags
(
ALLEGRO_WINDOWED |
ALLEGRO_RESIZABLE);
display=
al_create_display
(
800
,600
);
if
(!
display)
erreur
(
"
create_display(800,600)
"
);
// pour utiliser le clavier
if
(!
al_install_keyboard
(
))
erreur
(
"
al_install_keyboard()
"
);
// boucle qui laisse le temps à l'utilisateur de manipuler
// la fenêtre
while
(!
fin){
// récupération de l'état du clavier
al_get_keyboard_state
(&
key);
// si touche [Echap] appuyée fin boucle et quitter
if
(
al_key_down
(&
key,ALLEGRO_KEY_ESCAPE))
fin=
1
;
al_flip_display
(
);
}
al_destroy_display
(
display);
return
0
;
}
III-F. Gestion du plein écran▲
Pour gérer le plein écran, nous avons deux solutions : soit avoir une fenêtre qui couvre tout l'écran sans barre de contrôle en haut, soit quitter le mode fenêtré et être tout simplement en plein écran. Dans les deux cas, il s'agit d'une fonctionnalité obtenue avec la fonction :
void
al_set_new_display_flags
(
int
flags)
III-F-1. Fenêtre qui couvre tout l'écran▲
Le mode fenêtré plein écran est en principe donné par :
ALLEGRO_FULLSCREEN_WINDOWE
En effet d'après la documentation l'appel de :
al_set_new_display_flags
(
ALLEGRO_FULLSCREEN_WINDOW);
suivi de :
display=
al_create_display
(
800
,600
);
ne tient pas compte des 800x600 demandés. Il donne une fenêtre qui couvre tout l'écran selon la résolution courante, faisant disparaître et la barre de titre dans le haut de la fenêtre et la barre des tâches du bureau exactement comme si vous étiez en en mode plein écran.
Mais en réalité ce n'est pas ce qui se passe actuellement du fait semble-t-il d'une erreur pas encore corrigée. Vous obtiendrez une fenêtre sans barre de titre en haut de 800 par 600 pixels.
Le programme suivant permet de le vérifier :
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <time.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
void
erreur
(
const
char
*
txt)
{
ALLEGRO_DISPLAY*
d;
d=
al_is_system_installed
(
)?al_get_current_display
(
):NULL
;
al_show_native_message_box
(
d,"
ERREUR
"
,txt,NULL
,NULL
,0
);
exit
(
EXIT_FAILURE);
}
void
message
(
const
char
*
format,...)
{
ALLEGRO_DISPLAY*
display;
char
txt[1024
];
va_list args;
va_start
(
args,format);
vsnprintf
(
txt,sizeof
(
txt),format,args);
va_end
(
args);
display =
al_is_system_installed
(
) ?
al_get_current_display
(
) : NULL
;
al_show_native_message_box
(
display,"
Message
"
,txt,txt,NULL
,0
);
}
/**
***********************************************************
************************************************************
*/
int
main
(
)
{
ALLEGRO_DISPLAY*
display;
int
w,h;
srand
(
time
(
NULL
));
if
(!
al_init
(
))
erreur
(
"
al_init()
"
);
al_set_new_display_flags
(
ALLEGRO_FULLSCREEN_WINDOW);
// ensuite en dépit des 800x600 demandés prend automatiquement
// la résolution courante de l'écran
display=
al_create_display
(
800
,600
);
if
(!
display)
erreur
(
"
create_display
"
);
// changer sa couleur
al_clear_to_color
(
al_map_rgb
(
rand
(
)%
256
,rand
(
)%
256
,
rand
(
)%
256
));
al_flip_display
(
);
// pour récupérer la largeur et la hauteur
w =
al_get_display_width
(
display);
h =
al_get_display_height
(
display);
message
(
"
resolution : %d par %d
\n
"
,w,h);
al_rest
(
3
.0
);
al_destroy_display
(
display);
return
0
;
}
Cependant, lorsque cette erreur sera corrigée, avec ce même code vous devriez obtenir un mode plein écran. Actuellement pour obtenir une fenêtre plein écran, il faut récupérer soi-même la résolution maximale de l'écran et créer une fenêtre de cette taille :
ALLEGRO_DISPLAY_MODE rec;
al_get_display_mode
(
al_get_num_display_modes
(
) -
1
, &
rec);
al_set_new_display_flags
(
ALLEGRO_FULLSCREEN_WINDOW);
display =
al_create_display
(
rec.width, rec.height);
Il reste que la barre des tâches n'est pas masquée par la fenêtre. Elle demeure par dessus.
Par ailleurs, cette technique de récupération des résolutions possibles de la carte graphique et de l'écran et par conséquent la possibilité de trouver la résolution la plus grande sont détaillées plus loin.
III-F-2. Plein écran sans fenêtre▲
Le mode plein écran sans fenêtre est donné par :
ALLEGRO_FULLSCREEN
et l'appel de al_set_new_display_flags() avant la création de la fenêtre :
al_set_new_display_flags
(
ALLEGRO_FULLSCREEN);
III-F-2-a. Expérimentation▲
#include <stdio.h>
#include <time.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
void
erreur
(
const
char
*
txt)
{
ALLEGRO_DISPLAY*
d;
d =
al_is_system_installed
(
) ? al_get_current_display
(
) : NULL
;
al_show_native_message_box
(
d, "
ERREUR
"
, txt, NULL
, NULL
, 0
);
exit
(
EXIT_FAILURE);
}
/**
***********************************************************
************************************************************
*/
int
main
(
)
{
ALLEGRO_DISPLAY*
display;
int
w, h;
srand
(
time
(
NULL
));
if
(!
al_init
(
))
erreur
(
"
al_init()
"
);
al_set_new_display_flags
(
ALLEGRO_FULLSCREEN);
display =
al_create_display
(
320
, 200
);
if
(!
display)
erreur
(
"
create_display
"
);
// changer sa couleur
al_clear_to_color
(
al_map_rgb
(
rand
(
) %
256
, rand
(
) %
256
,
rand
(
) %
256
));
al_flip_display
(
);
// pour récupérer la largeur et la hauteur
w =
al_get_display_width
(
display);
h =
al_get_display_height
(
display);
// affiche la résolution dans la console
printf
(
"
resolution : %d par %d
\n
"
, w, h);
al_rest
(
3
.0
);
al_destroy_display
(
display);
// pour retenir la console avant fermeture
system
(
"
PAUSE
"
);
return
0
;
}
La taille passée pour la résolution, 800x600, est respectée indépendamment de la résolution courante de l'écran (ça marche même avec une résolution de 320 par 200 !). La taille des pixels est adaptée à la résolution adoptée. Par ailleurs si la fonction al_show_native_message_box() est appelée, la fenêtre de dialogue créée passe à l'arrière-plan et demeure inaccessible en quelque sorte derrière l'écran. Elle bloque alors le programme parce qu'il n'est plus possible de la fermer. C'est pourquoi nous préférons afficher la résolution dans la fenêtre console visible à la sortie du programme.
III-F-3. Résolutions supportées▲
Allegro fournit une structure :
ALLEGRO_DISPLAY_MODE
qui permet de connaître quels sont les paramètres plein écran que supporte l'ordinateur et sa carte graphique.
Cette structure est composée comme suit :
typedef
struct
ALLEGRO_DISPLAY_MODE {
int
width; // largeur de l'écran (résolution)
int
height; // hauteur de l'écran
int
format; // format de pixel du mode
int
refresh_rate; // fréquence de rafraîchissement du mode
}
ALLEGRO_DISPLAY_MODE;
Les champs width et height donnent une résolution possible, format correspond à une profondeur de couleur (8, 16, 24, 32 bits).
Le nombre total des résolutions plein écran possibles sur l'ordinateur s'obtient avec la fonction :
int
al_get_num_display_modes
(
void
)
Ensuite les caractéristiques de chaque mode sont récupérables avec la fonction :
ALLEGRO_DISPLAY_MODE *
al_get_display_mode
(
int
n, ALLEGRO_DISPLAY_MODE *
mode)
Cette fonction retourne dans la structure mode passée par référence en paramètre p2 les caractéristiques du mode numéro n donné en paramètre p1. En cas d'échec la fonction retourne NULL .
Le programme suivant commence par afficher dans la fenêtre console tous les modes plein écran possibles. Ensuite l'utilisateur peut sélectionner un mode afin d'obtenir le plein écran correspondant. Une fois installé, le plein écran reste trois secondes puis le plein écran display disparaît et nous retournons à la fenêtre console. Pour quitter, il suffit d'entrer une valeur impossible (-1 par exemple).
#include <stdio.h>
#include <time.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
void
erreur
(
const
char
*
txt)
{
ALLEGRO_DISPLAY*
d;
d=
al_is_system_installed
(
)?al_get_current_display
(
):NULL
;
al_show_native_message_box
(
d,"
ERREUR
"
,txt,NULL
,NULL
,0
);
exit
(
EXIT_FAILURE);
}
/**
***********************************************************
************************************************************
*/
int
main
(
)
{
ALLEGRO_DISPLAY*
display;
ALLEGRO_DISPLAY_MODE mode;
int
i,nbmode;
srand
(
time
(
NULL
));
if
(!
al_init
(
))
erreur
(
"
al_init()
"
);
// récupère le nombre de résolutions possibles
nbmode =
al_get_num_display_modes
(
);
printf
(
"
il y a %d résolution possibles :
\n
"
,nbmode);
for
(
i =
0
; i <
nbmode; i++
){
// récupère les informations pour chaque mode
al_get_display_mode
(
i, &
mode);
// affiche la résolution du mode courant
// dans la console
printf
(
"
mode %2d resolution %4d x %4d
"
"
%2d bits et %2d
\n
"
,
i, mode.width, mode.height,
al_get_pixel_format_bits
(
mode.format),
mode.refresh_rate);
}
// tester les résolutions
do
{
printf
(
"
entrer le numéro du mode souhaite :
\n
"
);
scanf_s
(
"
%d
"
, &
i);
rewind
(
stdin);
if
(
i >=
0
&&
i <
nbmode){
// crée un display plein écran
// dans le mode courant
al_get_display_mode
(
i, &
mode);
al_set_new_display_refresh_rate
(
mode.refresh_rate);
al_set_new_display_flags
(
ALLEGRO_FULLSCREEN);
display =
al_create_display
(
mode.width,
mode.height);
// change la couleur de la fenêtre
al_clear_to_color
(
al_map_rgb
(
rand
(
) %
256
,
rand
(
) %
256
,
rand
(
) %
256
));
// affiche et reste trois seconde
al_flip_display
(
);
al_rest
(
3
.0
);
// détruit le display courant, passe au suivant
al_destroy_display
(
display);
}
}
while
(
i >=
0
&&
i <
nbmode);
return
0
;
}
La fonction al_set_new_display_refresh_rate :
void
al_set_new_display_refresh_rate
(
int
refresh_rate)
Cette fonction sert à spécifier la fréquence de rafraîchissement dans cette situation où l'on recrée une fenêtre display à partir de celle existante et selon un nouveau mode. Il faut veiller à ce que mode et fréquence de rafraîchissement soient compatibles. Selon le mode souhaité, la fonction permet d'activer la fréquence correspondante qui doit lui être passée en paramètre.
Tous les modes trouvés sont en 32 bits pour la profondeur de couleur et il semble qu'il n'y ait plus d'autre choix actuellement. Par exemple sous Windows 7, 8, 8.1 la profondeur de couleur est obligatoirement 32 bits et non modifiable.
III-F-3-a. Obtenir la plus grande résolution ▲
Les modes sont classés des plus petites capacités graphiques vers les plus grandes. Le mode le plus complet est celui à la position :
al_get_num_display_modes
(
)-
1
La récupération de ses informations est la suivante :
#include <stdio.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
void
erreur
(
const
char
*
txt)
{
ALLEGRO_DISPLAY*
d;
d =
al_is_system_installed
(
) ? al_get_current_display
(
) : NULL
;
al_show_native_message_box
(
d, "
ERREUR
"
, txt, NULL
, NULL
, 0
);
exit
(
EXIT_FAILURE);
}
/**
***********************************************************
************************************************************
*/
int
main
(
)
{
ALLEGRO_DISPLAY_MODE mode;
int
nbmode =
0
;
if
(!
al_init
(
))
erreur
(
"
al_init()
"
);
// récupère les informations du dernier mode
nbmode =
al_get_num_display_modes
(
);
al_get_display_mode
(
nbmode -
1
, &
mode);
// affiche la résolution du mode courant dans la console
printf
(
"
mode %d resolution %4d x %4d
\n
"
, nbmode,
mode.width, mode.height);
// presser une touche pour continuer
system
(
"
PAUSE
"
);
return
0
;
}
Ensuite il est simple de créer une fenêtre de sa taille :
ALLEGRO_DISPLAY*
display;
display =
al_create_display
(
mode.width,mode.height);
III-G. Création d'un modèle de projet (template)▲
Un projet Allegro, entre édition de liens et initialisations de base, est un peu long à mettre en place. Mais Code::Blocks comme Visual Studio donnent la possibilité de réaliser des modèles de projet (template en anglais). Nous allons utiliser cette fonctionnalité pour faire un projet Allegro comprenant déjà un linkage spécifique et une première page de code.
Ensuite nous pourrons sélectionner ce modèle de projet parmi les autres lors de la création d'un nouveau projet.
Sous Code::Blocks comme sous Visual C++, la démarche est sensiblement la même :
- Créer un projet (vide ou console).
- Configurer soigneusement le projet à savoir indiquer où est la bibliothèque et éditer les liens avec les modules utilisés de la bibliothèque Allegro.
- Écrire la première page de code. Ce sera le minimum comprenant tout ce qui vous semble important pour démarrer un type d'application Allegro. Attention à bien tester le code et vérifier qu'il ne contient aucune erreur.
- Exporter en tant que modèle.
III-G-1. Code de base du projet▲
Voici une proposition de départ utile pour des projets Allegro simples. Vous serez peut-être amené ultérieurement à faire d'autres modèles de projet pour des projets plus complexes intégrant notamment la gestion des événements, des possibilités de dessin et des affichages d'images.
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
void
erreur
(
const
char
*
txt)
{
ALLEGRO_DISPLAY*
d;
d =
al_is_system_installed
(
) ? al_get_current_display
(
) : NULL
;
al_show_native_message_box
(
d, "
ERREUR
"
, txt, NULL
, NULL
, 0
);
exit
(
EXIT_FAILURE);
}
/**
***************************************************************
****************************************************************
*/
int
main
(
)
{
ALLEGRO_DISPLAY*
display;
ALLEGRO_KEYBOARD_STATE key;
if
(!
al_init
(
))
erreur
(
"
al_init()
"
);
if
(!
al_install_keyboard
(
))
erreur
(
"
al_install_keyboard()
"
);
display =
al_create_display
(
800
, 600
);
if
(!
display)
erreur
(
"
al_create_display()
"
);
do
{
al_get_keyboard_state
(&
key);
}
while
(!
al_key_down
(&
key, ALLEGRO_KEY_ESCAPE));
al_destroy_display
(
display);
return
0
;
}
/**
***************************************************************
****************************************************************
*/
Dernier point important, avant de passer à la sauvegarde du projet en tant que modèle, compilez le projet en mode debug et en mode release et vérifiez qu'il n'y pas de bogue.
Une fois ces trois opérations terminées (projet, configuration, tests), il faut sauvegarder le projet sous forme de modèle. Nous détaillons cidessous cette sauvegarde pour Code::Blocks, puis pour Visual Studio.
III-G-2. Modèle de projet sous Code::Blocks▲
Sous Code::Blocks, allez dans le menu File et sélectionnez Save project as template :
Dans la fenêtre entrez un nom pour le modèle et cliquez sur OK. Le modèle est sauvegardé.
Il se retrouve ensuite dans la fenêtre de sélection de modèles lors de la création d'un projet dans la rubrique User templates sur le côté gauche de la fenêtre :
Cliquez sur User templates.
La fenêtre suivante s'affiche :
Dans cette fenêtre, il suffit de sélectionner son modèle. Il est évidemment possible de faire toutes sortes de modèles, par exemple plusieurs types de projets Allegro pour des styles d'applications différentes qui nécessitent des initialisations différentes dans le code au départ.
III-G-3. Modèle de projet sous Visual Studio▲
Pour sauvegarder un projet en tant que modèle de projet (template) sous Visual Studio :
Dans le menu Fichier sélectionnez Exporter le modèle.
La fenêtre Assistant Exportation de modèle s'ouvre :
Un choix est proposé : faire un modèle de projet ou un modèle d'élément (par exemple une page de code). Sélectionnez Modèle de projet.
La liste tout en bas permet de sélectionner dans la solution le projet qui va servir de modèle (rappelons qu'une solution peut contenir plusieurs projets). Pour nous, le projet se nomme « modèle de projet ». Ensuite, cliquez sur Suivant.
Une fenêtre d'options pour le modèle apparaît :
Le premier champ sert à nommer son modèle. Nous avons nommé le nôtre « Allegro 5.0.10-base jeu » (quoiqu'ici ce ne soit pas encore vraiment complet).
Le second champ permet d'entrer une description du modèle, description qui sera retrouvée ensuite sur la gauche dans la fenêtre de création de projets. C'est pratique pour se rappeler de certaines spécifications propres au projet.
Le troisième champ offre la possibilité d'adjoindre une icône pour le projet. Nous avons choisi une petite icône qui se trouve dans un dossier images sur la partition D de notre disque dur.
Le quatrième champ permet d'associer une image à la description du projet. L'image choisie se trouvera centrée en dessous du texte d'explication dans le volet gauche de la fenêtre de création de projets.
L'emplacement de sortie correspond à l'emplacement sur le disque où est sauvegardé le modèle. Mais le modèle qui est utilisé pour un nouveau projet par Visual Studio en est une copie et se trouve dans le dossier Template. Si au besoin vous devez supprimer un modèle de projet et ne plus le voir apparaître dans la fenêtre de création de projets, il faut le supprimer dans le dossier Template.
Si vous cochez Importer automatiquement le modèle dans Visual Studio, celui-ci sera intégré et visible dans la fenêtre nouveau projet.
Si vous cochez Afficher une fenêtre d'explorateur pour le dossier des fichiers de sorties, une telle fenêtre s'ouvre lorsque vous cliquez sur Terminer, ce qui permet de voir où est stocké le modèle et sous quelle forme sur le disque.
Une fois toutes ces informations entrées, cliquez sur Terminer.
Ouvrez la fenêtre Nouveau projet, votre modèle y apparaît.
III-H. Quelques précisions▲
III-H-1. Utilisation de la fenêtre console▲
Sous Windows la fenêtre console est fournie par défaut lorsque l'on débute un projet à partir de « projet vide ». Pour supprimer cette console, sous Code::Blocks comme sous Visual Studio, il faut commencer un projet en sélectionnant un modèle du type application Win32.
III-H-1-a. Création d'un projet sans fenêtre console▲
Sous Code::Blocks, vous devez commencer par choisir un projet Win32 et simplement remplacer tout le code fourni automatiquement avec le modèle par celui de l'application Allegro. Ensuite, si vous partez souvent avec ce type de projet, il peut être utile de réaliser un nouveau modèle.
Pour Visual Studio il y a la possibilité de commencer un projet Win32, de spécifier qu'on le veut vide afin de le compléter pour Allegro ensuite. La démarche est la suivante :
Sélectionnez Nouveau projet, la fenêtre Nouveau projet s'ouvre :
Dans le volet gauche, sélectionnez Win32 et au centre Projet Win32, donnez un nom pour le projet et la solution, positionnez sur le disque l'endroit de la sauvegarde puis cliquez sur OK.
La fenêtre Assistant Application Win32 s'ouvre :
Sur la gauche, cliquez sur Paramètres de l'application. La fenêtre correspondante s'ouvre :
Décochez Vérifications SDL (…) et cochez Projet vide ce qui donne :
Cliquez sur Terminer.
Un nouveau projet sans page de code est ouvert que vous retrouvez dans l'explorateur de solutions. Il reste à lui ajouter une page de code et à établir les liens pour l'utilisation de la bibliothèque Allegro.
Ce projet ne contiendra pas de fenêtre console.
III-H-1-b. Alternative à la fenêtre console sous Allegro▲
Dans nos programmes d'expérimentation, nous avons presque toujours laissé la fenêtre console de Windows et nous l'avons utilisée de temps à autre. C'est pratique, mais il peut y avoir un problème si l'on souhaite tester les applications dans un autre environnement et sous un autre système, Linux ou Mac OS par exemple. Pour l'éviter,
Allegro fournit l'équivalent d'une console native à la bibliothèque.
Pour obtenir une console native et l'utiliser, nous avons besoin d'un pointeur sur une structure ALLEGRO_TEXTLOG :
ALLEGRO_TEXTLOG *
console;
Créer et ouvrir la fenêtre console revient à la fonction al_open_native_text_log :
ALLEGRO_TEXTLOG *
al_open_native_text_log
(
char
const
*
title, int
flags)
Cette fonction retourne un pointeur sur une fenêtre console et ouvre la fenêtre. En cas d'impossibilité, elle retourne la valeur NULL . Le premier paramètre title permet de donner un nom à la fenêtre. Le second flags peut recevoir trois valeurs qui déterminent différents paramétrages :
- 0 : a priori ce sont les valeurs par défaut. La police par défaut semble être Arial et en cas d'utilisation d'événements (les événements sont décrits dans le chapitre suivant), un événement est généré avec un clic sur le bouton de fermeture. C'est un événement du type ALLEGRO_EVENT_NATIVE_DIALOG_CLOSE. La récupération des événements d'une fenêtre console native nécessitera par ailleurs un appel à la fonction al_get_native_text_log_event_source() (voir le chapitre Les événementsÉvénements).
- ALLEGRO_TEXTLOG_NO_CLOSE : dans le cadre d'une utilisation avec des événements, cette valeur interdit le bouton de fermeture qui dès lors n'envoie pas d'événement.
- ALLEGRO_TEXTLOG_MONOSPACE : agit sur le choix de la police qui devient une police « monospace » c'est-à-dire une police dans laquelle toutes les lettres prennent la même dimension horizontale, par exemple la police courier New.
Exemple d'ouverture de console native :
ALLEGRO_TEXTLOG *
console;
console =
al_open_native_text_log
(
"
Ma console
"
, 0
);
Pour écrire dans la console c'est la fonction al_append_native_text_log :
void
al_append_native_text_log
(
ALLEGRO_TEXTLOG *
textlog, char
const
*
format, ...)
C'est l'équivalent d'un printf mais adressé à la fenêtre console native dont le pointeur est donné au premier paramètre textlog . Le second paramètre format est la chaîne de caractères formatée sur le même modèle que la fonction standard printf . Voici en exemple d'utilisation, l'affichage de la position de la souris :
al_append_native_text_log
(
console, "
position souris : %d, %d
\n
"
, mouse.x, mouse.y);
Pour fermer la console, c'est la fonction al_close_native_text_log :
void
al_close_native_text_log
(
ALLEGRO_TEXTLOG *
textlog)
La fonction ferme la console et désalloue l'adresse passée en paramètre au pointeur textlog . Attention au fait que le pointeur n'est pas mis à NULL . Il contient toujours la même adresse mémoire mais celle-ci n'est plus accessible.
III-H-1-b-i. Expérimentation▲
Dans le programme ci-dessous, une fenêtre console native Allegro est créée, la position de la souris est affichée dedans en mode texte et si la touche [Entrée] est appuyée, la fenêtre console est fermée.
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
void
erreur
(
const
char
*
txt)
{
ALLEGRO_DISPLAY*
d;
d =
al_is_system_installed
(
) ? al_get_current_display
(
) : NULL
;
al_show_native_message_box
(
d, "
ERREUR
"
, txt, NULL
, NULL
, 0
);
exit
(
EXIT_FAILURE);
}
/**
***************************************************************
****************************************************************
*/
int
main
(
)
{
ALLEGRO_DISPLAY*
display;
ALLEGRO_KEYBOARD_STATE key;
ALLEGRO_MOUSE_STATE mouse;
ALLEGRO_TEXTLOG *
console; // une console
if
(!
al_init
(
))
erreur
(
"
al_init()
"
);
if
(!
al_install_keyboard
(
))
erreur
(
"
al_install_keyboard()
"
);
if
(!
al_install_mouse
(
))
erreur
(
"
al_install_mouse()
"
);
display =
al_create_display
(
800
, 600
);
if
(!
display)
erreur
(
"
al_create_display()
"
);
// création et ouverture
console =
al_open_native_text_log
(
"
Ma console
"
, 0
);
if
(!
console)
erreur
(
"
al_open_native_text_log(
\"
Ma console
\"
, 0)
"
);
int
mx =
0
;
int
my =
0
;
do
{
al_get_keyboard_state
(&
key);
al_get_mouse_state
(&
mouse);
// écrire dans la console
if
(
console !=
NULL
&&
(
mx!=
mouse.x ||
my!=
mouse.y)){
mx =
mouse.x;
my =
mouse.y;
al_append_native_text_log
(
console,
"
position souris : %d, %d
\n
"
, mx, my);
}
//fermer la console
if
(
al_key_down
(&
key, ALLEGRO_KEY_ENTER)){
al_close_native_text_log
(
console);
console =
NULL
;
}
}
while
(!
al_key_down
(&
key, ALLEGRO_KEY_ESCAPE));
al_destroy_display
(
display);
return
0
;
}
/**
***************************************************************
****************************************************************
*/
III-H-2. Meilleur contrôle du clavier simple▲
La capture du clavier que nous utilisons pour l'instant est pratique et rapide à mettre en place. La même méthode existe pour la souris mais aussi pour le joystick. Certes les performances sont plus limitées qu'avec une file d'événements (pas de minuteur notamment) mais elle est suffisante dans certaines situations. Nous allons l'utiliser pour tester les fonctions de dessin ainsi que les fonctions d'affichage des images dans les deux chapitres qui suivent.
III-H-2-a. Problème des répétitions du clavier▲
Cette méthode qui est à la base dans la version 4 d'Allegro a des limites :
- elle ne permet pas de contrôler la vitesse d'exécution du programme avec un minuteur,
- les captures des touches du clavier sont très rapides et incontrôlées. Le temps que vous appuyez sur une touche peut correspondre à plusieurs centaines de tours de boucles.
III-H-2-a-i. Expérimentation▲
Dans le programme suivant, l'appui sur la touche [Entrée] incrémente une variable, et l'appui sur la touche [Espace] affiche la valeur de cette variable dans la fenêtre console.
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <stdio.h>
// contrôle d'erreur
void
erreur
(
const
char
*
txt)
{
ALLEGRO_DISPLAY*
d;
d =
al_is_system_installed
(
) ? al_get_current_display
(
) : NULL
;
al_show_native_message_box
(
d, "
ERREUR
"
, txt, NULL
, NULL
, 0
);
}
/**
*****************************************
*******************************************
*/
int
main
(
)
{
ALLEGRO_DISPLAY *
display;
ALLEGRO_KEYBOARD_STATE key; // stocke l'état du clavier
int
fin =
0
, cmpt =
0
;
if
(!
al_init
(
))
erreur
(
"
al_init()
"
);
//Pour avoir le clavier
if
(!
al_install_keyboard
(
))
erreur
(
"
al_install_keyboard()
"
);
display =
al_create_display
(
800
, 600
);
if
(!
display)
erreur
(
"
al_create_display()
"
);
al_set_window_title
(
display, "
Clavier simple
"
);
while
(!
fin){
// récupérer l'état du clavier
al_get_keyboard_state
(&
key);
if
(
al_key_down
(&
key, ALLEGRO_KEY_ESCAPE))
fin =
1
;
// incrémentation de la variable
if
(
al_key_down
(&
key, ALLEGRO_KEY_ENTER))
cmpt++
;
// affichage
if
(
al_key_down
(&
key, ALLEGRO_KEY_SPACE))
printf
(
"
%d
\n
"
, cmpt);
al_flip_display
(
);
}
al_destroy_display
(
display);
return
0
;
}
/**
*****************************************
*******************************************
*/
Pour chaque appui sur la touche [Entrée] il y a sur notre machine entre 300 et 500 passages dans le if. C'est bien sûr valable pour toutes les touches.
III-H-2-b. Compter les répétitions clavier▲
our résoudre ce problème, l'idée est de compter le nombre des répétitions pour chaque touche du clavier lorsqu'elle est appuyée. Il sera ainsi possible de contrôler l'action en fonction du nombre des répétitions. Ce comptage est mémorisé avec un tableau d'entiers :
int
press[ALLEGRO_KEY_MAX] ;
Dans ce tableau, chaque indice correspond à un identifiant de touche. Par exemple ALLEGRO_KEY_A , ALLEGRO_KEY_ESCAPE , ALLEGRO_KEY_etc.
Ainsi, à chaque tour dans la boucle du programme lorsqu'une touche est restée appuyée, on a :
if
(
al_key_down
(&
key,matouche))
press[matouche]++
;
Et elle est remise à 0 uniquement si la touche est relevée :
if
(
al_key_down
(&
key,matouche)){
press[matouche]++
;
// faire les instructions associées à la touche
}
else
if
(!
al_key_down
(&
key,matouche) // si relevée remise à 0
press[matouche]=
0
;
Ensuite le nombre de répétitions peut être utilisé par exemple en interdisant au-delà de cinq :
if
(
al_key_down
(&
key,matouche) &&
press[matouche] <
5
){
press[matouche]++
;
// faire les instructions associées à la touche
}
else
if
(!
al_key_down
(&
key,matouche)
press[matouche]=
0
;
Dans cet exemple, à partir de cinq répétitions, les instructions associées à la touche ne seront plus exécutées.
Cet algorithme est implémenté dans une fonction à partir d'un tableau d'entiers static local à la fonction. Le mot-clé static signifie qu'il reste en mémoire à l'issue de l'exécution de la fonction de sorte que chaque appel à la fonction retrouve le tableau dans l'état où il était à l'issue de l'appel précédent. Le tableau est initialisé à 0 seulement une fois, lors du premier appel. Voici la fonction :
int
is_key_pressed
(
ALLEGRO_KEYBOARD_STATE*
key,int
touche, int
repeat)
{
//le tableau conserve ses valeurs d'un appel à l'autre (static)
static
int
press[ALLEGRO_KEY_MAX]={
0
}
;
int
res=
0
;
if
(
al_key_down
(
key,touche)&&
press[touche] <
repeat ){
press[touche]++
;
res=
1
;
}
else
if
(
!
al_key_down
(
key,touche))
press[touche]=
0
;
return
res;
}
La fonction retourne true si la touche touche en paramètre est appuyée pour un nombre de fois inférieur au nombre repeat des répétitions autorisées. Elle retourne false sinon, parce que la touche n'est plus appuyée ou que le nombre des répétitions autorisées est atteint.
Le programme suivant permet d'expérimenter cette fonction et nous l'utiliserons pour la plupart des programmes de démonstrations des primitives de dessin.
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
void
erreur
(
const
char
*
txt)
{
ALLEGRO_DISPLAY*
d;
d =
al_is_system_installed
(
) ? al_get_current_display
(
) : NULL
;
al_show_native_message_box
(
d, "
Erreur
"
, txt, NULL
, NULL
, 0
);
exit
(
EXIT_FAILURE);
}
/**
***************************************************************
****************************************************************
*/
int
is_key_pressed
(
ALLEGRO_KEYBOARD_STATE*
key, int
touche, int
repeat)
{
//le tableau conserve ses valeurs d'un appel à l'autre (static)
static
int
press[ALLEGRO_KEY_MAX] =
{
0
}
;
int
res =
0
;
if
(
al_key_down
(
key, touche) &&
press[touche] <
repeat){
press[touche]++
;
res =
1
;
}
else
if
(!
al_key_down
(
key, touche))
press[touche] =
0
;
return
res;
}
/**
***************************************************************
****************************************************************
*/
int
main
(
)
{
ALLEGRO_DISPLAY*
display;
ALLEGRO_KEYBOARD_STATE k, *
key =
&
k;
ALLEGRO_TEXTLOG *
textlog;
if
(!
al_init
(
))
erreur
(
"
al_init()
"
);
if
(!
al_install_keyboard
(
))
erreur
(
"
install keyboard
"
);
display =
al_create_display
(
800
, 600
);
if
(!
display)
erreur
(
"
display
"
);
// fenêtre console native allegro
textlog =
al_open_native_text_log
(
"
test clavier
"
,
ALLEGRO_TEXTLOG_MONOSPACE);
al_append_native_text_log
(
textlog,
"
Test fleches pressee, ESCAPE pour quitter :
\n
"
);
do
{
al_get_keyboard_state
(
key);
if
(
is_key_pressed
(
key, ALLEGRO_KEY_UP, 1
))
al_append_native_text_log
(
textlog,
"
touche UP pressee
\n
"
);
if
(
is_key_pressed
(
key, ALLEGRO_KEY_RIGHT, 2
))
al_append_native_text_log
(
textlog,
"
touche RIGHT pressee
\n
"
);
if
(
is_key_pressed
(
key, ALLEGRO_KEY_DOWN, 3
))
al_append_native_text_log
(
textlog,
"
touche DOWN pressee
\n
"
);
if
(
is_key_pressed
(
key, ALLEGRO_KEY_LEFT, 10
))
al_append_native_text_log
(
textlog,
"
touche LEFT pressee
\n
"
);
}
while
(!
is_key_pressed
(
key, ALLEGRO_KEY_ESCAPE, 1
));
al_destroy_display
(
display);
return
0
;
}
/**
***************************************************************
****************************************************************
*/
III-H-3. Meilleur contrôle de la souris simple▲
La capture des clics de la souris avec la méthode que nous utilisons pour l'instant présente les mêmes avantages et inconvénients que la capture du clavier : pratique et rapide à mettre en place, mais le contrôle des clics doit être renforcé.
III-H-3-a. Problème des répétitions de clics▲
La capture des clics sur les boutons de la souris est très rapide et incontrôlée. Le temps pendant lequel vous cliquez peut correspondre à plusieurs centaines de tours de boucles.
III-H-3-a-i. Expérimentation▲
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <stdio.h>
int
SCREENX =
640
;
int
SCREENY =
480
;
/**
***************************************************************
****************************************************************
*/
void
erreur
(
const
char
*
txt)
{
ALLEGRO_DISPLAY*
d;
d =
al_is_system_installed
(
) ? al_get_current_display
(
) : NULL
;
al_show_native_message_box
(
d, "
ERREUR
"
, txt, NULL
, NULL
, 0
);
exit
(
EXIT_FAILURE);
}
/**
***************************************************************
****************************************************************
*/
int
main
(
)
{
ALLEGRO_DISPLAY*
display;
ALLEGRO_KEYBOARD_STATE key;
ALLEGRO_MOUSE_STATE mouse;
int
gauche =
0
, droite =
0
;
if
(!
al_init
(
))
erreur
(
"
al_init()
"
);
if
(!
al_install_keyboard
(
))
erreur
(
"
al_install_mouse()
"
);
if
(!
al_install_mouse
(
))
erreur
(
"
al_install_mouse()
"
);
display =
al_create_display
(
SCREENX, SCREENY);
if
(!
display)
erreur
(
"
al_create_display()
"
);
do
{
al_get_keyboard_state
(&
key);
al_get_mouse_state
(&
mouse);
if
(
al_mouse_button_down
(&
mouse, 1
)){
gauche++
;
printf
(
"
gauche : %d
\n
"
, gauche);
}
if
(
al_mouse_button_down
(&
mouse, 2
)){
droite++
;
printf
(
"
droite : %d
\n
"
, droite);
}
if
(
al_key_down
(&
key, ALLEGRO_KEY_ENTER))
gauche =
droite =
0
;
}
while
(!
al_key_down
(&
key, ALLEGRO_KEY_ESCAPE));
al_destroy_display
(
display);
return
0
;
}
/**
***************************************************************
****************************************************************
*/
À l'exécution de ce programme sur notre machine pour un clic, il peut y avoir entre 300 et 2 000 tours de boucle.
III-H-3-b. Compter les clics sur chaque bouton de la souris▲
Nous pouvons utiliser le même algorithme que celui du clavier pour contrôler les clics de la souris. Mais comme le nombre de boutons peut varier d'une souris à l'autre, nous avons intérêt à utiliser un tableau dynamique pour stocker l'état des boutons avec le nombre de répétitions. Le tableau dynamique est déclaré en global au-dessus du main :
static
int
*
PRESS =
NULL
;
Le nombre des boutons est obtenu dans la boucle et dans la fonction de contrôle avec la fonction de la bibliothèque al_get_num_mouse_button() .
int
nbbtn=
al_get_num_mouse_button
(
) ;
L'initialisation du tableau est faite à la première utilisation de la fonction de contrôle lorsque le pointeur est NULL :
int
nbbtn =
al_get_mouse_num_buttons
(
);
if
(
PRESS ==
NULL
){
PRESS =
(
int
*
)calloc
(
nbbtn+
1
, sizeof
(
int
));
memset
(
PRESS, 0
, sizeof
(
int
)*(
nbbtn +
1
));
}
La fonction complète pour le contrôle des boutons souris est la suivante :
int
is_mouse_pressed
(
ALLEGRO_MOUSE_STATE*
mouse, int
btn, int
repeat)
{
int
res =
0
;
int
nbbtn =
al_get_mouse_num_buttons
(
);
// initialisation du tableau de contrôle
if
(
PRESS ==
NULL
){
PRESS =
(
int
*
)calloc
(
nbbtn+
1
, sizeof
(
int
));
memset
(
PRESS, 0
, sizeof
(
int
)*(
nbbtn +
1
));
}
if
(
btn >
nbbtn)
btn =
nbbtn;
if
(
al_mouse_button_down
(
mouse, btn) &&
PRESS[btn] <
repeat){
PRESS[btn]++
;
res =
1
;
}
else
if
(!
al_mouse_button_down
(
mouse, btn))
PRESS[btn] =
0
;
return
res;
}
Elle retourne true si à partir de l'état state de la souris le bouton btn est pressé et que le nombre total de fois où il est pressé est inférieur à repeat . Elle retourne false sinon. Dans le programme suivant, nous contrôlons l'état de chaque bouton dans une boucle for avec deux répétitions autorisées pour chaque :
for
(
i=
1
; i<=
nbbtn; i++
)
if
(
is_mouse_pressed
(&
mouse,i,2
))
al_append_native_text_log
(
textlog,"
boutons %d presse
\n
"
,i);
Chaque indice i correspond à un bouton c'est pourquoi la boucle commence à 1. Voici le programme d'expérimentation complet :
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
static
int
*
PRESS =
NULL
;
void
erreur
(
const
char
*
txt)
{
ALLEGRO_DISPLAY*
d;
d =
al_is_system_installed
(
) ? al_get_current_display
(
) : NULL
;
al_show_native_message_box
(
d, "
Erreur
"
, txt, NULL
, NULL
, 0
);
exit
(
EXIT_FAILURE);
}
/**
***************************************************************
****************************************************************
*/
int
is_mouse_pressed
(
ALLEGRO_MOUSE_STATE*
mouse, int
btn, int
repeat)
{
int
res =
0
;
int
nbbtn =
al_get_mouse_num_buttons
(
);
// initialisation du tableau de contrôle
if
(
PRESS ==
NULL
){
PRESS =
(
int
*
)calloc
(
nbbtn+
1
, sizeof
(
int
));
memset
(
PRESS, 0
, sizeof
(
int
)*(
nbbtn +
1
));
}
if
(
btn >
nbbtn)
btn =
nbbtn;
if
(
al_mouse_button_down
(
mouse, btn) &&
PRESS[btn] <
repeat){
PRESS[btn]++
;
res =
1
;
}
else
if
(!
al_mouse_button_down
(
mouse, btn))
PRESS[btn] =
0
;
return
res;
}
/**
***************************************************************
****************************************************************
*/
int
main
(
)
{
ALLEGRO_DISPLAY*
display;
ALLEGRO_MOUSE_STATE mouse;
ALLEGRO_KEYBOARD_STATE key;
ALLEGRO_TEXTLOG *
textlog;
int
i,nbbtn;
if
(!
al_init
(
))
erreur
(
"
allegro init
"
);
if
(!
al_install_mouse
(
))
erreur
(
"
install mouse
"
);
if
(!
al_install_keyboard
(
))
erreur
(
"
install clavier
"
);
display =
al_create_display
(
800
, 600
);
if
(!
display)
erreur
(
"
display
"
);
// pour avoir une fenêtre console même sans débug
textlog =
al_open_native_text_log
(
"
test souris
"
,
ALLEGRO_TEXTLOG_MONOSPACE);
al_append_native_text_log
(
textlog,
"
SOURIS TEST 2 / ESCAPE pour quitter :
\n
"
);
nbbtn =
al_get_mouse_num_buttons
(
);
do
{
// action souris
al_get_mouse_state
(&
mouse);
// état des boutons
for
(
i =
1
; i <=
nbbtn; i++
){
if
(
is_mouse_pressed
(&
mouse, i, 2
))
al_append_native_text_log
(
textlog,
"
boutons %d presse
\n
"
, i);
}
// recup état du clavier
al_get_keyboard_state
(&
key);
}
while
(!
al_key_down
(&
key, ALLEGRO_KEY_ESCAPE));
al_destroy_display
(
display);
free
(
PRESS);
return
0
;
}
/**
***************************************************************
****************************************************************
*/
Obtenir ce livre▲
Ce document est une retranscription autorisée du livre Allegro 5 - Programmation de jeux en C et C++ écrit par Frédéric DROUILLON. Initialement publié aux éditions ENI, vous pouvez commander le livre sur le site de l'éditeur. |