Déplacer plusieurs objets en même temps.

Déplacer plusieurs objets.

Voir version :

Dépendances (dans l'archive) :
balle.bmp

Télécharger :

#include <sdl/sdl.h>

#pragma comment(lib,"sdl.lib")
#pragma comment(lib,"sdlmain.lib")

#define XRESOL 1000
#define YRESOL 800
#define FULLSCREEN 0
#define NBSPRITE 2000

struct Sprite
{
    int x,y;
    int vx,vy;
    SDL_Surface* srf;
};

SDL_Surface* Charger(const char* fic)
{
    SDL_Surface *res;
    SDL_Surface* tmp = SDL_LoadBMP(fic);
    if (tmp==NULL)
    {
        printf("Erreur chargement %s\n",fic);
        exit(-1);
    }
    res = SDL_DisplayFormat(tmp);
    SDL_FreeSurface(tmp);
    return res;
}

int KeyHit()
{
    SDL_Event e;
    if (SDL_PollEvent(&e))
        if (e.type == SDL_KEYDOWN)
            return 1;
    return 0;
}

void Blit(SDL_Surface* source,SDL_Surface* dest,int x,int y)
{
    SDL_Rect R;
    R.x = x;
    R.y = y;
    SDL_BlitSurface(source,NULL,dest,&R);
}

void Initialiser(struct Sprite* sp,SDL_Surface* srf)
{
    sp->x = rand()%(XRESOL-50);
    sp->y = rand()%(YRESOL-50);
    sp->vx = rand()%7-3;
    sp->vy = rand()%7-3;
    if (sp->vx==0 && sp->vy==0)
        sp->vx = 1;
    sp->srf = srf;
}

void Evoluer(struct Sprite* sp)
{
    sp->x+=sp->vx;
    sp->y+=sp->vy;
    if (sp->vx<0 && sp->x<0)
        sp->vx = -sp->vx;
    if (sp->vy<0 && sp->y<0)
        sp->vy = -sp->vy;
    if (sp->vx>0 && sp->x>(XRESOL-50))
        sp->vx = -sp->vx;
    if (sp->vy>0 && sp->y>(YRESOL-50))
        sp->vy = -sp->vy;
}

int main(int argc,char** argv)
{
    struct Sprite TabSprite[NBSPRITE];
    SDL_Surface* balle,*screen;
    int i;
    SDL_Init(SDL_INIT_VIDEO);
    if (FULLSCREEN)
        screen=SDL_SetVideoMode(XRESOL,YRESOL,32,SDL_HWSURFACE|SDL_DOUBLEBUF|SDL_FULLSCREEN);  
    else
        screen=SDL_SetVideoMode(XRESOL,YRESOL,32,SDL_SWSURFACE|SDL_DOUBLEBUF);  
    balle=Charger("balle.bmp");
    SDL_SetColorKey(balle,SDL_SRCCOLORKEY ,SDL_MapRGBA(balle->format,0,0,0,0));
    for(i=0;i<NBSPRITE;i++)
    {
        Initialiser(&TabSprite[i],balle);
    }
    while(!KeyHit())
    {
        SDL_FillRect(screen,NULL,0);
        for(i=0;i<NBSPRITE;i++)
        {
            Evoluer(&TabSprite[i]);
            Blit(TabSprite[i].srf,screen,TabSprite[i].x,TabSprite[i].y);
        }
        SDL_Flip(screen);
    }
    SDL_FreeSurface(balle);
    SDL_Quit();
    return 0;
}




Commentaires

	Pour faire bouger plusieurs objets en même temps, certains préconisent les threads.
	Je pense que c'est beaucoup trop violent.

	Voici comment le faire, sans threads.

	Tout d'abord, considérons une structure Sprite. Un sprite est un objet mobile.
	Dedans, coordonnées x,y et vecteur de déplacement vx,vy : dans quel sens part le sprite.

	Dans le main, un tableau de Sprites (de taille NBSPRITE, du #define plus haut).
	Amusez vous à lancer le programme, puis modifiez les #define en haut pour voir :) 
	Vous pouvez également changer la résolution d'écran et le fait d'être en plein écran ou non.

	Je charge une balle comme dans les exemples précédents. 
	Puis je fais un for, et je lance Initialiser sur chaque sprite.

	Regardons cette fonction : je définis une position x,y aléatoirement pour chaque sprite.
	Je définis que chaque image est une balle (pour chacun)
	Je définis un vecteur de déplacement : rand()%7-3 va nous sortir un nombre aléatoire entre -3 et 3
	Si x et y valent 0, je dis que x = 1, car je ne veux pas de balle qui ne bouge pas.

	Retournons dans le main, nous entrons dans le while (qui se coupera si vous appuyez sur une touche)
	Dedans, je repeins le fond en noir, puis je fais un for sur chaque sprite :

	- il évolue
	- je l'affiche

	Pour l'évolution, j'additionne vx à x et vy à y : déplacement selon le vecteur.
	Puis, pour gérer les rebonds, 4 if : si je suis trop à gauche et que le vecteur va à gauche, on le retourne pour qu'il
	reparte vers la droite. Pareil pour la droite, haut, bas.
	Voila donc comment je fais bouger mon sprite : en changeant x,y dans la structure.

	Pour l'affichage, c'est la fonction blit que j'ai employé dans l'exemple précédent. Je lui passe l'image du sprite,
	le x et le y.

	Et voila.

	Amusez vu à changer l'entier du #define du haut pour voir :)

	La fonction Charger : 
	---------------------

	Je charge l'image comme avant, je sors en mettant un message si je ne la trouve pas.
	Ce qui est intéressant est le SDL_DisplayFormat, ou je recrée une deuxième surface à partir de la première, qui aura comme particularité d'avoir
	les mêmes propriétés que le "vidéo buffer", c'est à dire votre "screen".
	Si vous ne le faites pas, et que les surfaces n'ont pas le même format, elles sont converties à chaque blit : c'est long et lourd.
	Si vous le faites, vous gagnez énormément en vitesse. 
	Pour vous en convaincre, essayez de virer le SDL_Delay à la fin du main, et lancez le programme : la surface défilera très vite. 
	Shuntez le SDL_DisplayFormat en retournant tmp juste avant, vous verrez que ce sera beaucoup plus lent.