Tutoriaux / aides : Programmer sur dreamcast le how-to / Découverte du Développement sur Dreamcast avec KOS et SDL / des liens

  

 

        

 

 

1er chapitre – 2eme Partie : Faire bouger une image sur l'écran de la DC avec la manette.

 

1er chapitre – 2eme Partie : Faire bouger  une image sur l'écran de la DC avec la manette.

 

On va s'appuyer sur le programme que l'on vient de faire mais on va essayer de le structurer un peu mieux (le 1er faisait tres script ...)

notre programme doit faire en plus :

              –Tester la manette

              –Changer la position de l'image en fonction du souhait utilisateur

              –Modifier l'affichage pour que le mouvement prenne effet

 

La 1ere chose qu'on va faire, c'est créer une fonction Init() dont le but est de faire toutes les initialisations. De la même manière, on va faire une fonction pour écrire sur l'écran. L'exemple précédent devient alors :

      #define _arch_dreamcast

      #include <kos.h>

      #include <SDL/SDL.h>

       

      extern uint8 romdisk[];

      KOS_INIT_FLAGS(INIT_DEFAULT | INIT_MALLOCSTATS);

      KOS_INIT_ROMDISK(romdisk);

       

      SDL_Surface *MainScreen ;

      SDL_Surface *Image ;

      int Init()

      {

           // Init SDL et test

           if ( SDL_Init( SDL_INIT_VIDEO ) < 0 )

                {fprintf( stderr, "Couldn't initialize SDL: %s\n", SDL_GetError() );

                return -1;}

       

           // Init ecran principal et test

           MainScreen = SDL_SetVideoMode(640, 480, 0, SDL_HWSURFACE|SDL_DOUBLEBUF);

           if ( MainScreen == NULL )

                {fprintf("Unable to set 640x480 video: %s\n", SDL_GetError());

                return -1;}

       

           // pas de curseur

                SDL_ShowCursor(0);

       

           // charge l'image dans une nouvelle surface

           Image = SDL_LoadBMP("/rd/JMD.bmp");

      }

      int Dessiner_Image(SDL_Surface *Image,int pos_x, int pos_y)

      {

           // creation d'un rectangle destination et définition de la position

           SDL_Rect dest;

           dest.x =  pos_x ;

           dest.y =  pos_y ;

       

           // affiche l'image

           SDL_BlitSurface(Image, NULL, MainScreen, &dest);

           SDL_Flip(MainScreen);

           return 0;

      }

      int main(int argc, char **argv)

      {

           // Init

           if (Init()==0) {printf("Init : OK\n");}

           else {return 0;}

       

                // dessine l'image

           int return_value;

           return_value = Dessiner_Image(Image ,5, 5);

       

           // on boucle à l'infinie pour montrer le spectacle

           int a=0;

           while(a==0)

           {  // boucle infinie

                }

           return 0;

      }

 

 

En ce qui concerne l'initialisation, on a exactement la même chose à quelques petits trucs prés : l'image à afficher devient globale (et plus locale à main) et on teste que l'init s'est bien déroulé.

Pour l'affichage de l'image, on ne définit plus 'en dur' la position de l'image mais on la passe en paramètre à la fonction. Enfin, la fonction retourne un entier dont on ne se sert pas car si on voulait être pro, on testerait les erreurs mais cette partie là a peu de chances de planter.

Voilà : pour le moment on n'a pas fait grand chose mais on a tout restructuré.

Maintenant, la première chose à faire est de s'occuper de la manette. SDL gère les informations en provenance de la manette comme des événements. Tout événement, quand il se produit, est mis dans une file d'attente que l'utilisateur doit aller purger. On va donc créer une file et une boucle qui vient scanner ce qu'il y a dedans.

On déclare donc une structure événement (SDL_Event) qui aura pour but d'accueillir se qu'on ira cueillir dans la file d'événements.  

        SDL_Event event;

 

On va maintenant créer la boucle qui va purger la file d'événements. Cette boucle va se positionner dans la boucle infinie. Son but est, tant qu'un événement est dans la liste, de le traiter et de passer au suivant. Le passage au suivant est automatique (ça fait penser au for each en VB). C'est la fonction qui s'occupe d'aller chercher un événement et de le stocker à l'endroit indiqué en paramètre. Dans notre cas, on va le mettre dans notre structure SDL_event :

       // prend un evenement dans la file d'attente

                          while( SDL_PollEvent(&event)){

                           }

               

 

Tous les événements hardware ou utilisateur de SDL retournent dans cette file. Il faut donc faire le tri et traiter uniquement ce qui est intéressant dans notre cas. Pour connaître le type d'un événement, il suffit de le tester et de réagir en fonction. On utilise un switch pour faire ça :

      switch( event.type){

                                     case ...

                                     // plus de detail plus tard .... }

 

          

Bon, maintenant que tout est prêt, on va enfin s'occuper de la manette. Il faut indiquer à SDL que l'on va utiliser le joystick. Pour ça, il faut passer le flag SDL_INIT_JOYSTICK lors de l'initialisation de SDL. On change donc l'appel à SDL_Init en :

      SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK )

     

Ensuite, toujours dans la phase d'initialisation, il faut déclarer le Joystick et le fait qu'on veut utiliser des événements associés à la manette. Tout ceci se fait au travers des 2 lignes suivantes que l'on va, biens sûr, ajouter à Init :

      // Declarations du Joystick

                SDL_Joystick* joyStick;

                SDL_JoystickEventState(SDL_ENABLE);

          

 

Quand tout est déclaré, on doit tester si un joystick est bien branché puis l'initialiser. La fonction SDL_NumJoysticks() retourne le nombre de joysticks branchés. Si c'est supérieur à 1 , c'est que des manettes sont branchées (logique non ?).

 Pour initialiser une manette, il faut ouvrir le port en spécifiant son numéro. Dans notre cas, on va initialiser la 1ere manette (port numéro 0). avec la fonction SDL_JoystickOpen( 0 ) qui retourne un pointeur. Si ce pointeur est Null, c'est qu'un pbm a été rencontré (pas de manette sur ce port ?)

Donc, si on résume :

       // Si des pad sont branchés, initialise la joystick

           if( SDL_NumJoysticks() > 0){

                joyStick = SDL_JoystickOpen( 0 );

           if( joyStick == NULL ){

                printf( "Couldn't initialize SDL_JoystickOpen: %s\n",SDL_GetError() );

              }

           }else{

                printf( "Couldn't Enum SDL_NumJoysticks: %s\n", SDL_GetError() );

              }

    

 

 Voilà, on a tout initialisé et il ne reste plus qu'à tester les événements qui arrivent dans la file pour traiter ceux qui nous intéressent. Il existe plein d'événements différents (allez voir la doc ou le header SDL_Events) mais nous utiliserons SDL_JOYAXISMOTION qui correspond à un mouvement du stick analogique. La structure de ce type d'événement comprend (en plus de son type et de son numéro de port) l'axe bougé et la valeur. Plus le mouvement du stick est important, plus la valeur est grande mais elle reste entre -32768 et 32767. La valeur de l'axe est 0 pour l'axe horizontal et 1 pour le vertical.

Quand on capture un événement correspondant à un mouvement de manette, on va donc regarder l'axe et la valeur et agir sur la position de l'image.

Dans la boucle de traitement d'événements, on rajoute donc le cas qui va bien :

         

      // prend un evenement dans la file d'attente

           while( SDL_PollEvent(&event)){

                   switch( event.type){

                 case SDL_JOYAXISMOTION:

                              if( event.jaxis.axis == 0)

                                          {position_x = position_x + event.jaxis.value/10;}

                              else

                                          {position_y = position_y + event.jaxis.value/10;}

                  }}

 

 

Pour connaître la valeur à changer (x ou y), on teste la valeur de l'axe puis on change suivant le cas la valeur des positions en fonction. Pour prendre en compte la variation de l'amplitude des mouvements du stick, on n'augmente pas les valeurs de façon constante mais en fonction de la valeur retournée par l'événement. On divise toutefois cette valeur par 10 pour que le mouvement de l'image ne soit pas trop rapide.

Une fois les positions changées, il ne reste plus qu'à afficher le résultat avec :

       return_value = Dessiner_Image(Image ,position_x, position_y);

à la fin du while.

 

Il reste un dernier petit problème à régler : chaque fois que nous affichons une image, la précédente reste à l'écran ! Il faut donc effacer, au fur et à mesure des déplacements les anciennes images. Pour ça, on ne va pas faire dans la finesse et effacer complètement l'écran en le coloriant en noir avec la fonction SDL_FillRect.

       SDL_FillRect( MainScreen, 0, 0 ) ;

               

est donc rajouté dans la fonction qui dessine l'écran.

 Et voilà, notre petit programme est complet et donne :

      #define _arch_dreamcast

      #include <kos.h>

      #include <SDL/SDL.h>

       

      extern uint8 romdisk[];

       

      KOS_INIT_FLAGS(INIT_DEFAULT | INIT_MALLOCSTATS);

      KOS_INIT_ROMDISK(romdisk);

       

      SDL_Surface *MainScreen ;

      SDL_Surface *Image ;

      int Init()

      {

           // Init SDL et test

           if ( SDL_Init( SDL_INIT_VIDEO  | SDL_INIT_JOYSTICK ) < 0 )

                {fprintf( stderr, "Couldn't initialize SDL: %s\n", SDL_GetError() );

                return -1;}

       

           // Init ecran principal et test

           MainScreen = SDL_SetVideoMode(640, 480, 0, SDL_HWSURFACE|SDL_DOUBLEBUF);

           if ( MainScreen == NULL )

                {fprintf("Unable to set 640x480 video: %s\n", SDL_GetError());

                return -1;}

       

           // pas de curseur

                SDL_ShowCursor(0);

       

           // charge l'image dans une nouvelle surface

           Image = SDL_LoadBMP("/rd/JMD.bmp");

       

               // Declarations du Joystick

                SDL_Joystick* joyStick;

                SDL_JoystickEventState(SDL_ENABLE);

       

           // Si des pad sont branchés, initialise la joystick

           if( SDL_NumJoysticks() > 0){

                joyStick = SDL_JoystickOpen( 0 );

            if( joyStick == NULL ){

                printf( "Couldn't initialize SDL_JoystickOpen: %s\n",SDL_GetError() );

              }

           }else{

                printf( "Couldn't Enum SDL_NumJoysticks: %s\n", SDL_GetError() );

              }

      }

      int Dessiner_Image(SDL_Surface *Image,int pos_x, int pos_y)

      {

           // creation d'un rectangle destination et définition de la position

           SDL_Rect dest;

           dest.x =  pos_x ;

           dest.y =  pos_y ;

           SDL_FillRect( MainScreen, 0, 0 ) ;

       

           // affiche l'image

                SDL_BlitSurface(Image, NULL, MainScreen, &dest);

           SDL_Flip(MainScreen);

           return 0;

      }

       int main(int argc, char **argv)

      {

                SDL_Event event;

           int position_x , position_y ;

           int return_value;

           position_x = 5;

           position_y = 5;

           // Init

           if (Init()==0) {printf("Init : OK\n");}

           else {return 0;}

       

                // dessine l'image

           return_value = Dessiner_Image(Image , position_x ,  position_y );

       

           // on boucle à l'infinie pour montrer le spectacle

           int a=0;

           while(a==0)

           {  // boucle infinie  }

           return 0;

      }

              // prend un evenement dans la file d'attente

                while( SDL_PollEvent(&event)){

                   switch(event.type)

      {

                 case SDL_JOYAXISMOTION:

                              if( event.jaxis.axis == 0)

                                          {position_x = position_x + event.jaxis.value/10;}

                              else

                                          {position_y = position_y + event.jaxis.value/10;}

                  }}

                }

           return 0;

      }

       

 

 

Page suivante : 1er chapitre – 3eme Partie : Même chose mais avec des collisions sur les bords d'écran et un fond