Partage
  • Partager sur Facebook
  • Partager sur Twitter

scolling à plusieurs vitesse en SDL

    10 avril 2010 à 17:34:31

    bonjour à tous :D

    je code un petit programme pour m'entrainer au scrolling.

    Celui-ci à pour but de faire bouger plusieurs images ( 3 ) à des vitesses de défillement diférentes
    pour créer un sensation d'espace. le défillement est infini.

    voici mon code.
    Je demande conseils et vérification de votre part. celui-ci fonctionne assez bien.
    pour le tester, il faut 4 images de 500/400 pixels en PNG.

    J'ai pu constater un petit bug que je n'arrive pas à illucider. à certain moments ( assez imprévisibles ), mes surfaces
    glissent tout seul sans que j'ai enfoncé la flèche directionnel qui fait défiller le paysage dans le sens désiré !!

    Voyez-vous quelque chose de louche dans ceci ? o_O

    /*scrolling
    
      le 10 avril 2010
    
                */
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <SDL/SDL.h> 
    #include <SDL/SDL_image.h> 
    
     
    #define LONG_ECRAN 400
    #define HAUT_ECRAN 400
    
    typedef struct 
    {  
    SDL_Surface *image, *copieImage;
    SDL_Rect imagePos, scrollPos;
    SDL_Rect copieImagePos, copieScrollPos;
    int mode, vitesse;
    }scrollage;
    
    scrollage S;
    scrollage S2;
    scrollage S3;
    
    void initStructure(scrollage *S, int nombreImage)
    {
    	if(nombreImage == 1)
             S->image = IMG_Load("image.png");
    	else if(nombreImage == 2)
    	S->image = IMG_Load("image2.png");
    	else if(nombreImage == 3)
    	S->image = IMG_Load("image3.png");
    
    	S->scrollPos.x = 0;
    	S->scrollPos.y = 0;
    	S->imagePos.x = 0;
    	S->imagePos.y = 0;
    	S->scrollPos.w = LONG_ECRAN;
    	S->scrollPos.h = HAUT_ECRAN;
    
    	// copie de l'image
    
    	if(nombreImage == 1)
             S->copieImage = IMG_Load("image.png");
    	else if(nombreImage == 2)
    	S->copieImage = IMG_Load("image2.png");
    	else if(nombreImage == 3)
    	S->copieImage = IMG_Load("image3.png");
    	
    	S->copieScrollPos.x = 0;
    	S->copieScrollPos.y = 0;
    	S->copieImagePos.x = S->copieImage->w;
    	S->copieImagePos.y = 0;
    	S->copieScrollPos.w = 0;
    	S->copieScrollPos.h = HAUT_ECRAN;
    
    	if(nombreImage == 1)
            S->vitesse = 1;
    	else if(nombreImage == 2)
    	S->vitesse = 2;
    	else if(nombreImage == 3)
    	S->vitesse = 3;
    	
    	S->mode = 0;
    }
    
    
    
    void libererStructure(scrollage *S)
    {
    SDL_FreeSurface(S->image);
    SDL_FreeSurface(S->copieImage);
    }
    
    
    
    void gauche(scrollage *S)
    {
    
    	if(S->scrollPos.x >= S->image->w - LONG_ECRAN)
             S->mode = 1;
    	if(S->scrollPos.x >= S->image->w)
    	S->mode = 2;
    	if(S->copieScrollPos.x >= S->copieImage->w - LONG_ECRAN)
             S->mode = 3;
    	if(S->copieScrollPos.x >= S->copieImage->w)
    	S->mode = 0;
    
                         switch(S->mode)
    					 {
    					 case 0:
    					 S->copieScrollPos.x = 0; 
    					 S->copieImagePos.x = LONG_ECRAN;
    					 S->copieScrollPos.w = 0; 
    
    					 S->scrollPos.w = LONG_ECRAN;
    					 S->scrollPos.x += S->vitesse;
    	                                  S->imagePos.x = 0;
    					 break;
    					 case 1:
    					 S->scrollPos.x += S->vitesse;
    	                                  S->imagePos.x = 0;
    					 S->scrollPos.w -= S->vitesse;
    
    	                                   S->copieImagePos.x = S->scrollPos.w;
    	                                   S->copieScrollPos.w = (LONG_ECRAN - S->scrollPos.w);
    					 break;
    					 case 2:
    					 S->scrollPos.w = 0; 
    					 S->scrollPos.x = 0; 
    					 S->imagePos.x = LONG_ECRAN;
    
    					 S->copieScrollPos.w = LONG_ECRAN; 
    					 S->copieScrollPos.x += S->vitesse;
    	                                  S->copieImagePos.x = 0;
    	                                   break;
    					 case 3:
    					 S->copieScrollPos.x += S->vitesse;
    	                                   S->copieImagePos.x = 0;
    					 S->copieScrollPos.w -= S->vitesse;
    
    					 S->imagePos.x = S->copieScrollPos.w;
                                               S->scrollPos.w = (LONG_ECRAN - S->copieScrollPos.w);
    					 break;
    					 }
    }
    
    
    
    void droite(scrollage *S)
    {
    	if(S->scrollPos.x <= 0)
    	S->mode = 3;
    	if(S->imagePos.x >= LONG_ECRAN)
    	S->mode = 2;
    	if(S->copieScrollPos.x <= 0)
    	S->mode = 1;
    	if(S->copieImagePos.x >= LONG_ECRAN)
    	S->mode = 0;
    
                         switch(S->mode)
    					 {
    					 case 0:
    					 S->copieScrollPos.x = S->copieImage->w;
    					 S->copieImagePos.x = 0;
    					 S->copieScrollPos.w = 0;
    
    					 S->scrollPos.x -= 1*S->vitesse;
    	                                   S->imagePos.x = 0;
    					 S->scrollPos.w = LONG_ECRAN;
    					 break;
    					 case 1:
                                               S->scrollPos.x -= S->vitesse;
    	                                   S->imagePos.x = 0;
    					 S->scrollPos.w += S->vitesse;
    
    	                                   S->copieImagePos.x = S->scrollPos.w;
    	                                   S->copieScrollPos.w = ((LONG_ECRAN*S->vitesse) - S->scrollPos.w);
    					 break;
    					 case 2:
    					 S->scrollPos.x = S->image->w;
    					 S->imagePos.x = 0;
    					 S->scrollPos.w = 0;
    
    					 S->copieScrollPos.w = LONG_ECRAN;
                                               S->copieScrollPos.x -= S->vitesse;
    					 S->copieImagePos.x = 0;
    					 break;
    					 case 3:
    					 S->copieScrollPos.x -= S->vitesse;
    	                                   S->copieImagePos.x = 0;
    					 S->copieScrollPos.w += S->vitesse;
    
    					 S->imagePos.x = S->copieScrollPos.w;
                                               S->scrollPos.w = (LONG_ECRAN - S->copieScrollPos.w);
    					 break;		 
    					 }
    }
    
    
    
    int main(int argc, char *argv[])
    {
        SDL_Surface *ecran = NULL, *fond = NULL;
    	SDL_Rect fondPos;
    	int continuer = 1;
    	SDL_Event event; 
    
        if (SDL_Init(SDL_INIT_VIDEO) == -1) 
        {
            fprintf(stderr, "Erreur d'initialisation de la SDL : %s\n", SDL_GetError()); 
            exit(EXIT_FAILURE); 
        }
    
        SDL_WM_SetIcon(IMG_Load("icone.bmp"), NULL); 
        ecran = SDL_SetVideoMode(LONG_ECRAN, HAUT_ECRAN, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
        SDL_WM_SetCaption("scroll Paysage", NULL); 
    
    	initStructure(&S, 1);
    	initStructure(&S2, 2);
    	initStructure(&S3, 3);
    
    	// fond
    
    	fond = IMG_Load("ciel.png");
    	fondPos.x = 0;
    	fondPos.y = 0;
    
       while (continuer) 
    {
        SDL_PollEvent(&event);
        switch(event.type)
       {
        case SDL_QUIT: 
        continuer = 0;
        break;
    	case SDL_KEYDOWN:               
                    switch(event.key.keysym.sym)
    				{
                     case SDLK_ESCAPE:
    					 continuer = 0;
    					 break;
    				 case SDLK_LEFT: 
    					 gauche(&S);
    					 gauche(&S2);
    					 gauche(&S3);
    					 break;
    				 case SDLK_RIGHT:	
    					 droite(&S);
    					 droite(&S2);
    					 droite(&S3);
    					 break;
    				}
    
    	}
    
        SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 0, 0, 0));
    
    	SDL_BlitSurface(fond, NULL, ecran, &fondPos);
    	
    	SDL_BlitSurface(S.image, &S.scrollPos, ecran, &S.imagePos);
    	SDL_BlitSurface(S.copieImage, &S.copieScrollPos, ecran, &S.copieImagePos);
    
    	SDL_BlitSurface(S2.image, &S2.scrollPos, ecran, &S2.imagePos);
    	SDL_BlitSurface(S2.copieImage, &S2.copieScrollPos, ecran, &S2.copieImagePos);
    
    	SDL_BlitSurface(S3.image, &S3.scrollPos, ecran, &S3.imagePos);
    	SDL_BlitSurface(S3.copieImage, &S3.copieScrollPos, ecran, &S3.copieImagePos);
    
    	SDL_Flip(ecran); 
    }
    
        libererStructure(&S);
    	libererStructure(&S2);
    	libererStructure(&S3);
    
    	SDL_FreeSurface(fond);
    
    	SDL_Quit(); 
    
        return EXIT_SUCCESS;
    }
    


    merci :D
    • Partager sur Facebook
    • Partager sur Twitter
      10 avril 2010 à 17:44:01

      A la limite si tu collais tes 4 images ici, ce serait plus simple pour nous.

      La première chose sure, c'est que tu n'as pas besoin de la surface copieImage.
      Mais, postes tes images, stp.

      • Partager sur Facebook
      • Partager sur Twitter
      Zeste de Savoir, le site qui en a dans le citron !
        10 avril 2010 à 18:03:37

        les voicis !!Image utilisateur
        Image utilisateur


        plus assez de place... quelqu'un fait un nouveau poste pour que je puisse renvoyer le reste des images ! on peu pas poster é fois d'affiler ! ;)
        là je dois y aller ! je reviens dans 2 h !
        • Partager sur Facebook
        • Partager sur Twitter
          10 avril 2010 à 18:23:20

          C'est un problème avec la fonction SDL_BlitSurface qui modifie les SDL_Rect qui lui sont passés en paramètres.

          Testes en appelant cette fonction, plutôt que SDL_BlitSurface
          void Blit(SDL_Surface *src, SDL_Rect *srcRect, SDL_Surface *dst, SDL_Rect *dstRect)
          {
              SDL_Rect tmp1Rect = *srcRect;
              SDL_Rect tmp2Rect = *dstRect;
          
              SDL_BlitSurface(src, &tmp1Rect, dst, &tmp2Rect);
          }
          


          Il subsiste un décalage, je regarde.
          • Partager sur Facebook
          • Partager sur Twitter
          Zeste de Savoir, le site qui en a dans le citron !
            10 avril 2010 à 21:24:12

            Dsl pour mon retour très tardif !

            voici le reste des images au cas ou :Image utilisateurImage utilisateur

            merci pour ta proposition.
            je vais regarder cela :) !

            Tu penses que l'on peu se passer de "copieImage" ? comment vois-tu les choses ? ^^
            • Partager sur Facebook
            • Partager sur Twitter
              10 avril 2010 à 22:05:57

              Citation : kalailuna


              Tu penses que l'on peu se passer de "copieImage" ? comment vois-tu les choses ? ^^



              Dès demain je te poste un code, sans copies de surfaces. ;)

              Pour les surfaces manquantes, ce n'est pas grave j'ai compris ce que tu faisais... :)
              • Partager sur Facebook
              • Partager sur Twitter
              Zeste de Savoir, le site qui en a dans le citron !
                10 avril 2010 à 22:46:41

                Cool ! merci :)

                J'suis content d'avoir le code d'un spécialiste !
                didont, t'as toujours pas viré ton bonnet d'anne depuis l'histoire des PNG en SDL :p
                Tu t'es rattrapé depuis ;)
                • Partager sur Facebook
                • Partager sur Twitter
                  11 avril 2010 à 9:31:36

                  Citation : kalaliluna


                  J'suis content d'avoir le code d'un spécialiste !


                  :p
                  Spécialiste de pas grand chose. :-°

                  Cadeau.
                  #include <sdl.h>
                  #include <sdl_image.h>
                  #include <stdlib.h>
                  
                  #define SCR_W       800
                  #define SCR_H       600
                  #define BPP         32
                  
                  #define N_LAYERS    4
                  
                  typedef struct input
                  {
                      SDL_bool keys[SDLK_LAST];
                      SDL_bool quit;
                  }Input;
                  
                  typedef struct layer
                  {
                      SDL_Surface *img;
                      Sint16 x, y;
                      double offsetx;
                      double speed;
                  }Layer;
                  
                  
                  void updateEvents ( Input *in )
                  {
                      SDL_Event event;
                      while ( SDL_PollEvent ( &event ) )
                      {
                          switch ( event.type )
                          {
                              case SDL_QUIT:
                                  in->quit = SDL_TRUE;
                                  break;
                              case SDL_KEYDOWN:
                                  in->keys[event.key.keysym.sym] = SDL_TRUE;
                                  break;
                              case SDL_KEYUP:
                                  in->keys[event.key.keysym.sym] = SDL_FALSE;
                                  break;
                              default:
                                  break;
                          }
                      }
                  }
                  
                  /* ------------------------------------------------------------------------- */
                  void Layer_add ( Layer *lyr, char const *filename, Sint16 x, Sint16 y, double spd )
                  {
                      lyr->img = IMG_Load ( filename );
                      if ( lyr->img == NULL )
                      {
                          fprintf ( stderr, "Error : %s\n", SDL_GetError() );
                          exit ( EXIT_FAILURE );
                      }
                  
                      lyr->img = SDL_DisplayFormatAlpha ( lyr->img );
                      if ( lyr->img == NULL )
                      {
                          fprintf ( stderr, "Error : %s\n", SDL_GetError() );
                          exit ( EXIT_FAILURE );
                      }
                  
                      lyr->x = x;
                      lyr->y = y;
                      lyr->offsetx = 0.0;
                      lyr->speed = spd;
                  }
                  
                  
                  void Layer_free ( Layer *lyr )
                  {
                      SDL_FreeSurface ( lyr->img );
                  }
                  
                  
                  
                  void Layer_display ( Layer *lyr )
                  {
                      SDL_Surface *screen = SDL_GetVideoSurface();
                      SDL_Rect srcRect, dstRect;
                  
                      if ( abs ( lyr->offsetx ) >= lyr->img->w )
                          lyr->offsetx += lyr->offsetx < 0 ? lyr->img->w : -lyr->img->w;
                  
                      dstRect.x = lyr->x;
                      dstRect.y = lyr->y;
                      dstRect.w = lyr->img->w;
                      dstRect.h = lyr->img->h;
                  
                      srcRect.x = lyr->offsetx < 0 ? lyr->img->w + lyr->offsetx : lyr->offsetx;
                      srcRect.y = 0;
                      srcRect.w = lyr->img->w - srcRect.x;
                      srcRect.h = lyr->img->h;
                  
                      while ( dstRect.x < screen->w )
                      {
                          SDL_BlitSurface ( lyr->img, &srcRect, screen, &dstRect );
                          dstRect.x += srcRect.w;
                          srcRect.x = 0;
                          srcRect.w = lyr->img->w;
                      }
                  
                  }
                  
                  
                  int main ( int argc, char *argv[] )
                  {
                      Layer layers[N_LAYERS];
                      Input input;
                      SDL_Surface *screen;
                      Uint32 i;
                  
                      if ( SDL_Init ( SDL_INIT_VIDEO ) < 0 )
                      {
                          fprintf ( stderr, "Unable to init SDL: %s\n", SDL_GetError() );
                          exit ( EXIT_FAILURE );
                      }
                  
                      screen = SDL_SetVideoMode ( SCR_W, SCR_H, BPP, SDL_SWSURFACE );
                      if ( screen == NULL )
                      {
                          fprintf ( stderr, "Couldn't set video mode: %s\n", SDL_GetError() );
                          exit ( EXIT_FAILURE );
                      }
                  
                      /* 4 background avec un décalage en y et une vitesse différente */
                      Layer_add ( &layers[0], "image.png", 0, 170, 0.0 );
                      Layer_add ( &layers[1], "image.png", 0, 180, 0.5 );
                      Layer_add ( &layers[2], "image.png", 0, 190, 3.0 );
                      Layer_add ( &layers[3], "image.png", 0, 200, 4.0 );
                  
                      /* On applique un petit décalage */
                      layers[1].offsetx = -5.0;
                      layers[2].offsetx = -10.0;
                      layers[3].offsetx = 12.0;
                  
                      memset ( &input, 0, sizeof input);
                      while ( !input.keys[SDLK_ESCAPE] && !input.quit )
                      {
                          updateEvents ( &input );
                  
                          if ( input.keys[SDLK_LEFT] )
                              for ( i = 0; i < N_LAYERS; i++ )
                                  layers[i].offsetx += layers[i].speed;
                  
                          if ( input.keys[SDLK_RIGHT] )
                              for ( i = 0; i < N_LAYERS; i++ )
                                  layers[i].offsetx -= layers[i].speed;
                  
                          SDL_FillRect ( screen, NULL, 0 );
                  
                          for ( i = 0; i < N_LAYERS; i++ )
                              Layer_display ( &layers[i] );
                  
                          SDL_Flip ( screen );
                      }
                  
                      for ( i = 0; i < N_LAYERS; i++ )
                          Layer_free ( &layers[i] );
                  
                      return EXIT_SUCCESS;
                  }
                  


                  Ce que tu peux faire,
                  • Utiliser une liste chaînée plutôt qu'un tableau pour stocker les layers.
                  • Encapsuler davantage pour éviter de voir les boucles for dans ton code.
                  • Appliquer le même principe à l'axe y.


                  M'enfin, la base est là.
                  Pour la gestion des events, c'est la méthode présentée par fvirtman dans son tuto, si tu ne connais pas ça peux surprendre, mais j'ai pris l'habitude de faire ainsi.
                  Si tu as des questions, n'hésite pas.
                  • Partager sur Facebook
                  • Partager sur Twitter
                  Zeste de Savoir, le site qui en a dans le citron !
                    11 avril 2010 à 11:37:59

                    Ouuf :-°

                    ca calme :p

                    Ton code semble bien plus fonctionnel et pratique car tu peux faire du scrolling sans copie de surface et avec des images pouvant etre plus petite que la taille de l'écran.

                    J'ai plusieurs questions car en effet, je ne comprend pas tout :

                    1)quel est le type sint16 ? je ne connais pas o_O
                    2) à quoi sert la fonction SDL_DisplayFormatAlpha ( lyr->img ); dans layer add ?
                    3)plus grave : je ne comprend pas ta fonction Layer_display. pourrais-tu m'en décrire le fonctionnement ?
                    je ne comprend pas plusieurs éléments de cette fonction :

                    3)1)d'ou vient abs ?
                    3)2)cette ligne est un mystere pour moi :

                    lyr->offsetx += lyr->offsetx < 0 ? lyr->img->w : -lyr->img->w;

                    le point d'interrogation me laisse pentoi. pareil pour les "deux points" en fin de ligne.. :euh:
                    Je pense que je n'ai pas encore assez poussé le code en C, d'ou mes incompréentions;

                    4)enfin, l'enploi du double pour offset m'intrigue car je ne savais pas qu l'on pouvait envoyer ce type en paramettre d'un Sdl_Rect.

                    Si t'a la patience pour répondre je te dis chapeau :zorro:
                    • Partager sur Facebook
                    • Partager sur Twitter
                      11 avril 2010 à 12:04:26

                      Alors je vais tenter de répondre à toutes les questions. :p

                      Citation


                      quel est le type sint16 ? je ne connais pas o_O


                      C'est un type défini par la sdl c'est un entier signé.

                      Tu le retrouve par exemple dans la définition de la structure SDL_Rect pour les coordonnées.
                      typedef struct{
                        Sint16 x, y;
                        Uint16 w, h;
                      } SDL_Rect;
                      


                      Citation

                      à quoi sert la fonction SDL_DisplayFormatAlpha ( lyr->img ); dans layer add ?


                      Cette fonction sert à convertir la surface au format de l'écran tout en conservant le canal alpha.
                      Si tu ne l'utilises pas la conversion(copie de surface) à lieu à chaque et plombe les performances.
                      Voir la FAQ bibliothèque tierce, et mon fameux post sur les PNG. ;)

                      Citation

                      d'ou vient abs ?


                      C'est une fonction déclarée dans <stdlib.h> qui retourne la valeur absolue d'un entier.
                      <man>abs

                      Citation


                      cette ligne est un mystere pour moi :

                      lyr->offsetx += lyr->offsetx < 0 ? lyr->img->w : -lyr->img->w;


                      Je reconnais que c'est peu digeste. :p
                      ca se traduit en
                      if(lyr->offsetx < 0)
                          lyr->offsetx += lyr->img->w;
                      else
                          Lyr->offsetx -= lyr->img->w
                      

                      On est dans le cas ou la valeur absolue de offset est >= la largeur de la surface.
                      Si le décalage est inférieur à 0 on rajoute la largeur
                      sinon on soustrait la largeur pour rester dans las plage -w < offset < w.

                      Enfin

                      Citation


                      enfin, l'enploi du double pour offset m'intrigue car je ne savais pas qu l'on pouvait envoyer ce type en paramettre d'un Sdl_Rect.


                      Pour l'emploi du type double, ca permet d'avoir une vitesse par exemple de 0.5, et un décalage réel.
                      Lors du passage à SDL_Rect seule la partie entière est conservée, mais malgré tout le décalage n'est pas altéré.

                      En espérant que ce soit plus clair. ;)

                      • Partager sur Facebook
                      • Partager sur Twitter
                      Zeste de Savoir, le site qui en a dans le citron !
                        11 avril 2010 à 12:32:47

                        Merci :D


                        C'est plus clair.
                        Je vais digérer tout ça et tenter de me l'approprier avec ta permission :p

                        Pour le moment je ne vois pas d'autres questions !

                        Merci a toi pour avoir pris tout ce temps pour coder puis m'expliquer !

                        Aller fait moi plaisir, remplace ton avatar avec celui-ci ;)
                        Image utilisateur
                        • Partager sur Facebook
                        • Partager sur Twitter
                          11 avril 2010 à 14:02:30

                          :p
                          Non, il est bien ce bonnet d'âne!

                          Citation


                          Je vais digérer tout ça et tenter de me l'approprier avec ta permission :p


                          Ce n'est pas à moi ça, c'est à tout le monde... ;)
                          • Partager sur Facebook
                          • Partager sur Twitter
                          Zeste de Savoir, le site qui en a dans le citron !

                          scolling à plusieurs vitesse en SDL

                          × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                          × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                          • Editeur
                          • Markdown