Programmation de la 2D

Fermé
Sabetodo Messages postés 120 Date d'inscription samedi 1 mars 2008 Statut Membre Dernière intervention 18 août 2010 - 19 févr. 2010 à 16:06
yves004 Messages postés 9 Date d'inscription vendredi 19 février 2010 Statut Membre Dernière intervention 19 février 2010 - 19 févr. 2010 à 16:16
Bonjour,
Salut à tous le monde. J s8 un passionne des jeux vidéo j'ai décide de me lancer dans la 2D. Alors j'ai suivi le tuto de Mathéo en C sur la création des jeux 2D en SDL. Maintenant pour me faire plaisir j'ai décide de programmer le fameux jeu pong. Apparemment le code marche sans problème puisqu'il ne signale pas d'erreur, mais lors du chargement de la fenêtre rien ne s'affiche. Pour ceux qui sont déjà bien avance la dessus, merci de me donner un coup de main. voici le code en entier bien commenté pour vous aider à m'aider:
#include <iostream>
#include <cstdlib>
#include <time.h>
#include <SDL/SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>

using namespace std;

/****************WELCOME*****TO***MY****FIRST**GAME****PONG***********/
/**********************COMMENT CELA MARCHE****************************/
/*
  Joueur de gauche: Monter = T
                    Descendre = G
                    Missile = Espace

  Joueur de droite: Monter, Descendre = Flêches
                    Missile = Entrer

*/



// Constantes
const int SCREEN_WIDTH = 800;// Largeur de la Fenêtre
const int SCREEN_HEIGHT = 600;// Hauteur de la Fenêtre
const int VITESSE_BALLE = 2;// Vitesse de la balle
const int VITESSE_BARRE = 2;// Vitesse des barres
const int VITESSE_COUP_SPE = 2;// Vitesse du missile
const int DELAY = 4;// Delay du Fps


// *** Structure Objet ***
//- Elle contient une surface pour y mettre l'image et un SDL_Rect pour donner ses positions.
struct Objet
{
    SDL_Surface* surface;
    SDL_Rect position;
};
//************************

// ********************************************* Mouvements balle ********************************************
//- Modifie selon les données les positions de la balle

int moveBalle(Objet &balle, Objet barreGauche, Objet barreDroit, int &mov_x, int &mov_y)
{
    /* -- Vérifie que la balle touche une barre -- */
    // On rajoute +- VITESSE_BALLE dans les condition pour pouvoir changer librement la vitesse de la balle

    // Si la balle touche la barre de droite, on multiplie par (-1) le mouvement de la balle pour la faire repartir dans l'autre sens
    if( ( ((balle.position.x + balle.surface->w) >= (SCREEN_WIDTH - barreDroit.surface->w - 20)) && ((balle.position.x + balle.surface->w) < (SCREEN_WIDTH - barreDroit.surface->w - 20 + VITESSE_BALLE)))
      &&
      ((balle.position.y <= (barreDroit.position.y + barreDroit.surface->h)) && ((balle.position.y + balle.surface->h) >= barreDroit.position.y)) )
      mov_x *= -1;

    // De même pour la barre de gauche
    else if( ((balle.position.x <= (barreGauche.surface->w + 20)) && (balle.position.x > (barreGauche.surface->w + 20 - VITESSE_BALLE)))
            &&
            ((balle.position.y <= (barreGauche.position.y + barreGauche.surface->h)) && ((balle.position.y + balle.surface->h) >= barreGauche.position.y)) )
      mov_x *= -1;
    /* ------------------------------------------- */



    // Vérifie si la balle touche les mur d'en haut ou d'en bas et si oui change le sens de mouvement
    if((balle.position.y + balle.surface->h) >= SCREEN_HEIGHT)
      mov_y *= -1;
    else if(balle.position.y <= 0)
      mov_y *= -1;



    // Change les positions
    balle.position.x += mov_x;
    balle.position.y += mov_y;




    /* On vient de changer les positions de la balle. Donc si elle passe les conditions suivantes
    c'est qu'elles n'est pas en face d'une barre et qu'elle est sortie.
    Le joueur de gauche est 1, celui de droite est 2*/
    // On rajoute +- VITESSE_BALLE dans les condition pour pouvoir changer librement la vitesse de la balle
    if((balle.position.x) > (SCREEN_WIDTH - 20 - barreDroit.surface->w + VITESSE_BALLE))// Sort vers la droite, donc renvoie 1 car le joueur de gauche (1) a gagné
        return 1;
    else if((balle.position.x) < (barreGauche.surface->w + 20 - VITESSE_BALLE))// Sort vers la gauche, donc renvoie 2 car le joueur de droite (2) a gagné
        return 2;
    else
        return 0;// On renvoi 0 si personne gagne comme çà le jeux continue

}

// *********************************************************************************************************



// ********************************************* Mouvements des barres ********************************************
//- Modifie les positions des barres si on appuis sur les touches du clavier appropriées

void moveBarre(Objet &barreGauche, Objet &barreDroit, Uint8* keystates)
{
     if(keystates[SDLK_UP] && (barreDroit.position.y - VITESSE_BARRE >= 0))// La fléche du HAUT est appuié, donc on fait remonter la barre de droite
         barreDroit.position.y -= VITESSE_BARRE;

     if(keystates[SDLK_DOWN] && (barreDroit.position.y + barreDroit.surface->h + VITESSE_BARRE <= SCREEN_HEIGHT))// La fléche du BAS est appuié, donc on fait redescendre la barre de droite
         barreDroit.position.y += VITESSE_BARRE;

     if(keystates[SDLK_t] && (barreGauche.position.y - VITESSE_BARRE >= 0))// La touche T est appuié, donc on fait remonter la barre de gauche
         barreGauche.position.y -= VITESSE_BARRE;

     if(keystates[SDLK_g] && (barreGauche.position.y + barreGauche.surface->h + VITESSE_BARRE <= SCREEN_HEIGHT))// La touche G est appuié, donc on fait redescendre la barre de gauche
         barreGauche.position.y += VITESSE_BARRE;
}


// ************************************** Attend qu'une touche soit appuyé ***************************************

void waitEvent(SDL_Event event, bool &continuer)
{
bool attendre = true;

    while(attendre)
    {
        SDL_WaitEvent(&event);// Attend un événement
        switch(event.type)
        {
            case SDL_QUIT:// On click sur la croix de la fenétre donc on annule le booléen de la boucle d'attente et celui de la boucle principale
                continuer = false;
                attendre = false;
                break;

            case SDL_KEYDOWN:// Une touche est préssé donc on quitte cette boucle et sortons de la fonction
                attendre = false;
                break;
        }
    }
}

// ***************************************************************************************************************





// ******************************************* Colle les Img à l'écran *******************************************

void blit(SDL_Surface* screen, Objet fond, Objet balle, Objet barreGauche, Objet barreDroit, Objet score, Objet coupSpe, bool scoreOK, int coupSpeBool)
{
    // Blitages
    SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 255, 255, 255)); // On efface l'écran (ici fond blanc)
    SDL_BlitSurface(fond.surface, NULL, screen, &fond.position);// Colle l'img de fond
    SDL_BlitSurface(balle.surface, NULL, screen, &balle.position);// Colle la balle
    SDL_BlitSurface(barreGauche.surface, NULL, screen, &barreGauche.position);// Colle la barre gauche
    SDL_BlitSurface(barreDroit.surface, NULL, screen, &barreDroit.position);// Colle la barre droite
    if(scoreOK)// Si on a indiqué de coller le score, on le fait
          SDL_BlitSurface(score.surface, NULL, screen, &score.position);// Colle le Score
    if(coupSpeBool)// De même pour le coup spécial
          SDL_BlitSurface(coupSpe.surface, NULL, screen, &coupSpe.position);// Colle le coup special
    SDL_Flip(screen);// Mise à jour de l'écran
}

// ***************************************************************************************************************





// ******************************************* Gère les coups Spéciaux *******************************************
//- On regarde si une touche pour les coups spéciaux n'est pas préssé. Si oui, on affiche le coup spécial en changeant ses coordonnées à chaques appels de cette fonction

void coupSpecial(SDL_Event event, bool &continuer, Objet &coupSpe, int &coupSpeBarre, int &mov_coupSpe, Objet barreGauche, Objet barreDroit, int &gagnant)
{


    SDL_PollEvent(&event);
    switch(event.type)
    {
        case SDL_QUIT:// On click sur la croix de la fenétre donc on annule le booléen de la boucle principale
            continuer = false;
            break;

        case SDL_KEYDOWN:// Une touche est préssé
            switch (event.key.keysym.sym)
            {

			    case SDLK_SPACE:// Espace préssé
			         if(coupSpeBarre == 0)// Si le coup spécial n'existe pas, on le donne donc au joueur de gauche (coupSpeBarre = 1); on place le missile
			         {
    			        coupSpeBarre = 1;
    			        coupSpe.position.y = barreGauche.position.y + (barreGauche.surface->h/2);
    			        coupSpe.position.x = barreGauche.surface->w + 20;
                     }
				    break;

			    case SDLK_RETURN:// Entrer préssé
			         if(coupSpeBarre == 0)// Si le coup spécial n'existe pas, on le donne donc au joueur de droite (coupSpeBarre = 2); on place le missile
			         {
    			        coupSpeBarre = 2;
    			        coupSpe.position.y = barreDroit.position.y + (barreDroit.surface->h/2);
    			        coupSpe.position.x = SCREEN_WIDTH - barreDroit.surface->w - 20;
    			        mov_coupSpe *= -1; // Pour aller vers l'arrière
                     }
				    break;
            }
            break;
    }


    // Si un coup spécial est déjà en cours, donc différent de 0, on l'affiche
    if(coupSpeBarre != 0)
    {

       // --- Sort vers la droite
       if( ((coupSpe.position.x  + coupSpe.surface->w)   >=   (SCREEN_WIDTH - barreDroit.surface->w - 20)) && (coupSpeBarre == 1) )
       {
           // Le joueur de gauche (1) a gagné car la balle a touché la barre de droite
           if((coupSpe.position.y <= (barreDroit.position.y + barreDroit.surface->h)) && ((coupSpe.position.y + coupSpe.surface->h) >= barreDroit.position.y))
           {
               gagnant =  1;
               coupSpeBarre = 0;// On remet le coup spécial à 0 pour dire qu'aucun missiles n'est en jeux
           }
           else // Sinon le missile est sortie mais n'a rien touché. On ne l'affiche plus
               coupSpeBarre = 0;
       }


       // --- Sort vers la gauche
       else if ( ((coupSpe.position.x)   <=   (barreGauche.surface->w + 20)) && (coupSpeBarre == 2) )
       {
            // Le joueur de droite (2) a gagné car la balle a touché la barre de gauche
            if((coupSpe.position.y <= (barreGauche.position.y + barreGauche.surface->h)) && ((coupSpe.position.y + coupSpe.surface->h) >= barreGauche.position.y))
            {
                gagnant =  2;
                coupSpeBarre = 0;// On remet le coup spécial à 0 pour dire qu'aucun missiles n'est en jeux
                mov_coupSpe *= -1; // Remet le mouvement dans le bon sens
            }
            else// Sinon le missile est sortie mais n'a rien touché. On ne l'affiche plus
            {
                coupSpeBarre = 0;
                mov_coupSpe *= -1; // Remet le mouvement dans le bon sens
            }
       }


       // --- Sinon rien ne se passe, donc le missile est en action
       else
           coupSpe.position.x += mov_coupSpe;
    }

}

// ***************************************************************************************************************




// **************************************************** MENU *****************************************************
//- Affiche le menu. Si on clique sur quitter, on modifie les booléens pour quitter le jeux et si on click sur jouer, pour afficher le jeux



bool menu(SDL_Surface* screen, Objet fond, SDL_Event event, bool &continuer)
{
    // Objets temporairement affichés pour le menu.
    struct Objet titre = {IMG_Load("titre.png")}, jouer = {IMG_Load("jouer.png")}, quitter = {IMG_Load("quitter.png")};

    // Positions des Objets précedement définis
    titre.position.x = (SCREEN_WIDTH / 2) - (titre.surface->w / 2); titre.position.y = 100;
    jouer.position.x = (SCREEN_WIDTH / 2) - (jouer.surface->w / 2); jouer.position.y = (SCREEN_HEIGHT / 2);
    quitter.position.x = (SCREEN_WIDTH / 2) - (quitter.surface->w / 2); quitter.position.y = (SCREEN_HEIGHT / 2) + 100;

    // Affichage du Menu
    SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 255, 255, 255)); // On efface l'écran (ici fond blanc)
    SDL_BlitSurface(fond.surface, NULL, screen, &fond.position);// Colle l'img de fond
    SDL_BlitSurface(titre.surface, NULL, screen, &titre.position);// Colle le titre
    SDL_BlitSurface(jouer.surface, NULL, screen, &jouer.position);// Colle le bouton "jouer"
    SDL_BlitSurface(quitter.surface, NULL, screen, &quitter.position);// Colle le bouton "quitter"
    SDL_Flip(screen); // Mise à jour de l'écran



    bool attendre = true;// Booléen pour rester dans la boucle du Menu
    int clickDispo = 0; // Vaut 0 pour un click non disponible, 1 pour jouer et 2 pour quitter

    while(attendre)
    {
        SDL_WaitEvent(&event);// Attend un événement
        switch(event.type)
        {
            case SDL_QUIT:// On click sur la croix de la fenétre donc on annule le booléen de la boucle du menu et celui de la boucle principale
                continuer = false;
                attendre = false;
                return 0;
                break;


            case SDL_MOUSEMOTION:// Lorsque la souris bouge

                // Si la souris est sur le bouton "jouer", on change l'img du bouton
                if(event.motion.y >= jouer.position.y && event.motion.y <= (jouer.position.y + jouer.surface->h) &&
                event.motion.x >= jouer.position.x && event.motion.x <= (jouer.position.x + jouer.surface->w))
                {
                    jouer.surface = IMG_Load("jouerOver.png");
                    clickDispo = 1;
                }

                // Sinon si la souris est sur le bouton "quitter", on change l'img du bouton
                else if(event.motion.y >= quitter.position.y && event.motion.y <= (quitter.position.y + quitter.surface->h) &&
                event.motion.x >= quitter.position.x && event.motion.x <= (quitter.position.x + quitter.surface->w))
                {
                    quitter.surface = IMG_Load("quitterOver.png");
                    clickDispo = 2;
                }

                // Sinon on remet les boutons d'origines et on met la disponibilité du click à 0 car on est sur aucun boutons
                else
                {
                    jouer.surface = IMG_Load("jouer.png");
                    quitter.surface = IMG_Load("quitter.png");
                    clickDispo = 0;
                }

                // Affichage du Menu
                SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 255, 255, 255)); // On efface l'écran (ici fond blanc)
                SDL_BlitSurface(fond.surface, NULL, screen, &fond.position);// Colle l'img de fond
                SDL_BlitSurface(titre.surface, NULL, screen, &titre.position);// Colle le titre
                SDL_BlitSurface(jouer.surface, NULL, screen, &jouer.position);// Colle le bouton "jouer"
                SDL_BlitSurface(quitter.surface, NULL, screen, &quitter.position);// Colle le bouton "quitter"
                SDL_Flip(screen); // Mise à jour de l'écran
                break;


            case SDL_MOUSEBUTTONUP:// Lorsqu'un click est effectué

                // Si on est sur le bouton "jouer" (car clickDispo vaut 1 pour ce bouton), on libéres les surfaces qu'on utilisera plus,
                // on arrête la boucle du menu et on accépte de rentrer dans la boucle principale avec le booléen "continuer" à true.
                if(clickDispo == 1)
                {
                   continuer = true;
                   attendre = false;
                   SDL_FreeSurface(titre.surface);
                   SDL_FreeSurface(jouer.surface);
                   SDL_FreeSurface(quitter.surface);
                   return 1;
                }

                // De même, mais on quitte le menu et mettons le booléen "continuer" à false pour quitter définitivement le programme
                else if(clickDispo == 2)
                {
                   continuer = false;
                   attendre = false;
                   SDL_FreeSurface(titre.surface);
                   SDL_FreeSurface(jouer.surface);
                   SDL_FreeSurface(quitter.surface);
                   return 0;
                }
                break;
        }
    }
}



// ***************************************************************************************************************



// ********************************************* Fonction principale *********************************************

int main(int argc, char* argv[])
{

    // Prend un nombre aléatoire pour définir l'ordonnée de la balle entre 0 et 200
    srand(time(NULL));// Initialise pour une pioche aléatoire
    int ordonneAleatoire = (rand() % 200);




    //--------------------------------------------- Definition SDL ---------------------------------------------//

    SDL_Init(SDL_INIT_VIDEO); // Initialisation de la SDL

    // Définition des structures Objets (on y charge l'image de fond), puis des positions de ces structures
    struct Objet fond = {IMG_Load("fond.png")}, balle = {IMG_Load("balle.png")}, barreGauche = {IMG_Load("barreGauche.png")},
           barreDroit = {IMG_Load("barreDroit.png")}, score = {NULL}, coupSpe = {IMG_Load("missile.png")};

           fond.position.x = 0; fond.position.y = 0;// Fond
           balle.position.x = SCREEN_WIDTH / 2 - 100; balle.position.y = ordonneAleatoire;// Balle
           barreGauche.position.x = 20; barreGauche.position.y = (SCREEN_HEIGHT / 2) - (barreGauche.surface->h / 2);// Barre de Gauche
           barreDroit.position.x = SCREEN_WIDTH - barreDroit.surface->w - 20; barreDroit.position.y = (SCREEN_HEIGHT / 2) - (barreDroit.surface->h / 2);// Barre de Droite
	       coupSpe.position.x = SCREEN_WIDTH - barreDroit.surface->w - 20;coupSpe.position.y = barreDroit.position.y + (barreDroit.surface->h/2);// Coup Spéciale



    SDL_Surface* screen = NULL;// Définie la surface "screen" principale
    SDL_Event event;// Définie le nom pour les événements
    Uint8 *keystates = SDL_GetKeyState(NULL);// Pour le clavier

    screen = SDL_SetVideoMode(SCREEN_WIDTH,  SCREEN_HEIGHT, 32, SDL_HWSURFACE | SDL_DOUBLEBUF); // Définitions de la fenêtre, caractéristiques
    SDL_WM_SetCaption("Mon Super Pong", NULL);// Titre


    // Définition des polices etc ...
    TTF_Init();// Initialisation pour les Polices
    TTF_Font *police = TTF_OpenFont("nightmareheronormal.ttf", 70);// Indique la police, et la taille
    SDL_Color couleurBlanche = {255, 255, 255};// Indique la couleur
    score.surface = TTF_RenderText_Blended(police, "Score: 0 - 0", couleurBlanche);// Ecriture du texte
    score.position.x = (SCREEN_WIDTH / 2) - (score.surface->w / 2); score.position.y = (SCREEN_HEIGHT / 2) - (score.surface->h / 2);// Positions du score

    //----------------------------------------------------------------------------------------------------------//




    //----------------------------------------------- Variables ------------------------------------------------//

    bool continuer = true;// Bool qui va permettre de continuer le jeu
    int mov_x = VITESSE_BALLE, mov_y = VITESSE_BALLE, mov_coupSpe = VITESSE_COUP_SPE;// Mouvement de la balle et du coup special
    int gagnant = 0, scoreGauche = 0, scoreDroit = 0;// Scores, gagnant
    char scoreText[20] = "";// Texte du score
    int coupSpeBarre = 0;// Nbr pour savoir qui lance le coup spécial
    int tempsPrecedent = 0, tempsActuel = 0;// Temps pour le fps

    //----------------------------------------------------------------------------------------------------------//




     if(menu(screen, fond, event, continuer))// Si menu() renvoi 1, on affiche le jeux et on met le programme en pause
     {
     blit(screen, fond, balle, barreGauche, barreDroit, score, coupSpe, 1, coupSpeBarre);// Affiche le jeux
     waitEvent(event, continuer);// Attend qu'on appuie sur une touche pour commencer
     }


     // ***---____________________   Coeur du programme   ____________________---*** //

     while(continuer)// Tourne tant que le booléen "continuer" est vrai
     {
            tempsActuel = SDL_GetTicks();// A chaques retours de boucles, on met a jours "tempsActuel"

            // Si la différence entre tempsActuel et tempsprecedent est > 5, donc qu'un certains temp c'est écoulé, on rafraichie le jeux
            if((tempsActuel - tempsPrecedent) > DELAY)
            {
        	    moveBarre(barreGauche, barreDroit, keystates);// On appel la fonction qui bouge les barres

        	    gagnant = moveBalle(balle, barreGauche, barreDroit, mov_x, mov_y);// On bouge la balle. Si elle est dehors, moveBall() renvoi le gagnant et on modifie le score

                coupSpecial(event, continuer, coupSpe, coupSpeBarre, mov_coupSpe, barreGauche, barreDroit, gagnant);// On regarde si il n'y a pas de coup spécial lancé


                if(gagnant != 0)// S'il y a un gagnant, on change le scores et on re-initialise les positions
        	    {
                     if(gagnant == 1)// gagnant = 1  donc le joueur de gauche a gagné. On lui incrémente son score
        	              scoreGauche++;
        	         else if(gagnant == 2)// De même mais on remet le mouvement de la balle dans le bon sens (vers la droite)
        	         {
        	              scoreDroit++;
        	              mov_x *= -1;
                     }

        	         sprintf(scoreText, "Score : %ld - %ld", scoreGauche, scoreDroit);// Change le texte du score
        	         score.surface = TTF_RenderText_Blended(police, scoreText, couleurBlanche);// Edition du texte sur la surface "score"
        	         score.position.x = (SCREEN_WIDTH / 2) - (score.surface->w / 2); score.position.y = (SCREEN_HEIGHT / 2) - (score.surface->h / 2);// Positions du texte

        	         // Re-Initialise les positions des barres
        	         barreGauche.position.y = (SCREEN_HEIGHT / 2) - (barreGauche.surface->h / 2);barreDroit.position.y = (SCREEN_HEIGHT / 2) - (barreDroit.surface->h / 2);

        	         // Repioche un nombre aléatoire
                     srand(time(NULL));// Initialise pour une pioche aléatoire
                     ordonneAleatoire = (rand() % 200);

                     // Re-Initialise la position de la balle avec le nombre aléatoire
                     balle.position.x = SCREEN_WIDTH / 2 - 100; balle.position.y = ordonneAleatoire;

            		 coupSpeBarre = 0;// Si il y a un gagnant, on se doit d'annuler un éventuel coup spécial en cours
            		 mov_coupSpe = VITESSE_COUP_SPE;// On remet le missile dans le bon sens (vers la droite)
            		 mov_x = VITESSE_BALLE; mov_y = VITESSE_BALLE;// On remet la balle dans le bon sens également

                     // Affiche le jeux avec les scores
                     blit(screen, fond, balle, barreGauche, barreDroit, score, coupSpe, 1, coupSpeBarre);

                     waitEvent(event, continuer);// Attend qu'on appuie sur une touche pour continuer
                }

                // De même, on blit
                blit(screen, fond, balle, barreGauche, barreDroit, score, coupSpe, 0, coupSpeBarre);

                tempsPrecedent = tempsActuel;// On actualise le temps précédent au temps actuel
            }
            // Sinon, on attend que le temps s'écoule pour économiser le processeur
            else
                SDL_Delay(DELAY - (tempsActuel - tempsPrecedent));// Economise le processeur
     }

     //***--- _______________________________________________________________ ---***//





    // On quitte la boucle, donc on ferme le programme proprement
    TTF_Quit();
    SDL_FreeSurface(screen);
    SDL_FreeSurface(fond.surface);
    SDL_FreeSurface(balle.surface);
    SDL_FreeSurface(barreGauche.surface);
    SDL_FreeSurface(barreDroit.surface);
    SDL_FreeSurface(score.surface);
    SDL_FreeSurface(coupSpe.surface);
    SDL_Quit();

return EXIT_SUCCESS;
}
// ********************************************************************//

A voir également:

1 réponse

yves004 Messages postés 9 Date d'inscription vendredi 19 février 2010 Statut Membre Dernière intervention 19 février 2010 10
19 févr. 2010 à 16:16
0