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

  

 

        

 

 

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

 

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

 

 

Avant d'ajouter quoi que ce soit, on va créer une structure qui va nous stocker l'abscisse et l'ordonnée. Ceci va nous faciliter les passages de paramètres. On va appeler cette structure Position :

       typedef struct {

                int16 X;

                int16 Y;

           } Position;

    

Maintenant, on va se servir de cette structure pour remplacer les variables position_x et position_y :

 

- A la place des déclarations et des initialisations :

        Position Pos_ACtualPosition;

           Pos_ACtualPosition.X = 5;

           Pos_ACtualPosition.Y = 5;

   

 - A la place des passages de paramètres dans les fonctions

      int Dessiner_Image(SDL_Surface *Image, Position IN_Position)

      {

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

           SDL_Rect dest;

           SDL_FillRect( MainScreen, 0, 0 ) ;

           dest.x = IN_Position.X;

           dest.y = IN_Position.Y;

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

           SDL_Flip(MainScreen);

           return 0;

      }

 

puis comme passage :

        return_value = Dessiner_Image(Image ,Pos_ACtualPosition);

   

 Autre modification, on va d'abord modifier la façon de bouger notre image. En effet, l'utilisation des événements est bien mais n'est pas parfaite avec SDL sur DC (au moment ou j'écris). Dans tous les cas, je n'arrive pas a avoir de résultat satisfaisants. On va donc utiliser des fonctions de KOS pures et dures pour remplacer le contenu de la boucle infinie.

On va créer une fonction dont le but sera de bouger la position de l'image en fonction des actions de l'utilisateur. On va donc l'appeler Move_Image.  Son rôle va être de prendre une position, de tester les actions de l'utilisateur, de modifier puis renvoyer la position. On aura donc une structure position en entrée et en sortie :

      Position Move_Image (Position IN_Position){}

     

Il est nécessaire de mapper un contrôleur avant de pouvoir le tester. Le test retourne alors une variable de type cont_cond_t  qui indique quel bouton est pressé.

        cont_cond_t cond;

        cont_get_cond(maple_first_controller(), &cond);

 

 On va donc, par la suite, tester les 4 axes de la manette et faire évoluer notre position en fonction :

        if (!(cond.buttons & CONT_DPAD_UP)) {

                     IN_Position.Y = IN_Position.Y - 8;    }

                    if (!(cond.buttons & CONT_DPAD_DOWN)) {

                     IN_Position.Y = IN_Position.Y + 8;    }

                   if (!(cond.buttons & CONT_DPAD_RIGHT)) {

                     IN_Position.X = IN_Position.X + 8;    }

                   if (!(cond.buttons & CONT_DPAD_LEFT)) {

                     IN_Position.X = IN_Position.X - 8;    }

           

Il ne reste plus alors qu'à retourner IN_Position.

L'intérieur de la boucle infinie devient alors :

        // changement de position

                Pos_ACtualPosition = Move_Image(Pos_ACtualPosition);

        // Refresh de l'ecran

                return_value = Dessiner_Image(Image ,Pos_ACtualPosition);

          

Comme on est fainéant, on profite aussi de nos tests de la manette pour tester le bouton START. Lors de l'utilisation, on va rebooter la dreamcast. De cette manière, plus besoin de se baisser pour appuyer sur le bouton power entre chaque test.

         if (!(cond.buttons & CONT_START)) {

                     arch_reboot();   }

          

Maintenant, on va essayer de faire un fond d'écran. Pour ça, on va copier de windows un pattern  (Aquarium) et s'en servir pour tapisser l'arrière plan derrière notre image.

On copie donc aquarium.bmp dans le romdisk.

Le principe de l'arrière plan est de copier autant de fois que nécessaire le pattern pour qu'il recouvre tout l'écran. On créera donc une fonction qui s'occupe de ça. La première chose à faire est de déclarer une variable globale de type surface et de charger dedans l'image aquarium :

        SDL_Surface *Background_Pattern ;

   

puis dans Init()

      Background_Pattern = SDL_LoadBMP("/rd/Aquarium.bmp");

          

La fonction qui dessine le background doit être générique et va donc prendre un pattern et tapisser une surface avec ce pattern. Notre fonction recevra donc en entrée un pattern et une surface cible. Le prototype sera :

       void Creation_Background(SDL_Surface *pattern, SDL_Surface *Destination);

         

Je vais partir du principe qu'on ne connaît pas à l'avance la taille de l'image destination. Du coup, on va dessiner des lignes avec le pattern tant que l'écran ne sera pas rempli horizontalement et verticalement.

Une première boucle va remplir chaque ligne et une seconde va répéter l'opération tant que tout l'écran n'est pas rempli.

Pour connaître la hauteur et la largeur d'une surface, on utilise les propriétés h et w. On va utiliser des compteurs pour suivre la position à laquelle on est. L'algorithme est donc : tant que la largeur des patterns déjà écrit (soit la largeur d'un pattern multiplié par le nb de pattern) est inférieure à la largeur de l'écran, j'écris un pattern. De cette manière, on écrit une ligne complète. On englobe cette boucle d'une deuxième qui dit : tant que la hauteur de ce qui est déjà écrit (nb de ligne écrites multiplié par la hauteur d'un pattern) est inférieure ou égale à la hauteur de la surface à remplir, j'écris une nouvelle ligne. Pour écrire, on utilise la fonction Blit_surface qu'on a déjà vue. La position est définie en fonction de la position en nb de lignes (int_compt2) et en colonnes (int_compt)

Donc pour dessiner une ligne :

      void Creation_Background(SDL_Surface *pattern, SDL_Surface *Destination)

      {

           SDL_Rect dest;

           int int_compt , int_compt2;

       

           // Dessin du background

           int_compt2=0;

           while((int_compt2*(*Background_Pattern).h) <= (*Destination).h)

           {

                int_compt=0;

                while((int_compt*(*Background_Pattern).w) <= (*Destination).w)

                {

                   dest.x = int_compt*(*Background_Pattern).w;

                   dest.y = int_compt2*(*Background_Pattern).h;

                   SDL_BlitSurface(Background_Pattern, NULL, Destination, &dest);

                   int_compt++;

              }

                int_compt2++;

           }

      }

 

On va remplacer le coloriage de l'écran en noir de notre programme (SDL_FillRect( MainScreen, 0, 0 ) ;) par l'appel à la fonction Creation_Background(Background_Pattern, MainScreen); pour remplir avec le pattern  Background_Pattern la surface qui représente l'écran  MainScreen.

Pour tester les collisions, on va tester la position de l'image par rapport à la taille de l'écran. Il faut que la surface image soit inclue dans la surface écran. On va donc créer une fonction qui retourne une position et qui va prendre en paramètre les deux images et la position de l'image à tester. Si l'image est inclue, la fonction va retourner la position d'origine, sinon, la fonction va adapter la position pour qu'elle reste inclue.

      Position Image_inclus (SDL_Surface *Image_A_Tester, SDL_Surface *Image_Support, Position IN_Position)

 

Tout d'abord, on bloque à 0 les coordonnées de la position pour qu'elles ne puissent pas être négative. De cette manière, on bloque l'image en haut et à gauche.

Pour bloquer l'image à droite et en bas, il faut calculer en fonction de la taille de l'image et de la taille du support.

La position correspond à l'angle haut gauche de l'image. Donc, pour que l'image soit bloquée à droite, il faut que la position soit inférieure à la taille du support moins la largeur de l'image. C'est le même raisonnement pour le bas.

Tout ceci donne la fonction :

      Position Image_inclus (SDL_Surface *Image_A_Tester, SDL_Surface *Image_Support, Position IN_Position)

      {

           if (IN_Position.X >= (*Image_Support).w - (*Image_A_Tester).w) {IN_Position.X = (*Image_Support).w - (*Image_A_Tester).w;}

           if (IN_Position.Y >= (*Image_Support).h - (*Image_A_Tester).h) {IN_Position.Y = (*Image_Support).h - (*Image_A_Tester).h;}

           if (IN_Position.X <= 0) {IN_Position.X = 0;}

           if (IN_Position.Y <= 0) {IN_Position.Y = 0;}

                return IN_Position;}

 

 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 ;

      SDL_Surface *Background ;

      SDL_Surface *Background_Pattern ;

      SDL_Joystick* joyStick;

       

      typedef struct {

           int16 X;

           int16 Y;

      } Position;

       

      // prototypes

      Position Move_Image (Position IN_Position);

      int Init();

      int Dessiner_Image(SDL_Surface *Image, Position IN_Position);

      void Creation_Background(SDL_Surface *pattern, SDL_Surface *Destination);

      Position Image_inclus (SDL_Surface *Image_A_Tester, SDL_Surface *Image_Support, Position IN_Position);

       

      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");

           Background_Pattern  = SDL_LoadBMP("/rd/Aquarium.bmp");

       

           // 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() );

              }

           return 0;

      }

      void Creation_Background(SDL_Surface *pattern, SDL_Surface *Destination)

      {

           SDL_Rect dest;

           int int_compt , int_compt2;

       

           // Dessin du background

           int_compt2=0;

           while((int_compt2*(*Background_Pattern).h) <= (*Destination).h)

           {

                int_compt=0;

                while((int_compt*(*Background_Pattern).w) <= (*Destination).w)

                {

                   dest.x = int_compt*(*Background_Pattern).w;

                   dest.y = int_compt2*(*Background_Pattern).h;

                   SDL_BlitSurface(Background_Pattern, NULL, Destination, &dest);

                   int_compt++;

              }

                int_compt2++;

           }

      }

      int main(int argc, char **argv)

      {

           int return_value;

           Position Pos_ACtualPosition;

           Pos_ACtualPosition.X = 0;

           Pos_ACtualPosition.Y = 0;

       

           // Init all

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

           else {return 0;}

       

           // affiche une premiere fois l'image

           return_value = Dessiner_Image(Image ,Pos_ACtualPosition);

       

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

           SDL_Event event;

           int a, b=0;

           while(a==0)

           {

              // changement de position

                Pos_ACtualPosition = Move_Image(Pos_ACtualPosition);

       

              // test de collisions sur les bord d'ecrans

                Pos_ACtualPosition = Image_inclus(Image , MainScreen , Pos_ACtualPosition);

              

              // Refresh de l'ecran

                return_value = Dessiner_Image(Image ,Pos_ACtualPosition);

           }

            return 0;

      }

      Position Image_inclus (SDL_Surface *Image_A_Tester, SDL_Surface *Image_Support, Position IN_Position)

      {

              if (IN_Position.X >= (*Image_Support).w - (*Image_A_Tester).w) {IN_Position.X = (*Image_Support).w - (*Image_A_Tester).w;}

              if (IN_Position.Y >= (*Image_Support).h - (*Image_A_Tester).h) {IN_Position.Y = (*Image_Support).h - (*Image_A_Tester).h;}

              if (IN_Position.X <= 0) {IN_Position.X = 0;}

              if (IN_Position.Y <= 0) {IN_Position.Y = 0;}

                return IN_Position;

      }

      int Dessiner_Image(SDL_Surface *Image, Position IN_Position)

      {

              // creation d'un rectangle destination et definition de la position

           SDL_Rect dest;

           Creation_Background(Background_Pattern, MainScreen);

           dest.x = IN_Position.X;

           dest.y = IN_Position.Y;

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

           SDL_Flip(MainScreen);

           return 0;

      }

      Position Move_Image (Position IN_Position)

           {

                   cont_cond_t cond;

                   cont_get_cond(maple_first_controller(), &cond);

                   if (!(cond.buttons & CONT_DPAD_UP)) {

                     IN_Position.Y = IN_Position.Y - 8;    }

                   if (!(cond.buttons & CONT_DPAD_DOWN)) {

                     IN_Position.Y = IN_Position.Y + 8;    }

                   if (!(cond.buttons & CONT_DPAD_RIGHT)) {

                     IN_Position.X = IN_Position.X + 8;    }

                   if (!(cond.buttons & CONT_DPAD_LEFT)) {

                     IN_Position.X = IN_Position.X - 8;     }

                   if (!(cond.buttons & CONT_START)) {

                     arch_reboot();   }

                   return IN_Position;        

           }

 

 

 

Page suivante : 1er chapitre – 4eme Partie : Pareil avec des objets qui bougent tout seul