menu

Billard avec SDL

Par Pierre

Télécharger

  • la video
  • le code source à compiler
  • les boules rouge et bleue

    Objectifs :

    N'a pas été fait : la structuration du projets en sous fichiers assemblés par #include qui n'ont pas été reconnus à la compilation.

    Non plus : le transport du projet sur clef USB. La librairie SDL n'est plus reconnue au changement d'ordinateur....

    Reste un artefact lors de certains chocs boule/boule dans lesquels elles se retrouvent collées l'une à l'autre

    Création de la table

    Initialisation du mode vidéo

    L'initialisation est faite dans la fonctino principale : main
    if ( SDL_Init( SDL_INIT_VIDEO|SDL_INIT_TIMER) <0 )
    	{
    		printf( "initialisation impossible
    	   		de SDL: %s\n", SDL_GetError() );
    		return 1;
        }
    

    Essaye d'initialiser le mode vidéo et la gestion du temps.

    En cas d'erreur, SDL_Init renvoie un résultat négatif et le printf écrit le message dans le fichier standard de sortie : stdout.txt qui se trouve dans le sous répertoire bin

    atexit(SDL_Quit);
    
    s'assure de la bonne fermeture à la fin
    SDL_Surface* ecran = SDL_SetVideoMode(
    		LARGEUR_ECRAN, HAUTEUR_ECRAN, 32,
    		SDL_HWSURFACE|SDL_DOUBLEBUF);
    
    

    Réserve en mémoire vidéo (SDL_HWSURFACE) unemplacement pour placer une image en couleur 32bits (232 couleurs) avec, si possible, un double tampon (SDL_DOUBLEBUF) d'affichage :

    l'image est préparée dans le tampon et affichée d'un seul coup lorsqu'elle est prète par SDL_blit

    Cette image sera accessible par la variable pointeur ecran de type SDL_Surface

    if ( !ecran )
        {
            printf("Impossible de créer
    	   	le rectangle video: %s\n", SDL_GetError());
            return 1;
        }
    
    envoie un message d'erreur si la rservation de mémoire n'a pas pu se faire
    SDL_FillRect(ecran, NULL,
    	SDL_MapRGB(ecran->format, 255,255,255));
    
    Crée un rectangle de couleur à partir du bord haut gauche (NULL) en couleur (Red Green Blue =RGB) blanche dans l'image ecran
    SDL_WM_SetCaption("Billard", NULL);
    
    
    Affiche le nom Billard en haut de la fenêtre.

    Bords dégradés et en biseau

    C'est une image qui va être créée, pour laquelle il faut réserver une zone en mémoire avec SDL_CreateRGBSurface que l'on rempli de blanc avec SDL_FillRect

    Les bord seront faits en dégradés par une succession de lignes horizontales et de barres verticales de plus en plus sombres.

    Pour obtenir des bords biseautés, il faut placer la ligne à des coordonnées décalées et à une longueur dimiuée de 2. (un pixel perdu à chaque extrémité)

    Pour griser, on augmente la quantité de Red Green et Blue du de 255/epaisseur à chaque ligne/barre

    Une fois le fond créé, on peut libérer la mémoire de ligne et de barre
    SDL_Surface* creerLeFond(int epaisseur)
    {
        //creation d'une surface blanche unie
        SDL_Surface *leFond=SDL_CreateRGBSurface(SDL_HWSURFACE, LARGEUR_ECRAN, HAUTEUR_ECRAN, 32, 0, 0, 0, 0);
        SDL_FillRect(leFond, 0, SDL_MapRGB(leFond->format, 255, 255, 255));
    
        //création d'un dégradé de gris
        //sur des lignes horizontale et des barres verticales
    
        SDL_Surface *ligne=SDL_CreateRGBSurface(SDL_HWSURFACE, LARGEUR_ECRAN, 1, 32, 0, 0, 0, 0);
        SDL_Surface *barre=SDL_CreateRGBSurface(SDL_HWSURFACE, 1, HAUTEUR_ECRAN, 32, 0, 0, 0, 0);
    
        SDL_Rect dstHorHaut,dstHorBas,dstVertDrt,dstVertGch,tailleH,tailleV;
    
        // dst est la position de collage
        dstHorHaut.x=0;
        dstHorHaut.y=0;
        dstHorBas.x=0;
        dstHorBas.y=HAUTEUR_ECRAN;
        dstVertDrt.x=0;
        dstVertGch.y=0;
        dstVertDrt.x=LARGEUR_ECRAN;
        dstVertDrt.y=0;
    
        // longeur de ligne à coller
        tailleH.w=LARGEUR_ECRAN;
        tailleH.h=1;
        tailleH.x=0;
        tailleH.y=0;
    
        //longueur de la barre à coller
        tailleV.w=1;
        tailleV.h=HAUTEUR_ECRAN;
        tailleV.x=0;
        tailleV.y=0;
    
    
        int i=0;
        int pas=int(255/epaisseur);
        for (i=epaisseur;i>0;i--)
        {
            //décalage de 1 de la position de collage et diminution de 2 de la largeur à coller
            // pour avoir un biseau dans l'angle
    
            //ligne du haut
            dstHorHaut.x++;
            dstHorHaut.y++;
    
            //ligne du bas
            dstHorBas.x++;
            dstHorBas.y--;
            tailleH.w-=2;
    
            //barre de droite
            dstVertGch.x++;
            dstVertGch.y++;
    
            //barre de gauche
            dstVertDrt.x--;
            dstVertDrt.y++;
            tailleV.h-=2;
    
            // grise la ligne
            SDL_FillRect(ligne, NULL, SDL_MapRGB(ligne->format, pas*i,pas*i,pas*i));
            SDL_BlitSurface(ligne, &tailleH , leFond, &dstHorBas);
            SDL_BlitSurface(ligne, &tailleH , leFond, &dstHorHaut);
    
    
            // grise la barre
            SDL_FillRect(barre, NULL, SDL_MapRGB(ligne->format, pas*i,pas*i,pas*i));
            SDL_BlitSurface(barre, &tailleV , leFond, &dstVertDrt);
            SDL_BlitSurface(barre, &tailleV , leFond, &dstVertGch);
    
        };
        SDL_free(ligne);
        SDL_free(barre);
        return leFond;
    }
    
    
    

    Placer les boules

    Pour cela on
  • définit les structures
  • charge le taleau des boules
  • place enfin les boules à la souris

    Définir les structures

    La structure vecteur ne contient que 2 champs : ses coordonnées .x, .y.
    ils sont de type float afin de permettre des mouvements de moins d'un pixel.

    La structure boule contiendra des champ de

  • position, .coord
  • de vitesse .vitesse de type .vecteur
  • et d'image .img pointeur SDL_Surface*

    Les fonctions permettront de tester le ercouvrement des boules lors du placement (et plus tard, lors des déplacements)

    typedef struct vecteur
    {
        float x,y;
    }  vecteur;
    typedef struct tBoule
    {
        vecteur coord,vitesse;
        SDL_Surface* img;
    } tBoule;
    
    float distCarre(vecteur point1, vecteur point2)
    {
        return (point1.x-point2.x)*(point1.x-point2.x)+(point1.y-point2.y)*(point1.y-point2.y);
    }
    
    float norme(vecteur v)
    {
        return sqrt( v.x*v.x+v.y*v.y);
    }
    
    float prodScal(vecteur u, vecteur v)
    {
        return u.x*v.x+u.y*v.y;
    }
    
    

    Création de la liste des boules

    Un tableau de boules est créé dans la fonction prncipale main.
    Il est ensuite initialisé par chargeBoulespour le.img et la vitesse (nulle)

    tBoule liste[NOMBRE_DE_BOULES];
    
    int chargeBoules(tBoule *liste,int nbrBoules)
    {
        SDL_Surface* boule = SDL_LoadBMP("boule.bmp");
        if (!boule)
        {
            printf("n'a pas pu cherger l'image: %s\n", SDL_GetError());
            return 0;
        }
        SDL_Surface* bouleBleue = SDL_LoadBMP("bouleBleue.bmp");
        if (!bouleBleue)
        {
            printf("n'a pas pu cherger l'image: %s\n", SDL_GetError());
            return 0;
        }
    
        //définit la couleur blanche
        Uint32 couleurTransparence=SDL_MapRGB(boule->format, 255, 255, 255);
    
        //rend le blanc transparent
        SDL_SetColorKey(boule, SDL_SRCCOLORKEY, couleurTransparence);
        SDL_SetColorKey(bouleBleue, SDL_SRCCOLORKEY, couleurTransparence);
    
        // affecte l'image à la boule
        int i=0;
        for (i=0;i<nbrBoules-1;i++)
        {
            liste[i].img=boule;
            liste[i].vitesse.x=0;
            liste[i].vitesse.y=0;
        }
        liste[nbrBoules-1].img=bouleBleue;
        return 1;
    }
    

    Place les boules à la souris

    la fonction placeBoules fait ce travail.

    On déplace la souris au centre de l'écran avec SDL_WarpMouse puis,
    Pour chaque boule for (i=0;i <nbrBoules;i++)

    1. on met en tampon la partie de l'écran où l'on pose la boule.
    2. on attend les événements SDL_MOUSEDOWN avec SDL_WaitEvent(&event); pour lequel
      1. on test le non recouvrement avec d'autres boules et le bord et si non
      2. on repose le tampon,
      3. on pose la boule
      4. et on mémorise les coordonnées du point
    3. ou SDL_MOUSEMOTION pour lequel
      1. on test le non recouvrement avec le bord, et si non,
      2. on repose le tampon,
      3. on met en tampon la partie de l'écran où l'on dépose la boule
    4. jusqu'au positionnement de la boule au au SDL_QUIT
    Il ne reste qu'à libérer la mémoire tampon avec SDL_Free

    
    int placeBoules(tBoule *liste,int nbrBoules,SDL_Surface *ecran)
    {
    
        // place le curseur au centre
        // promène les boules jusqu'au clic
        // et n'accepte le clic que si la position n'empiète sur aucune des boules déja placées.
    
        // au clic, affecte les coordonnées aux centres de chaque boule.
        // et une vitesse nulle.
    
        SDL_Surface* boule;
        SDL_Surface* tamponBoule;
        // fstBoule contient la position précédente/courante de la boule
        SDL_Rect tailleBoule,dstBoule,origine;
        vecteur coordi; // coordonnées du candidat
        int x,y,diametreCarre;
    
    
    // replace la souris au centre
    
        x=LARGEUR_ECRAN/2;
        y=HAUTEUR_ECRAN/2;
        SDL_WarpMouse(x,y);
    
    // i boule courante, j boule comparée
        int i=0,j=0;
    
    ////////////////////////////////////// pour chaque boule/////////////////////////////////////////
    
        for (i=0;i <nbrBoules;i++)
        {
            // boule promenée à l'écran
            boule=liste[i].img;
    
            // cree le tampon boule
            SDL_GetClipRect(boule, &tailleBoule);
            tamponBoule = SDL_CreateRGBSurface(SDL_HWSURFACE, tailleBoule.w, tailleBoule.h, 32, 0, 0, 0, 0);
    
            dstBoule.x=x- boule->w/2;
            dstBoule.y=y- boule->h/2;
            dstBoule.h=boule->h;
            dstBoule.w=boule->w;
    
            // met en tampon le dessous de la boule
            SDL_BlitSurface(ecran,&dstBoule,tamponBoule,NULL);
    
            // et colle la boule sur l'écran
            SDL_BlitSurface(boule,NULL,ecran,&dstBoule);
            SDL_Flip(ecran);
    
    
    /////////////////////////////// attend un mouvement de souris ou un clic/////////////////////////////
            int attend=1;
            int flag=0;
    
            SDL_Event event;
            while (attend)
            {
                // met en veille en attendant un événement
                SDL_WaitEvent(&event);
                switch(event.type)
                {
                    case SDL_QUIT : // Si c'est un évènement de type "Quitter"
                        return 0;
                    break;
    
    
    ////////////////////////////// si c'est un clic, //////////////////////////////////////////////////////
    
    
                    // vérifier d'abord la compatibilité avec les bords
                    // ne poser la boule  que dans ce cas
    
                    case SDL_MOUSEBUTTONDOWN :
                        SDL_GetMouseState(&x,&y);
    
                        // le pointeur dépasse la bordure
                        if (x <EPAISSEUR+boule->w/2) {break;}
                        if (x+boule->w/2+EPAISSEUR>LARGEUR_ECRAN){break;}
                        if (y <EPAISSEUR+boule->h/2){break;}
                        if (y+boule->h/2+EPAISSEUR>HAUTEUR_ECRAN) {break;}
    
                   // disjoinction des boules déja placée : de 0 à i-1
    	          // leurs distance doit être de plus de 2 rayons
    
                        flag=0;
                        coordi.x=x;
                        coordi.y=y;
                        for (j=0;jh)+boule->h;
                            diametreCarre*=diametreCarre/4;
                            if ( int(distCarre(liste[j].coord,coordi)) <diametreCarre)
                            {
                                flag=1;
                                break; // arrete seulement le "for j"
                            }
    
                        }
                        if (flag)
                        {
                            break;
                        };
    
    //////////////////////////////////// si la place est libre  //////////////////////////////////////
    
                        // repose le tampon
                        // dstBoule  continent l'ancienne position
                        SDL_BlitSurface(tamponBoule,NULL,ecran,&dstBoule);
    
                        // affecte les coordonnées
                        liste[i].coord.x=x;
                        liste[i].coord.y=y;
    
                        //et pose définitivement la boule sans mettre en tampon
                        dstBoule.x=x-boule->w/2;
                        dstBoule.y=y-boule->h/2;
                        SDL_BlitSurface(boule,NULL,ecran,&dstBoule);
                        SDL_Flip(ecran);
                        attend=0;
                    break;
    
    //////////////////////////////////// si il y a un mouvement de souris ////////////////////////////
    
              case SDL_MOUSEMOTION :
              // force à rester dans le billard
                        SDL_GetMouseState(&x,&y);
                        if (x- boule->w/2<EPAISSEUR)
                        {
                            x=EPAISSEUR+boule->w/2;
                        }
                        if (x+boule->w/2+EPAISSEUR>LARGEUR_ECRAN)
                        {
                            x=LARGEUR_ECRAN-EPAISSEUR-boule->w/2;
                        }
                        if (y- boule->h/2<EPAISSEUR)
                        {
                            y=EPAISSEUR+boule->h/2;
                        }
    
                        if (y+boule->h/2+EPAISSEUR>HAUTEUR_ECRAN)
                        {
                            y=HAUTEUR_ECRAN-EPAISSEUR-boule->h/2;
                        }
    
    ////////////////////////////// déplace la boule ///////////////////////////////////////////////////
    				// repose le tampon
                        SDL_BlitSurface(tamponBoule,NULL,ecran,&dstBoule);
    
                        // met en tampon
                        dstBoule.x=x- boule->w/2;
                        dstBoule.y=y- boule->h/2;
                        dstBoule.h=boule->h;
                        dstBoule.w=boule->w;
    
                        origine.x=0;
                        origine.y=0;
    
                        SDL_BlitSurface(ecran,&dstBoule,tamponBoule,&origine);
                        // colle la boule
                        SDL_BlitSurface(boule, NULL, ecran, &dstBoule);
                        SDL_Flip(ecran);
    
                    break;
                }
    
            }
        }
        SDL_FreeSurface(tamponBoule);
        return 1;
    
    }
    

    le jeux

    La fonction jouer s'occupe successivement de
  • demander une impulsion
  • puis répète, pour chaque boule
  • déplacer
  • faire rebondir
  • jusqu'à l'arrêt de toutes les boules (déterminé par V_MINI) : Si le drapeau (flag) continuer est encore à 0, c'est que toutes les boules sont immobiles.

    jouer

    ///////////////////// dans la fonction     main //////////////////////////
    while (jouer(liste,NOMBRE_DE_BOULES,ecran,fond))
        {
            ;
    
        }
    
    
    
    ////////////// prend l'impulsion et fais bouger les boules jusqu'à l'arret /////////////////
    
    int jouer(tBoule *liste,int nbrBoules,SDL_Surface *ecran,SDL_Surface *fond)
    {
        SDL_Rect origine,dstBoule;
        int i,j,continuer=1;
        Uint32 temps=SDL_GetTicks();
    
        // attend une impulsion
        while (continuer)
        {
            continuer=impulsion(liste,nbrBoules,ecran);
            if (!continuer)
            {
                return 0;
            }
    
    
    
    
    /////////////////////////// déplace les boules jusqu'à l'arret : toutes < V_MINI ////////////
    
            // s'arrete si SDL_EXIT
            while (continuer)
            {
                continuer=0;
                for (i=0;i<NOMBRE_DE_BOULES;i++)
                {
    
           // ralenti la boule boule
                    liste[i].vitesse.x*=VISCOSITE;
                    liste[i].vitesse.y*=VISCOSITE;
    
    	  // test si la vistesse est suffisante
                    if ( fabs(liste[i].vitesse.x)+fabs(liste[i].vitesse.y)>V_MINI )
                    {
                        continuer=1;
                    }
                    else
                    {
                        liste[i].vitesse.x=0;
                        liste[i].vitesse.y=0;
                    }
    
           // déplace la boule
                    deplaceBoule(&(liste[i]));
    
    
           // test et fait rebondir sur les bords et sur toutes les autres boules.
                    rebondBouleBord(liste[i], &liste[i]);
                    for (j=0;j<NOMBRE_DE_BOULES;j++)
                    {
                        if (i!=j)
                        {
                            rebondBouleBoule(liste[i],liste[j],&liste[i],&liste[j]);
                        }
                    };
    
                }
    
    
           //affiche toutes les boules
                origine.x=0;
                origine.y=0;
                SDL_BlitSurface(fond,NULL,ecran,&origine);
                for (i=0;i<NOMBRE_DE_BOULES;i++)
                {
                    dstBoule.x=liste[i].coord.x-liste[i].img->h/2;
                    dstBoule.y=liste[i].coord.y-liste[i].img->w/2;
                    SDL_BlitSurface(liste[i].img,NULL,ecran,&dstBoule);
                }
                while(SDL_GetTicks()<temps+20){};
                temps=SDL_GetTicks();
                //printf(" %d\n", temps);
                SDL_Flip(ecran);
            };
    
        }
    
    }
    
    

    Impulsion

    C'est la fonction impulsion qui en a la charge :
  • on attend le clic jusqu'à ce qu'il se produise sur une boule (utilisation de distcarre )
  • on attend alors le SDL_MOUSEUP en déplaçant la boule (mise en tampon du fond)
  • et on affecte comme vistesse à la boule selectionnée une portion de la distance entre la boule et la souris déterminée par COEF_VITESSE

    //////////////////// attend le clicdown ///////////////////////////////////////
    
    int impulsion(tBoule *liste,int nbrBoules,SDL_Surface *ecran)
    {
    
        float vx=0,vy=0,rayonCarre;
        int x,y,i,numBouleChoisie;
        vecteur coordSouris;
    
        // attend le clic
        int attend=1;
        SDL_Event event;
    
        while (attend)
        {
            SDL_WaitEvent(&event); // Récupèration de l'évènement dans event
            switch(event.type) // Test du type d'évènement
            {
                case SDL_QUIT : // Si c'est un évènement de type "Quitter"
                    return 0;
                    attend=0;
                break;
    
    /////////////////// en cas de clic chercher la boule cliquée ////////////////////
    
                case SDL_MOUSEBUTTONDOWN :
                   // récupère les coordonnées du point de clic
                   SDL_GetMouseState(&x,&y);
                   coordSouris.x=x;
    			coordSouris.y=y;
    		// cherche si une des boules est à moins d'un rayon du clic
                    for (i=0;i<nbrBoules;i++)
                    {
                        rayonCarre=liste[i].img->h/2;
                        rayonCarre*=rayonCarre;
                        if (distCarre(liste[i].coord,coordSouris)<=rayonCarre)
                        {
                            numBouleChoisie=i;
                            attend=0;
                            break;
                        }
                    }
                break;
            }
        }
    
    
    
    
    
    ////////////////////// étire (déplace la boule) en attendant le lacher /////////////////
    
        attend=1;
        SDL_Surface *boule,*tamponBoule;
        boule=liste[numBouleChoisie].img;
    
    
        SDL_Rect tailleBoule,dstBoule,origine;
        SDL_GetClipRect(boule, &tailleBoule);
        tamponBoule = SDL_CreateRGBSurface(SDL_HWSURFACE, tailleBoule.w, tailleBoule.h, 32, 0, 0, 0, 0);
    
        // calcule le recangle occupé par la boule
        dstBoule.x=x- boule->w/2;
        dstBoule.y=y- boule->h/2;
        dstBoule.h=boule->h;
        dstBoule.w=boule->w;
    
       // met en tampon le dessous de la boule
        SDL_BlitSurface(ecran,&dstBoule,tamponBoule,NULL);
    
    
        while (attend)
        {
            SDL_WaitEvent(&event);
            switch (event.type)
            {
                case SDL_QUIT:
                    attend=0;
                    return 1;
                break;
    
    
    //////////////////////// déplace la boule en suivant la souris ///////////////////////
    
                	case SDL_MOUSEMOTION :
              	// force à rester dans le billard
              	// EPAISSEUR est celle de la partie dégradée
                        SDL_GetMouseState(&x,&y);
                        if (x- boule->w/2<EPAISSEUR)
                        {
                            x=EPAISSEUR+boule->w/2;
                        }
                        if (x+boule->w/2+EPAISSEUR>LARGEUR_ECRAN)
                        {
                            x=LARGEUR_ECRAN-EPAISSEUR-boule->w/2;
                        }
                        if (y- boule->h/2<EPAISSEUR)
                        {
                            y=EPAISSEUR+boule->h/2;
                        }
    
                        if (y+boule->h/2+EPAISSEUR>HAUTEUR_ECRAN)
                        {
                            y=HAUTEUR_ECRAN-EPAISSEUR-boule->h/2;
                        }
    
                        // repose le tampon
                        SDL_BlitSurface(tamponBoule,NULL,ecran,&dstBoule);
    
                        // met en tampon
                        dstBoule.x=x- boule->w/2;
                        dstBoule.y=y- boule->h/2;
                        dstBoule.h=boule->h;
                        dstBoule.w=boule->w;
    
                        origine.x=0;
                        origine.y=0;
                        SDL_BlitSurface(ecran,&dstBoule,tamponBoule,&origine);
    
                        // colle la boule
                        SDL_BlitSurface(boule, NULL, ecran, &dstBoule);
                        SDL_Flip(ecran);
    
                    break;
    
    
    
    
    
    //////////////////////////// boutton relaché ////////////////////////////////////////
    
                case SDL_MOUSEBUTTONUP :
                    SDL_GetMouseState(&x,&y);
                    liste[i].vitesse.x=(liste[i].coord.x-x)*COEF_VITESSE;
                    liste[i].vitesse.y=(liste[i].coord.y-y)*COEF_VITESSE;
                    attend=0;
                break;
            }
        }
        return 1;
    };
    
    
    

    Déplace

    Déplace à chaque étape de la vistesse
    Ici, c'est un pointeur tBoule qui est foourni à la fonction.
    Pour accèder à ses champs, c'est donc boule->vitesse.x.

    void deplaceBoule(tBoule *boule)
    {
        boule->coord.x+=boule->vitesse.x;
        boule->coord.y+=boule->vitesse.y;
    }
    
    

    Rebondit

    Il y a rebond sur le bord si, après déplacement, la boule empiète sur la bande de bord.
    Il faut alors inverser la composante de la vitesse perpendiculaire au bord en question (réflexion)

    void rebondBouleBord(tBoule incidente, tBoule *reflechie)
    {
        float r=incidente.img->h/2;
        copieBoule(incidente,reflechie);
        // test l'appartenance à un des pièges
    
        // rebond à gauche
        if (incidente.coord.x<EPAISSEUR+r && incidente.vitesse.x<0 )
        {
            reflechie->vitesse.x=-incidente.vitesse.x;
        }
        // rebond à droite
        if (incidente.coord.x+r+EPAISSEUR>LARGEUR_ECRAN && incidente.vitesse.x>0)
        {
            reflechie->vitesse.x=-incidente.vitesse.x;
        }
        // rebond en haut
        if (incidente.coord.y<EPAISSEUR+r && incidente.vitesse.y<0)
        {
            reflechie->vitesse.y=-incidente.vitesse.y;
        }
        // rebond en bas
        if (incidente.coord.y+r+EPAISSEUR>HAUTEUR_ECRAN && incidente.vitesse.y>0)
        {
            reflechie->vitesse.y=-incidente.vitesse.y;
        }
    }
    

    Il y a rebond sur une boule si, après déplacement, la boule empiète sur une autre (la distance de leurs centres est inférieur à la somme de leurs rayons)
    Dans le repère barycentrique (ici, déterminé par le milieu des deux boules), les vitesses seront opposées.
    Seule la composante dans l'axe du choc (déterminé par les deux centres des boules) doit être inversée.

    Le repère mobile (u,v) normalisé est déterminé :

  • u par le segment des deux centres des boules, normalisé.
  • v est alors obtenu par un quart de tour (x->y et y->-x)
  • les coordonnées de la vitesse relative à ce repère mobile sont obtenues par produit scalaire

    void rebondBouleBoule(tBoule incidente1, tBoule incidente2, tBoule *reflechie1, tBoule *reflechie2)
    {
        // incidente1->img->h est la haurteur=largeur=diametre de la boule
        if (distCarre(incidente1.coord,incidente2.coord)>(incidente1.img->h)*(incidente1.img->h))
        {
            copieBoule(incidente1,reflechie1);
            copieBoule(incidente2,reflechie2);
        }
        else
        {
            //  VM : vitesse du (repère) mobile, (u,v) base mobile orthonormal
            vecteur VM,u,v;
    
            VM.x=(incidente1.vitesse.x+incidente2.vitesse.x)/2;
            VM.y=(incidente1.vitesse.y+incidente2.vitesse.y)/2;
    
            // direction de réflexion donné  par le centre des boules
            u.x=(incidente1.coord.x-incidente2.coord.x);
            u.y=(incidente1.coord.y-incidente2.coord.y);
    
            // normalisation de u
            float r=norme(u);
            u.x=u.x/r;
            u.y=u.y/r;
    
            // quart de tours pour v
            v.x=u.y;
            v.y=-u.x;
    
            // vitesse incidente de la boule 1 relative au repere mobile
            // celle de la boule 2 est l'oppposée.
            // VIA coordonnées dans le repère absolu
            // VIM coordonnées dans le repère mobile
            // N.B. dans le repère mobile, les vitesses des deux boules restent opposées
    
            vecteur VIA,VIM;
    
            VIA.x=incidente1.vitesse.x-VM.x;
            VIA.y=incidente1.vitesse.y-VM.y;
    
            VIM.x=prodScal(VIA,u);
            VIM.y=prodScal(VIA,v);
    
            // vitesse réfléchie
            // seule la partie suivant u  est inversée
            // dans le repère mobile, les vitesse des deux boules restent opposées
    
            reflechie1->vitesse.x=-VIM.x*u.x+VIM.y*v.x + VM.x;
            reflechie1->vitesse.y=-VIM.x*u.y+VIM.y*v.y+ VM.y;
            reflechie1->coord.x=incidente1.coord.x;
            reflechie1->coord.y=incidente1.coord.y;
            reflechie1->img=incidente1.img;
    
    
            reflechie2->vitesse.x=VIM.x*u.x-VIM.y*v.x+VM.x;
            reflechie2->vitesse.y=+VIM.x*u.y-VIM.y*v.y+VM.y;
            reflechie2->coord.x=incidente2.coord.x;
            reflechie2->coord.y=incidente2.coord.y;
            reflechie2->img=incidente2.img;
        }
    }
    
    

    Fermer

    Il faut libérer la mémoire vidéo, quand on n'en a plus l'usage. c'est fait dans la fonciton main

     ////////////////  libérer la mémoire ///////////////////////////////
        int i=0;
        for (i=0;i<NOMBRE_DE_BOULES;i++)
        {
            SDL_FreeSurface(liste[i].img);
        }
    
        SDL_FreeSurface(fond);
    
        SDL_FreeSurface(ecran);
    
        // all is well ;)
        printf("Exited cleanly\n");
        return 0;
        SDL_Quit();