Allegro 5

Programmation de jeux en C ou C++


précédentsommairesuivant

VII. Joystick

VII-A. Introduction

La bibliothèque Allegro 5 fournit le nécessaire pour utiliser un ou plusieurs joysticks simultanément dans un programme. Un joystick peut être constitué de plusieurs « sticks ». Le stick est une manette qui permet d'orienter manuellement quelque chose à l'écran. Pour ce faire, chaque manette peut disposer d'un ou plusieurs axes : horizontal, vertical, profondeur, gauche-droite, bas-haut, etc. selon la complexité du joystick. Le joystick dispose également d'une panoplie de boutons disposés de façon très diverse selon les modèles.

VII-B. Prise en main simple

VII-B-1. Principales fonctions

Pour que le programme puisse disposer d'un joystick, c'est comme pour le clavier et la souris, il faut commencer par installer le joystick avec un appel à la fonction :

 
Sélectionnez
bool al_install_joystick(void)

Cette fonction installe un pilote pour le joystick et retourne true si succès et false en cas d'échec. Si un driver a déjà été installé, elle retourne true immédiatement.

Ainsi au départ nous avons :

 
Sélectionnez
if (!al_install_joystick())
    erreur("al_install_joystick()");

Ensuite des fonctions nous permettent d'identifier le ou les joysticks branchés à l'application :

La fonction al_get_num_joystick :

 
Sélectionnez
int al_get_num_joysticks(void)

Retourne le nombre de joysticks effectivement branchés sur l'ordinateur. La fonction retourne 0 s'il n'y a pas de joystick ou que le driver n'est pas installé. Exemple d'appel :

 
Sélectionnez
int nbjoy = al_get_num_joysticks();
printf("nombre de joysticks : %d\n", nbjoy);

Par ailleurs, le branchement des joysticks peut être géré dynamiquement et un joystick peut être ajouté ou retiré. Si le nombre de joysticks est modifié, il faut alors un appel à la fonction al_reconfigure_joysticks pour que la modification soit prise en compte (la gestion dynamique des joysticks est abordée dans la section suivanteUtilisation des événements).

La fonction al_get_joystick :

 
Sélectionnez
ALLEGRO_JOYSTICK * al_get_joystick(int num)

La fonction retourne un pointeur sur le joystick dont le numéro est passé en paramètre. Attention, les différents joysticks sont numérotés de 0 à n et l'indice du dernier joystick branché est obtenu avec l'expression :

 
Sélectionnez
al_get_num_joystick()-1

S'il n'y a aucun joystick, la fonction retourne NULL .

Le numéro n'est pas un identificateur du joystick. Il correspond uniquement à sa position dans la liste. Si un joystick est retiré ou ajouté, les positions des autres s'en trouvent modifiées et leurs numéros d'ordre peuvent changer. Ce qui permet d'identifier un joystick c'est son adresse mémoire, un pointeur ALLEGRO_JOYSTICK* .

Exemple d'appel :

 
Sélectionnez
ALLEGRO_JOYSTICK*joy ;
(...)
joy = al_get_joystick(0); // le premier dans la liste

La fonction al_get_joystick_name :

 
Sélectionnez
const char *al_get_joystick_name(ALLEGRO_JOYSTICK *joy)

Retourne le nom du joystick dont l'adresse est passée au paramètre joy . Exemple d'appel :

 
Sélectionnez
ALLEGRO_JOYSTICK*joy ;
(…)
joy = al_get_joystick(0); // le premier dans la liste
const char*nom = al_get_joystick_name(joy);
printf("JOYSTICK 1, nom : %s\n", nom);

La fonction al_get_joystick_num_sticks :

 
Sélectionnez
int al_get_joystick_num_sticks(ALLEGRO_JOYSTICK *joy)

Retourne le nombre de manettes (sticks) dont dispose le joystick joy donné en paramètre. Une manette peut contrôler un ou plusieurs axes (horizontal, vertical, profondeur, etc.). Le nombre maximum des manettes est actuellement limité à huit. Exemple d'appel :

 
Sélectionnez
ALLEGRO_JOYSTICK*joy ;
(…)
int nbsticks = al_get_joystick_num_sticks(joy);
printf("\t%d sticks, noms : ", nbsticks);

La fonction al_get_joystick_stick_name :

 
Sélectionnez
const char *al_get_joystick_stick_name(ALLEGRO_JOYSTICK *joy, int stick)

Retourne le nom de la manette stick sur le joystick joy donné en paramètre. La manette est identifiée par un numéro. L'ensemble des manettes d'un joystick constitue un tableau et ce numéro correspond à son indice dans le tableau (la numérotation des indices commence à 0). Si la manette n'existe pas, la valeur NULL est retournée. Exemple d'appel :

 
Sélectionnez
ALLEGRO_JOYSTICK*joy ;
(...)
int nbsticks = al_get_joystick_num_sticks(joy);
for (i = 0; i < nbsticks; i++){
    const char * nom = al_get_joystick_stick_name(joy, i);
    printf("%s, ", nom);
}

La fonction al_get_joystick_num_axes :

 
Sélectionnez
int al_get_joystick_num_axes(ALLEGRO_JOYSTICK *joy, int stick)

Retourne le nombre total d'axes contrôlés par la manette passée au paramètre stick sur le joystick joy donné en paramètre. L'ensemble des manettes d'un joystick constitue un tableau et le numéro passé au paramètre stick correspond à son indice dans le tableau (les indices commencent à 0). Si la manette n'existe pas, la valeur 0 est retournée par la fonction. Le nombre maximum des axes est actuellement limité à trois. Exemple d'appel :

 
Sélectionnez
ALLEGRO_JOYSTICK*joy ;
int nbaxes;
(...)
int nbsticks = al_get_joystick_num_sticks(joy);
    
    for (i = 0; i < nbsticks; i++){
        nbaxes = al_get_joystick_num_axes(joy, i);
        printf("\t\tsticks %d, %d axes : \n", i, nbaxes);
    }
}

La fonction al_get_joystick_axis_name :

 
Sélectionnez
const char *al_get_joystick_axis_name(ALLEGRO_JOYSTICK *joy, int stick, int axis)

Retourne le nom de l'axe axis sur la manette sticks pour le joystick joy passé en paramètre. L'ensemble des manettes d'un joystick constitue un tableau et pour chaque manette, l'ensemble des axes constitue également un tableau. L'ensemble des axes est actuellement limité à trois. Les numéros pour identifier manettes et axes correspondent à leurs indices dans leur tableau respectif (commencent à 0). Si l'axe n'existe pas, la valeur NULL est retournée. Exemple d'appel :

 
Sélectionnez
ALLEGRO_JOYSTICK*joy;
int nbaxes[3] = { 0 }; // trois axes maximum
(...)
int nbsticks = al_get_joystick_num_sticks(joy);
// pour chaque stick le nombre d'axes
for (i = 0; i < nbsticks; i++){
    nbaxes[i] = al_get_joystick_num_axes(joy, i);
    printf("\t\tsticks %d, %d axes : \n", i, nbaxes[i]);
    // le nom de chaque axe
    for (j = 0; j < nbaxes[i]; j++){
        const char * nom = al_get_joystick_axis_name(joy, i, j);
        printf("\t\t\t%s\n", nom);
    }
}

La fonction al_get_joystick_num_buttons :

 
Sélectionnez
int al_get_joystick_num_buttons(ALLEGRO_JOYSTICK *joy)

Retourne le nombre de boutons sur le joystick joy passé en paramètre. Le nombre total des boutons est actuellement limité à trente-deux. Exemple d'appel :

 
Sélectionnez
ALLEGRO_JOYSTICK*joy;
(...)
int nbbtn = al_get_joystick_num_buttons(joy);
printf("\t%d boutons, noms : \n", nbbtn);

La fonction al_get_joystick_button_name :

 
Sélectionnez
const char *al_get_joystick_button_name(ALLEGRO_JOYSTICK *joy, int button)

Retourne le nom d'un bouton sur le joystick joy passé en paramètre. Les boutons sont rassemblés dans un tableau et le bouton est identifié avec le paramètre button par son indice dans le tableau (commence à 0). Exemple d'appel :

 
Sélectionnez
ALLEGRO_JOYSTICK*joy;
(...)
int nbbtn = al_get_joystick_num_buttons(joy);
for (i = 0; i < nbbtn; i++){
    const char*nom = al_get_joystick_button_name(joy, i);
    printf("\t\t%s\n", nom);
}

La fonction al_get_joystick_state :

 
Sélectionnez
void al_get_joystick_state(ALLEGRO_JOYSTICK *joy, ALLEGRO_JOYSTICK_STATE *ret_state)

Retourne par référence la structure ret_state remplie avec les valeurs du joystick joy au moment de l'appel. Exemple d'appel :

 
Sélectionnez
ALLEGRO_JOYSTICK_STATE etatjoy;
ALLEGRO_JOYSTICK*joy=NULL;
(...)
do{
    (...)
    if (joy != NULL){
        al_get_joystick_state(joy, &etatjoy);
        (...)
    }
} while ( ... );

VII-B-2. Expérimentation en mode texte

Le programme ci-dessous affiche dans une fenêtre console toutes les informations d'un joystick unique préalablement branché. Il affiche également toutes les valeurs prises par le joystick s'il est manipulé. Chaque bouton est appuyé ou pas. C'est une valeur entière de 0 s'il n'est pas appuyé, et supérieure à 0 s'il est appuyé. Les positions de chaque axe sont données en valeur flottante comprise entre -1 et +1. Le coin en haut à gauche des deux axes horizontal et vertical correspond aux coordonnées (-1,-1).

Si aucun joystick n'est branché le programme indique 0 et attend pour quitter (touche [Echap]).

Nos affichages se font dans la fenêtre console Windows qui accompagne toutes nos applications dans cet ouvrage. Sous un autre système, il faudra peut-être utiliser la console Allegro native ou bien la console en vigueur dans l'autre système.

Installer le joystick et afficher ses paramètres dans une fenêtre console
Sélectionnez
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <allegro5/allegro_image.h>
#include <time.h>
#include <stdio.h>

#define SCREENX 640
#define SCREENY 480

ALLEGRO_DISPLAY* init_allegro();
void erreur(const char*txt);
/*****************************************************************
*****************************************************************/
int main()
{
    ALLEGRO_DISPLAY*display;
    ALLEGRO_KEYBOARD_STATE key;

 // tester le joystick 
    ALLEGRO_JOYSTICK_STATE etatjoy;    // état joystick
    ALLEGRO_JOYSTICK*joy=NULL;        // le joystick
    int nbjoy;                        // nombre de joysticks
    int nbsticks;                    // nombre de manettes (8 max)
    int nbaxes[3] = { 0 };            // nombre d'axes par manette (3 max)
    float val[8][3] = { 0 };        // valeur du joystick pour chaque
                                    // manette par axe
    int nbbtn;                        // le nombre de boutons (32 max)
    
    int i,j;
 
 display = init_allegro();

 // le nombre de joystick
    nbjoy = al_get_num_joysticks(); 
    printf("nombre de joysticks : %d\n", nbjoy);
 
    if (nbjoy){
        // le premier joystick et son nom
        joy = al_get_joystick(0);
        const char*nom = al_get_joystick_name(joy);
        printf("JOYSTICK 1, nom : %s\n", nom);

        // nombre de sticks du joystick
        nbsticks = al_get_joystick_num_sticks(joy);
        printf("\t%d sticks, noms : ", nbsticks);
        // les noms des sticks
        for (i = 0; i < nbsticks; i++){
            const char * nom = al_get_joystick_stick_name(joy, i);
            printf("%s, ", nom);
        }
        putchar('\n');

        // pour chaque manette le nombre d'axes
        for (i = 0; i < nbsticks; i++){
            nbaxes[i] = al_get_joystick_num_axes(joy, i);
            printf("\t\tsticks %d, %d axes : \n", i, nbaxes[i]);
            // le nom de chaque axe
            for (j = 0; j < nbaxes[i]; j++){
                const char * nom = al_get_joystick_axis_name(joy, i, j);
                printf("\t\t\t%s\n", nom);
            }
        }

        // nombre de boutons
        nbbtn = al_get_joystick_num_buttons(joy);
        printf("\t%d boutons, noms : \n", nbbtn);
        // les noms des boutons
        for (i = 0; i < nbbtn; i++){
            const char*nom = al_get_joystick_button_name(joy, i);
            printf("\t\t%s\n", nom);
        }
    }
    printf("\n------------------------------\n");


 do{
        al_get_keyboard_state(&key);

        if (joy != NULL){
            al_get_joystick_state(joy, &etatjoy);

            for (i = 0; i < nbbtn; i++) // 32 max
                if (etatjoy.button[i] >0)
                    printf("bouton %d presse\n", i);

            for (i = 0; i < nbsticks; i++){// 8 max
                for (j = 0; j < nbaxes[i]; j++){ // 3 max
                    if (val[i][j] != etatjoy.stick[i].axis[j]){
                        val[i][j] = etatjoy.stick[i].axis[j];
                        printf("stick %d, axe %d = %f\n", i, j, val[i][j]);
                    }
                }
            }
        }
                
    } while (!al_key_down(&key, ALLEGRO_KEY_ESCAPE));

    al_destroy_display(display);
    return 0;
}
/*****************************************************************
*****************************************************************/
ALLEGRO_DISPLAY* init_allegro()
{
    ALLEGRO_DISPLAY*display;
    
 if (!al_init())
        erreur("al_init()");

    if (!al_install_keyboard())
        erreur("al_install_keyboard()");

 // pour disposer du joystick
    if (!al_install_joystick())
        erreur("al_install_joystick()");

    display = al_create_display(SCREENX, SCREENY);
    if (!display)
        erreur("al_create_display()");
    return display;
}
/*****************************************************************
*****************************************************************/
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);
}
/*****************************************************************
*****************************************************************/

Attention de ne pas oublier l'appel à la fonction d'installation du driver joystick avant l'utilisation d'un joystick dans la boucle du programme.

Une structure ALLEGRO_JOYSTICK_STATE réunit trois ensembles qui sont trois tableaux :

  • le tableau des boutons,
  • le tableau des manettes,
  • pour chaque manette, le tableau des axes.

Nous pouvons accéder à chaque bouton de la façon suivante :

 
Sélectionnez
ALLEGRO_JOYSTICK_STATE etatjoy;
(...)
int valbtn = etatjoy.button[num_bouton];

et pour chaque manette aux valeurs de chacun de ses axes :

 
Sélectionnez
float valaxe = etatjoy.stick[num_manette].axis[num_bouton];

L'implémentation de cette structure est détaillée dans la section qui suit.

VII-B-3. Structure de données pour l'état d'un joystick

La structure de données pour l'état d'un joystick est un tableau de manettes et chaque manette est elle-même un tableau d'axes qui contient des valeurs flottantes. Ce pourrait être un tableau de float à deux dimensions, par exemple :

 
Sélectionnez
float JOYSTICK[NBMANETTES][NBAXES];

En effet un tableau à deux dimensions est un tableau de tableaux. C'est suffisant pour les manettes mais il manque les boutons. Nous pourrions avoir une structure du type :

 
Sélectionnez
typedef struct{
    float manette[NBMANETTES][NBAXES] ;
    int bouton[NBBOUTONS] ;
}JOYSTICK ;

Mais à l'utilisation il n'est pas aisé de dissocier de façon explicite les manettes et les axes. C'est toujours une manette qui est désignée. Par exemple :

 
Sélectionnez
JOYSTICK j;
j.manette[0][1] = 0.5; // accès manette 0 axe 1 du joystick j

De plus il est alors impossible d'ajouter des informations qui concerneraient chaque axe, par exemple le nom. Pour ces raisons déjà, et il y en a peut-être d'autres, les développeurs d'Allegro 5 ont procédé autrement. Chaque dimension du tableau est encapsulée dans une structure ; en simplifiant, cela donne pour les manettes et les axes :

 
Sélectionnez
struct{ float axes[NBAXES]; } manettes[NBMANETTES];

Ici nous avons un tableau de structures dont chacune contient un tableau d'axes. Nous pouvons écrire par exemple :

 
Sélectionnez
manette[0].axes[1] = 0.5 ; // accès manette 0 axe 1 du joystick j

Cette écriture est plus claire mais a surtout l'avantage de permettre le cas échéant de compléter les informations relatives aux manettes et aux axes. Ainsi la structure de données pour ALLEGRO_JOYSTICK_STATE est définie de la façon suivante dans le fichier source « joystick.h » de la bibliothèque :

 
Sélectionnez
typedef struct ALLEGRO_JOYSTICK_STATE ALLEGRO_JOYSTICK_STATE;
struct ALLEGRO_JOYSTICK_STATE
{
    struct {
        float axis[_AL_MAX_JOYSTICK_AXES];
    } stick[_AL_MAX_JOYSTICK_STICKS];
    int button[_AL_MAX_JOYSTICK_BUTTONS];
};

Les tableaux ne sont pas dynamiques et leurs dimensions maximum sont définies dans le même fichier par les macros constantes suivantes :

 
Sélectionnez
#define _AL_MAX_JOYSTICK_AXES 3
#define _AL_MAX_JOYSTICK_STICKS 8
#define _AL_MAX_JOYSTICK_BUTTONS 32

C'est là que sont définis les nombres maximum de manettes, d'axes et de boutons.

VII-C. Utilisation des événements

VII-C-1. Types d'événements

Rappelons qu'un joystick peut générer quatre types d'événements (la structure des événements joystick est détaillée dans le chapitre sur les événementsÉvénements) :

ALLEGRO_EVENT_JOYSTICK_AXIS : un axe a changé de valeur.

ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN : un bouton est pressé.

ALLEGRO_EVENT_JOYSTICK_BUTTON_UP : un bouton est relevé.

ALLEGRO_EVENT_JOYSTICK_CONFIGURATION : un joystick est branché ou débranché.

VII-C-2. Expérimentation en mode texte

Ce programme permet de brancher ou débrancher un joystick. En principe il peut accueillir plusieurs joysticks simultanément.

Chaque événement du joystick est détaillé dans la fenêtre console : quel joystick, quelle manette, quel axe, quel bouton appuyé ou quel bouton relevé :

Expérimenter les valeurs du joystick en mode texte
Sélectionnez
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <stdio.h>

#define SCREENX    800
#define SCREENY    600

ALLEGRO_DISPLAY*allegro_init(ALLEGRO_EVENT_QUEUE**queue);
void affiche_joysticks(void);
void            affiche_pos_manette(ALLEGRO_JOYSTICK_EVENT*j);
void            affiche_bouton(ALLEGRO_JOYSTICK_EVENT*j, int val);
void            erreur(const char*msg);
/*****************************************************************
*****************************************************************/
int main()
{
    ALLEGRO_DISPLAY*display;
    ALLEGRO_EVENT_QUEUE*queue;
    int fin = 0;

    display = allegro_init(&queue);

    affiche_joysticks();

    while (!fin){

        ALLEGRO_EVENT event;

        al_wait_for_event(queue, &event);

        switch (event.type){

            // EVENEMENTS JOYSTICK
        
            // mouvement sur un axe
        case ALLEGRO_EVENT_JOYSTICK_AXIS:
            affiche_pos_manette(&event.joystick);
            break;

            // bouton appuyé
        case ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN:
            affiche_bouton(&event.joystick, 1);
            break;

            // bouton relevé
        case ALLEGRO_EVENT_JOYSTICK_BUTTON_UP:
            affiche_bouton(&event.joystick, 0);
            break;

            // branchement ou débranchement d'un joystick
        case ALLEGRO_EVENT_JOYSTICK_CONFIGURATION:
            al_reconfigure_joysticks();
            affiche_joysticks();
            break;

            // pour quitter
        case ALLEGRO_EVENT_DISPLAY_CLOSE:
            fin = 1;
            break;

        case ALLEGRO_EVENT_KEY_DOWN:
            if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
                fin = 1;
            break;
        }
    }

    al_destroy_display(display);
    al_destroy_event_queue(queue);
    return 0;
}
/*****************************************************************
*****************************************************************/
ALLEGRO_DISPLAY* allegro_init(ALLEGRO_EVENT_QUEUE**queue)
{
    ALLEGRO_DISPLAY*display;

    if (!al_init())
        erreur("al_init()");

    if (!al_install_keyboard())
        erreur("al_install_keyboard()");

    // pour utilisation joystick
    if (!al_install_joystick())
        erreur("al_install_joystick()");

    display = al_create_display(SCREENX, SCREENY);
    if (!display)
        erreur("al_create_display()");

    *queue = al_create_event_queue();
    if (!*queue)
        erreur("al_create_event_queue()");

    al_register_event_source(*queue,
        al_get_display_event_source(display));
    al_register_event_source(*queue,
        al_get_keyboard_event_source());

    // enregistrement événements joystick
    al_register_event_source(*queue,
        al_get_joystick_event_source());
    return display;
}
/*****************************************************************
*****************************************************************/
void affiche_joysticks()
{
int j,m,a;
int nbjoy = al_get_num_joysticks();

    printf("nombre de joysticks : %d\n", nbjoy);

    for (j = 0; j < nbjoy; j++){
        ALLEGRO_JOYSTICK*joy = al_get_joystick(j);
        printf("JOYSTICK %d : %s\n", j, al_get_joystick_name(joy));

        // les manettes du joystick
        int nbmanette = al_get_joystick_num_sticks(joy);
        for (m = 0; m < nbmanette; m++){

            const char*nom_manette = al_get_joystick_stick_name(joy, m);
            printf("\tManette %d : %s \n", m, nom_manette);

            // les axes par manette
            int nbaxe = al_get_joystick_num_axes(joy, m);
            for (a = 0; a < nbaxe; a++){
                const char*nom_axe = al_get_joystick_axis_name(joy, m, a);
                printf("\t\tAxe %d : %s \n", a, nom_axe);
            }
        }
        printf("-------------------------------------\n");
    }
}
/*****************************************************************
*****************************************************************/
void affiche_pos_manette(ALLEGRO_JOYSTICK_EVENT*j)
{

    // le joystick activé
    printf("JOYSTICK : %s\n", al_get_joystick_name(j->id));

    // la manette activée
    const char*nom_manette = al_get_joystick_stick_name(j->id, j->stick);
    printf("\tManette %d, %s : \n", j->stick, nom_manette);

    // l'axe concerné
    const char*nom_axe = al_get_joystick_axis_name(j->id, j->stick, j->axis);
    printf("\t\tAxe %d, %s : ",j->axis, nom_axe );

    // sa valeur
    printf("valeur : %.2f\n", j->pos);

    printf("------------------------------\n");
}
/*****************************************************************
*****************************************************************/
void affiche_bouton(ALLEGRO_JOYSTICK_EVENT*j, int val)
{
    const char*nom_bouton = al_get_joystick_button_name(j->id, j->button);
    printf("Bouton %d, %s = %d \n", j->button, nom_bouton, val); 
}
/*****************************************************************
*****************************************************************/
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);
}
/*****************************************************************
*****************************************************************/

Évidemment l'affichage n'est pas terrible surtout si le joystick n'est pas absolument stable avec des microvariations sur ses axes par exemple. Cela empêche de bien lire les informations dans la console. Éventuellement il y a la possibilité d'effacer la console avec l'appel :

 
Sélectionnez
system(" cls ") ;

Ce bout de code est néanmoins intéressant parce qu'il permet de bien voir comment récupérer les valeurs du joystick directement à partir de l'union ALLEGRO_EVENT .

VII-C-3. Expérimentation graphique

Cette expérimentation est inspirée d'un exemple fourni avec la bibliothèque. Il est écrit par Peter Wrang, l'un de développeurs de la bibliothèque. Voici le code commenté :

Expérimenter les valeurs du joystick en mode graphique
Sélectionnez
#include <allegro5/allegro.h>
#include <allegro5/allegro_native_dialog.h>
#include <allegro5/allegro_primitives.h>

#define SCREENX    800
#define SCREENY    600

#define NOIR al_map_rgb(0, 0, 0)
#define BLEU al_map_rgb(0, 255, 255)
#define ROUGE al_map_rgb(255, 0, 0)
#define VERT al_map_rgb(0, 255, 0)

#define MAXMANETTES 8
#define MAXAXES 3
#define MAXBTN 32

// les données d'un joystick :
int nbmanettes=0; // nombre de manettes
int nbaxes[MAXMANETTES] = { 0 }; // nombre d'axes par manette
float valaxes[MAXMANETTES][MAXAXES] = { 0 };// valeur des axes
int nbbtn=0; // nombre de boutons
int valbtn[MAXBTN] = { 0 }; // valeur des boutons

ALLEGRO_DISPLAY* allegro_init    (ALLEGRO_EVENT_QUEUE**queue);
void             init_joystick (ALLEGRO_JOYSTICK*joy);
void affiche_joystick(void);
void dessine_axes (int x, int y, int manette);
void dessine_bouton (int btn, int val);
void             erreur         (const char*msg);
/*****************************************************************
*****************************************************************/
int main()
{
    ALLEGRO_DISPLAY*display;
    ALLEGRO_EVENT_QUEUE*queue;
    int fin = 0;

    display = allegro_init(&queue);

    init_joystick(al_get_joystick(0));

    while (!fin){

        ALLEGRO_EVENT event;

 // si la file est vide afficher
        if (al_is_event_queue_empty(queue))
            affiche_joystick();
 
        al_wait_for_event(queue, &event);

        switch (event.type){
            // EVENEMENTS JOYSTICK

            // mouvement sur un axe
            case ALLEGRO_EVENT_JOYSTICK_AXIS :
                valaxes[event.joystick.stick][event.joystick.axis] = 
 event.joystick.pos;
                break;

            // bouton appuyé
            case ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN:
                valbtn[event.joystick.button] = 1;
                break;

            // bouton relevé
            case ALLEGRO_EVENT_JOYSTICK_BUTTON_UP:
                valbtn[event.joystick.button] = 0;
                break;

            // branchement ou débranchement d'un joystick
            case ALLEGRO_EVENT_JOYSTICK_CONFIGURATION:
                al_reconfigure_joysticks();
                init_joystick(al_get_joystick(0));
                break;

            // pour quitter
            case ALLEGRO_EVENT_DISPLAY_CLOSE:
                fin = 1;
                break;

            case ALLEGRO_EVENT_KEY_DOWN :
                if (event.keyboard.keycode == ALLEGRO_KEY_ESCAPE)
                    fin = 1;
                break;
        }
    }

    al_destroy_display(display);
    al_destroy_event_queue(queue);
    return 0;
}
/*****************************************************************
*****************************************************************/
ALLEGRO_DISPLAY* allegro_init(    ALLEGRO_EVENT_QUEUE**queue)                
{
ALLEGRO_DISPLAY*display;

    if (!al_init())
        erreur("al_init()");

    if (!al_install_keyboard())
        erreur("al_install_keyboard()");

    if (!al_init_primitives_addon())
        erreur("al_init_primitives_addon()");

    // pour utilisation joystick
    if (!al_install_joystick())
        erreur("al_install_joystick()");

    display = al_create_display(SCREENX, SCREENY);
    if (!display)
        erreur("al_create_display()");

    *queue = al_create_event_queue();
    if (!*queue)
        erreur("al_create_event_queue()");

    al_register_event_source(*queue,
                            al_get_display_event_source(display));
    al_register_event_source(*queue,
                             al_get_keyboard_event_source());
    
 // enregistrement événements joystick
    al_register_event_source(*queue,
                            al_get_joystick_event_source());
    return display;
}

/*****************************************************************
*****************************************************************/
void init_joystick(ALLEGRO_JOYSTICK*joy)
{
    ALLEGRO_JOYSTICK_STATE etatj;
    int i, j;

    if (joy == NULL)
        return;
 // état du joystick
 al_get_joystick_state(joy, &etatj);

 // récupération des valeurs des manettes
 nbmanettes = al_get_joystick_num_sticks(joy);
    for (i = 0; i < nbmanettes; i++){
        nbaxes[i] = al_get_joystick_num_axes(joy, i);
        for (j = 0; j < nbaxes[i]; j++)
            valaxes[i][j] = etatj.stick[i].axis[j];
    }

 // récupération des états des boutons
    nbbtn = al_get_joystick_num_buttons(joy);
    for (i = 0; i < nbbtn; i++)
        valbtn[i] = (etatj.button[i] > 0) ? 1 : 0;
}
/*****************************************************************
Affichage graphique de toutes les données d'un joystick, axes et
boutons. Les affichages sont centrés et répartis à l'écran de façon
proportionnelle à leur nombre
*****************************************************************/
void affiche_joystick()
{
 // récupère la bitmap de destination courante
 // supposée être l'écran ou la fenêtre avec sa taille
    ALLEGRO_BITMAP *page = al_get_target_bitmap();
    int tx = al_get_bitmap_width(page);
    int ty = al_get_bitmap_height(page);
    int i;

 // fond noir
    al_clear_to_color(NOIR);

 // les manettes
    for (i = 0; i < nbmanettes; i++){
 // centrer
        int posx = (i + 0.5)*tx / nbmanettes;
        int posy = ty / 2;
        dessine_axes(posx, posy, i);
    }

 // les boutons
    for (i = 0; i < nbbtn; i++){
        dessine_bouton(i,valbtn[i]);
    }

 // voir à l'écran
    al_flip_display();
}
/*****************************************************************
Une manette correspond à une position dans un espace selon au
maximum trois axes correspondants chacun à une dimension :
horizontale, verticale, profondeur (x,y,z). 
Il y a deux dessins à faire : la surface totale et dans cette 
surface, de façon proportionnée, le voyant indicateur de la 
position de la manette. L'affichage de la manette est centré 
autour de de la position passée en paramètre.
*****************************************************************/
void dessine_axes(int posx,int posy, int manette)
{
    const int taille = 30;        // pour zone affichage (rayon)
    const int bord = 5;            // bord
    const int total = taille + bord; // total
    int x, y; // position horizontale et verticale de la manette 
    
    // rectangle de la surface totale d'affichage
    al_draw_filled_rectangle(posx - total, posy - total,
         posx + total, posy + total, ROUGE);
    
    // pourtour en bleu clair dans la zone totale
 al_draw_rectangle(posx - total + 0.5, posy - total + 0.5,
         posx + total - 0.5, posy + total - 0.5, 
 BLEU,0);
    
    // pourtour hors zone
    al_draw_rectangle(posx - total , posy - total ,
        posx + total , posy + total ,
        BLEU, 0);
    
    
    // calcul de la position des axes horizontal et vertical 
    x = posx + valaxes[manette][0] * taille;
    y = posy + valaxes[manette][1] * taille;

    // position de la manette
 al_draw_filled_rectangle(x - 5, y - 5, x + 5, y + 5, ROUGE);

    // si l'axe z de profondeur existe il est affiché à part
    if (nbaxes[manette] == 3){
        // calcul position
        int zx = posx + total + bord * 2;
        int z = posy + valaxes[manette][2] * taille;

        // rectangle de la surface totale d'affichage
        al_draw_filled_rectangle(zx - bord, posy - total, 
 zx + bord, posy + total, ROUGE);
        // contour
        al_draw_rectangle(zx - bord + 0.5, posy - total + 0.5,
                         zx + bord - 0.5, posy + total - 0.5,
 BLEU,0);
        
        // position de la manette
        al_draw_filled_rectangle(zx-5, z-5, zx+5, z+5, VERT);
    }
}
/*****************************************************************
*****************************************************************/
void dessine_bouton(int btn, int val)
{
    ALLEGRO_BITMAP*page = al_get_target_bitmap();
    int posx = al_get_bitmap_width(page);
    int posy = al_get_bitmap_height(page);

 // position du bouton (32 boutons possibles : 4 lignes de 8)
    posx = posx / 2 - 120 + (btn % 8) * 30;
    posy = posy - 120 + (btn / 8) * 30;

    // rectangle bouton
    al_draw_filled_rectangle(posx, posy, posx+25, posy+25, ROUGE);

    // pourtour bleu
    al_draw_rectangle( posx + 0.5, posy + 0.5, 
 posx + 24.5, posy + 24.5,BLEU,0);

    // si pressé intérieur en vert
    if (val > 0)
        al_draw_filled_rectangle(posx + 2, posy + 2, 
 posx + 23, posy + 23, VERT);

}
/*****************************************************************
*****************************************************************/
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);
}
/*****************************************************************
*****************************************************************/

Obtenir ce livre

Image non disponible

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.


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2015 Frédéric DROUILLON. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.