Partage
  • Partager sur Facebook
  • Partager sur Twitter

TP Mario Sokoban - annuler les coups

    16 janvier 2020 à 17:21:49

    Bonjour,

    Après avoir terminé le TP Mario Sokoban, je suis en train de l’améliorer progressivement.

    Ma version gère les niveaux. Si le joueur termine le niveau, le suivant s’affiche. En cours de partie, il peut aussi directement passer au niveau suivant ou revenir au précédent avec PageUp/PageDown. J’ai aussi ajouté un système de téléportation (idée que j’ai trouvée sur ce forum). Dès que Mario passe sur le portail 1, il est téléporté au portail 2 et vice-versa.

    Je travaille maintenant sur une fonctionnalité qui permet d’annuler les coups. Tous les mouvements de Mario sont enregistrés au fur et à mesure dans un fichier sauvegarde_mouvement.txt via la fonction sauvegardeMouvement(). Si le joueur appuie sur Tab, on revient un coup en arrière de la manière suivante : on fait appel à la fonction annulerMouvement () qui ouvre le fichier de sauvegarde, on se positionne au dernier mouvement et on le renvoie à la fonction dernierCoup(). Puis on supprime le dernier mouvement du fichier en copiant tous les mouvements précédents dans un fichier de sauvegarde temporaire, on vide le fichier de sauvegarde, on copie à nouveau les mouvements dedans et on supprime le fichier temporaire.

    Jusque-là, tout marche nickel et on peut annuler tous les coups, du moment que Mario ne déplace pas de caisses ou passe à proximité. La en effet le programme se comporte bizarrement. Les caisses ne retrouvent pas toujours leur emplacement initial et continuent parfois à suivre le déplacement de Mario sur une case ou deux. J’imagine que l’erreur doit provenir quelquepart de ma fonction dernierCoup() dans jeu.c, peut-être au niveau de la gestion des caisses avec déplacerCaisse() mais je vois pas où.

    Peut-être que vos lumières me permettront d’y voir plus clair ^^

    Je vous mets l’intégralité du code, et je suis toujours preneur de tous vos commentaires d’amélioration !

    Merci

    Main.c :

    #include <SDL.h>
    #include <SDL_image.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    #include "constantes.h"
    #include "jeu.h"
    #include "editeur.h"
    #include "chargements.h"
    
    int main (int arg, char * argv[])
    {
    	SDL_Window * fenetre = NULL;
    	SDL_Renderer * rendu = NULL;
    	SDL_Surface *caisseIconeSurface = NULL;
    	SDL_Texture *imageMenu = NULL, *image[8] = {0} , *mario[4] = {0};
    	SDL_Rect positionMenu, positionElement;
    	SDL_bool lancement_programme = SDL_TRUE;
    	positionMenu.x = 0;
    	positionMenu.y = 0;
        positionElement.x = 0;
        positionElement.y = 0;
    
    	//-----------------------------------------------------------------------------------------------------------------
    	//Initialisation de la SDL
    
    	if (SDL_Init(SDL_INIT_VIDEO) != 0)
    		SDL_ExitWithError("Initialisation SDL");
    	
    	if (SDL_CreateWindowAndRenderer(LARGEUR_FENETRE, HAUTEUR_FENETRE, 0, &fenetre, &rendu) != 0)
    		SDL_ExitWithError("Impossible de créer la fenêtre ou le rendu");
    	
    	SDL_SetWindowTitle(fenetre, "Mario Sokoban");
    	
    	//-----------------------------------------------------------------------------------------------------------------
    	//Chargement des images
    
    	imageMenu = loadTexture(rendu, "src/images/menu_copie.jpg", &positionMenu);
    	image[CAISSE] = loadTexture(rendu, "src/images/caisse.jpg", &positionElement);
        image[MUR] = loadTexture(rendu, "src/images/mur.jpg", &positionElement);
        image[OBJECTIF] = loadTexture(rendu, "src/images/objectif.png", &positionElement);
    	image[CAISSE_OK] = loadTexture(rendu, "src/images/caisse_ok.jpg", &positionElement);
    	mario[HAUT] = loadTexture(rendu, "src/images/mario_haut.gif", &positionElement);
    	mario[BAS] = loadTexture(rendu, "src/images/mario_bas.gif", &positionElement);
    	mario[GAUCHE] =	loadTexture(rendu, "src/images/mario_gauche.gif", &positionElement);
    	mario[DROITE] = loadTexture(rendu, "src/images/mario_droite.gif", &positionElement);
    	image[MARIO] = mario[BAS];
    	image[PORTAIL1] = loadTexture(rendu, "src/images/teleporteur1.png", &positionElement);
    	image[PORTAIL2] = loadTexture(rendu, "src/images/teleporteur2.jpg", &positionElement);
    	caisseIconeSurface = IMG_Load("src/images/caisse.jpg");
    		if(caisseIconeSurface == 0)
    		{
    			SDL_DestroyRenderer(rendu);
    			SDL_ExitWithError("Impossible de charger l'image");
    		}
    	
    	//-----------------------------------------------------------------------------------------------------------------
    	//Chargement de l'icone
    
    	SDL_SetWindowIcon(fenetre, caisseIconeSurface);
    	SDL_FreeSurface(caisseIconeSurface);	
    	
    	//-----------------------------------------------------------------------------------------------------------------
    	//Début boucle Event
    	
    	while (lancement_programme)
    	{
    		SDL_Event event;
    			while (SDL_PollEvent(&event))
    			{
    				switch(event.type)
    				{
    					case SDL_QUIT:
    					lancement_programme = SDL_FALSE;
    					break;
    				
    					case SDL_KEYDOWN:
    						switch(event.key.keysym.sym)
    						{
    							case SDLK_ESCAPE: // Veut arrêter le jeu
    								lancement_programme = SDL_FALSE;
    								break;
    							case SDLK_KP_1: // Demande à jouer
    								jouer(rendu, image, mario, &positionElement);
    								break;
    							case SDLK_KP_2: // Demande l'éditeur de niveaux
    								editeur(rendu, image, &positionElement);
    								break;
    							default:
    								break;
    						}
    						break;	
    						
    				default:
    					break; 
    				}
    			}
    
    		renderCopy(rendu, imageMenu, &positionMenu);
    		SDL_RenderPresent(rendu);
    				
    	}
    
    	SDL_DestroyTexture(imageMenu);
    	SDL_DestroyTexture(image[PORTAIL1]);
        SDL_DestroyTexture(image[PORTAIL2]);
    	SDL_DestroyTexture(image[MUR]);
        SDL_DestroyTexture(image[CAISSE]);
    	SDL_DestroyTexture(image[CAISSE_OK]);
        SDL_DestroyTexture(image[OBJECTIF]);
    	SDL_DestroyTexture(mario[HAUT]);
    	SDL_DestroyTexture(mario[BAS]);
    	SDL_DestroyTexture(mario[GAUCHE]);
    	SDL_DestroyTexture(mario[DROITE]);
    	SDL_DestroyRenderer(rendu);
    	SDL_DestroyWindow(fenetre);
    
    	return EXIT_SUCCESS;
    }



    Jeu.c :

    #include <SDL.h>
    #include <SDL_image.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    #include "constantes.h"
    #include "jeu.h"
    #include "fichier.h"
    #include "chargements.h"
    
    
    void jouer(SDL_Renderer * rendu, SDL_Texture * image[], SDL_Texture *mario[], SDL_Rect * positionElement)
    {
    //-------------------------------------------------------------------------------------------------------------
    //Déclaration des variables
        
    	SDL_Texture  *marioActuel = NULL , *barreControleJeu = NULL;
        SDL_Rect positionJoueur, positionBarreControleJeu, posPortail1, posPortail2;
    
        SDL_bool lancement_programme = SDL_TRUE;
        SDL_Event event;
    
        int carte [NB_BLOC_HAUTEUR][NB_BLOC_LARGEUR] = {0};
        int i = 0, j = 0, objectifsRestants = 0, niveau = 1, dernierMouvement = 0;
    	positionBarreControleJeu.x = 0;
    	positionBarreControleJeu.y = TAILLE_BLOC*NB_BLOC_HAUTEUR;
    
    	barreControleJeu = loadTexture(rendu,"src/images/barre_controle_jeu.jpg", &positionBarreControleJeu);
    	marioActuel = mario[BAS];
    //------------------------------------------------------------------------
    
    	if(!chargerNiveau(carte, niveau, &positionJoueur))
            exit(EXIT_FAILURE);	
    
    	while (lancement_programme)
    	{
    		while (SDL_PollEvent(&event))
    		{
    			switch(event.type)
    			{
    				case SDL_QUIT:												//Croix : on revient au menu
    				lancement_programme = SDL_FALSE;
    				remove("src/sauvegarde_mouvement.txt");
    				break;
    			
    				case SDL_KEYDOWN:
    					switch(event.key.keysym.sym)
    					{
    						case SDLK_ESCAPE: 									//Esc : on revient au menu
    							lancement_programme = SDL_FALSE;
    							remove("src/sauvegarde_mouvement.txt");
    							break;						
    						case SDLK_SPACE: 									//Barre espace : On réinitialise le niveau en cours
    							chargerNiveau(carte, niveau, &positionJoueur);
    							remove("src/sauvegarde_mouvement.txt");  	
    							break;
    						case SDLK_PAGEUP:									//PageUp : On passe au niveau suivant
    							niveau++; 
    							chargerNiveau(carte, niveau, &positionJoueur);
    							remove("src/sauvegarde_mouvement.txt"); 	
    							break;
    						case SDLK_PAGEDOWN:									//PageDn : On revient au niveau précédent
    							if(niveau == 1)
    								break;
    							niveau--;
    							chargerNiveau(carte, niveau, &positionJoueur);
    							remove("src/sauvegarde_mouvement.txt"); 
    							break;
    						case SDLK_TAB: 										//Tab : On annule le dernier coup
    							dernierMouvement = annulerMouvement(); 
    							dernierCoup(carte, &positionJoueur, posPortail1, posPortail2, dernierMouvement); 	
    							break;
    						case SDLK_UP:										//On déplace Mario vers le haut
    							marioActuel = mario[HAUT];
    							sauvegardeMouvement(HAUT);						
    							deplacerJoueur(carte, &positionJoueur, HAUT, posPortail1, posPortail2); 
    							break;
    						case SDLK_DOWN: 									//On déplace Mario vers le bas
    							marioActuel = mario[BAS];
    							sauvegardeMouvement(BAS);
    							deplacerJoueur(carte, &positionJoueur, BAS, posPortail1, posPortail2); 								
    							break;
    						case SDLK_LEFT: 									//On déplace Mario vers la gauche
    							marioActuel = mario[GAUCHE];
    							sauvegardeMouvement(GAUCHE);
    							deplacerJoueur(carte, &positionJoueur, GAUCHE, posPortail1, posPortail2); 								
    							break;
    						case SDLK_RIGHT: 									//On déplace Mario vers la droite
    							marioActuel = mario[DROITE];
    							sauvegardeMouvement(DROITE);
    							deplacerJoueur(carte, &positionJoueur, DROITE, posPortail1, posPortail2); 								
    							break;
    						default:
    							break;
    					}
    					break;	
    					
    			default:
    				break; 
    			}
    		}
           
    	   if(SDL_RenderClear(rendu) != 0)
    		{
    			SDL_DestroyRenderer(rendu);
    			SDL_ExitWithError("Impossible d'afficher la texture");
    		}
    
    		if(SDL_SetRenderDrawColor(rendu, 255, 255, 255, SDL_ALPHA_OPAQUE) !=0)
    		{
    			SDL_DestroyRenderer(rendu);
    			SDL_ExitWithError("Impossible d'afficher la texture");
    		}
    		
    		objectifsRestants = 0;
    
            //CREATION DE LA MAP
    		afficherNiveau(rendu, image, carte, positionElement, &posPortail1, &posPortail2, &objectifsRestants);
    
    		//Affichage de Mario à sa position
    		positionElement->x = positionJoueur.x * TAILLE_BLOC;
            positionElement->y = positionJoueur.y * TAILLE_BLOC;
    		
    		renderCopy(rendu, marioActuel, positionElement);
    		renderCopy(rendu, barreControleJeu, &positionBarreControleJeu);
    
    		//Test s'il reste des objectifs ou si on affiche le niveau suivant
    		if (!objectifsRestants)
    		{
    			niveau++;
    			chargerNiveau(carte, niveau, &positionJoueur);
    			remove("src/sauvegarde_mouvement.txt");
    		}
    		
    		SDL_RenderPresent(rendu);
        }
    	
    	SDL_DestroyTexture(barreControleJeu);
    }
    
    //--------------------------------------------------------------------------------------------------------------------------
    
    void deplacerJoueur(int carte[][NB_BLOC_LARGEUR], SDL_Rect *pos, int direction, SDL_Rect posPortail1, SDL_Rect posPortail2)
    {
    	int i, j;
    
    	switch (direction)
    	{
    		case HAUT :
    			if(pos->y - 1 < 0) // STOP si la case suivante est le bord du jeu
    				break;
    			if(carte[pos->x][pos->y - 1] == MUR) // STOP si la case suivante est un mur
    				break;
    			if ((carte[pos->x][pos->y - 1] == CAISSE || carte[pos->x][pos->y - 1] == CAISSE_OK) && (pos->y - 2 < 0 || carte[pos->x][pos->y - 2] == MUR || 
    				carte[pos->x][pos->y - 2] == CAISSE || carte[pos->x][pos->y - 2] == CAISSE_OK)) // STOP si la case suivante est une caisse et que la case d'après est un mur/caisse/bord du jeu
    				break;
    			if(carte[pos->x][pos->y - 1] == PORTAIL1)	// On se téléporte si la case suivante est un portail
    			{
    				positionPortail(pos, posPortail2);
    				break;
    			}
    			if(carte[pos->x][pos->y - 1] == PORTAIL2)
    			{
    				positionPortail(pos, posPortail1);
    				break;
    			}
    			deplacerCaisse(&carte[pos->x][pos->y - 1], &carte[pos->x][pos->y - 2]); //Si toutes les conditions précédentes sont nulles, on vérifie s'il y a une caisse à déplacer
    			pos->y--;	// On déplace le joueur
    			break;
    
    		case BAS :
    			if(pos->y + 1 >= NB_BLOC_HAUTEUR) 
    				break;
    
    			if(carte[pos->x][pos->y + 1] == MUR) 
    				break;
    
    			if ((carte[pos->x][pos->y + 1] == CAISSE || carte[pos->x][pos->y + 1] == CAISSE_OK) && (pos->y + 2 > NB_BLOC_HAUTEUR || carte[pos->x][pos->y + 2] == MUR || 
    				carte[pos->x][pos->y + 2] == CAISSE || carte[pos->x][pos->y + 2] == CAISSE_OK))
    				break;
    			if(carte[pos->x][pos->y + 1] == PORTAIL1)
    			{
    				positionPortail(pos, posPortail2);
    				break;
    			}
    			if(carte[pos->x][pos->y + 1] == PORTAIL2)
    			{
    				positionPortail(pos, posPortail1);
    				break;
    			}
    			deplacerCaisse(&carte[pos->x][pos->y + 1], &carte[pos->x][pos->y + 2]);	
    			pos->y++;
    			break;
    		
    		case GAUCHE :
    			if(pos->x - 1 < 0) 
    				break;
    			if(carte[pos->x - 1][pos->y] == MUR) 
    				break;
    			if ((carte[pos->x - 1][pos->y] == CAISSE || carte[pos->x - 1][pos->y] == CAISSE_OK) && (pos->x - 2 < 0 || carte[pos->x - 2][pos->y] == MUR || 
    				carte[pos->x - 2][pos->y] == CAISSE || carte[pos->x - 2][pos->y] == CAISSE_OK)) 
    				break;
    			if(carte[pos->x - 1][pos->y] == PORTAIL1)
    			{											
    				positionPortail(pos, posPortail2)	;	
    				break;
    			}
    			if(carte[pos->x - 1][pos->y] == PORTAIL2)
    			{
    				positionPortail(pos, posPortail1);	
    				break;
    			}
    			deplacerCaisse(&carte[pos->x - 1][pos->y], &carte[pos->x - 2][pos->y]);
    			pos->x--;
    			break;
    		
    		case DROITE :
    			if(pos->x + 1 >= NB_BLOC_LARGEUR)
    				break;
    			if(carte[pos->x + 1][pos->y] == MUR) 
    				break;
    			if ((carte[pos->x + 1][pos->y] == CAISSE || carte[pos->x + 1][pos->y] == CAISSE_OK) && (pos->x + 2 >= NB_BLOC_LARGEUR || carte[pos->x + 2][pos->y] == MUR || 
    				carte[pos->x + 2][pos->y] == CAISSE || carte[pos->x + 2][pos->y] == CAISSE_OK)) 
    				break;
    			if(carte[pos->x + 1][pos->y] == PORTAIL1)
    			{
    				positionPortail(pos, posPortail2);
    				break;
    			}
    			if(carte[pos->x + 1][pos->y] == PORTAIL2)
    			{
    				positionPortail(pos, posPortail1);
    				break;
    			}
    			deplacerCaisse(&carte[pos->x + 1][pos->y], &carte[pos->x + 2][pos->y]);
    			pos->x++;
    			break;
    	}
    
    }
    
    //--------------------------------------------------------------------------------------------------------------------------
    
    void deplacerCaisse (int *premiereCase, int *deuxiemeCase)
    {
    	if(*premiereCase == CAISSE || *premiereCase == CAISSE_OK)
    	{
    		if(*deuxiemeCase == OBJECTIF)
    			*deuxiemeCase = CAISSE_OK;
    		else
    			*deuxiemeCase = CAISSE;
    
    		if(*premiereCase == CAISSE_OK)
    			*premiereCase = OBJECTIF;
    		else
    			*premiereCase = VIDE;	
    	}
    }
    
    //--------------------------------------------------------------------------------------------------------------------------
    	
    void dernierCoup(int carte[][NB_BLOC_LARGEUR], SDL_Rect *pos, SDL_Rect posPortail1, SDL_Rect posPortail2, int dernierMouvement)
    {
    	switch (dernierMouvement)
    	{ 
    		case HAUT :
    			if(carte[pos->x][pos->y + 1] == PORTAIL1)	//On se téléporte si la dernière case était un portail
    			{
    				positionPortail(pos, posPortail2);
    				break;
    			}
    			if(carte[pos->x][pos->y + 1] == PORTAIL2)
    			{
    				positionPortail(pos, posPortail1);
    				break;
    			}
    			pos->y++;	//On recule le joueur
    			deplacerCaisse(&carte[pos->x][pos->y - 2], &carte[pos->x][pos->y - 1]);	//On replace la caisse à sa position précédente
    			break;
    
    		case BAS :
    			if(carte[pos->x][pos->y - 1] == PORTAIL1)
    			{
    				positionPortail(pos, posPortail2);
    				break;
    			}
    			if(carte[pos->x][pos->y - 1] == PORTAIL2)
    			{
    				positionPortail(pos, posPortail1);
    				break;
    			}
    			pos->y--;
    			deplacerCaisse(&carte[pos->x][pos->y + 2], &carte[pos->x][pos->y + 1]);
    			break;
    		
    		case GAUCHE :
    			if(carte[pos->x + 1][pos->y] == PORTAIL1)
    			{
    				positionPortail(pos, posPortail2);
    				break;
    			}
    			if(carte[pos->x + 1][pos->y] == PORTAIL2)
    			{
    				positionPortail(pos, posPortail1);
    				break;
    			}
    			pos->x++;
    			deplacerCaisse(&carte[pos->x - 2][pos->y], &carte[pos->x - 1][pos->y]);
    			break;
    		
    		case DROITE :
    			if(carte[pos->x - 1][pos->y] == PORTAIL1)
    			{
    				positionPortail(pos, posPortail2);
    				break;
    			}
    			if(carte[pos->x - 1][pos->y] == PORTAIL2)
    			{
    				positionPortail(pos, posPortail1);
    				break;
    			}
    			pos->x--;
    			deplacerCaisse(&carte[pos->x + 2][pos->y], &carte[pos->x + 1][pos->y]);
    			break;
    	}
    }
    
    //--------------------------------------------------------------------------------------------------------------------------
    
    void positionPortail (SDL_Rect *pos, SDL_Rect posPortail)
    {
    	pos->x = posPortail.x;
    	pos->y = posPortail.y;
    }
    
    

    fichier.c :

    #include <stdlib.h>
    #include <stdio.h>
    #include <SDL.h>
    #include <SDL_image.h>
    
    #include "constantes.h"
    #include "fichier.h"
    
    int chargerNiveau(int niveau[][NB_BLOC_LARGEUR], int niv, SDL_Rect *positionJoueur)
    {
        FILE* fichier_niveau = NULL;
        char ligneFichier[NB_BLOC_HAUTEUR * NB_BLOC_LARGEUR + 1] = {0};
        char path[50];
        int i = 0, j = 0;
    
        sprintf(path,"src/niveaux/editeur_niveau%d.lvl", niv);
        fichier_niveau = fopen(path, "r");
    
        if (fichier_niveau == NULL)
        {
          printf("Impossible d'ouvrir le fichier niveau%d.lvl", niv);
          return 0;
        }
    
        fgets(ligneFichier, NB_BLOC_HAUTEUR * NB_BLOC_LARGEUR + 1, fichier_niveau);
    
        for (i = 0 ; i < NB_BLOC_HAUTEUR  ; i++)
        {
            for (j = 0 ; j < NB_BLOC_LARGEUR ; j++)
            {
                switch (ligneFichier[(j * NB_BLOC_HAUTEUR) + i])
                {
                    case '0':
                        niveau[i][j] = 0;
                        break;
                    case '1':
                        niveau[i][j] = 1;
                        break;
                    case '2':
                        niveau[i][j] = 2;
                        break;
                    case '3':
                        niveau[i][j] = 3;
                        break;
                    case '4':
                        niveau[i][j] = 4;
                        break;
                    case '5':
                        niveau[i][j] = 5;
                        break;
                    case '6':
                        niveau[i][j] = 6;
                        break;
                    case '7':
                        niveau[i][j] = 7;
                        break;
                }
            }
        }
    
        //Recherche de la position de Mario
        for (i = 0; i < NB_BLOC_HAUTEUR ; i++)
            for (j = 0; j < NB_BLOC_LARGEUR ; j++)
                if (niveau[i][j] == MARIO)
    			{
    				positionJoueur->x = i;
    				positionJoueur->y = j;
    				niveau[i][j] = VIDE;
    			}
    
        fclose(fichier_niveau);
        return 1;
    }
    
    //--------------------------------------------------------------------------------------------------------------------------
    
    int sauvegarderNiveau(int carte[][NB_BLOC_LARGEUR], int niv)
    {
        FILE* sauvegarde_niveau = NULL;
        int i = 0, j = 0;
    
        char path [50];
    
        sprintf(path,"src/niveaux/editeur_niveau%d.lvl", niv);
        sauvegarde_niveau = fopen(path, "w");
        
        if (sauvegarde_niveau == NULL)
        {
          printf("Impossible d'ouvrir le fichier sauvegarde.lvl");
          return 0;
        }
    
        for (i = 0 ; i < NB_BLOC_HAUTEUR ; i++)
        {
            for (j = 0 ; j < NB_BLOC_LARGEUR ; j++)
            {
                fprintf(sauvegarde_niveau, "%d", carte[j][i]);
            }
        }
    
        fclose(sauvegarde_niveau);
        return 1;
    }
    
    //--------------------------------------------------------------------------------------------------------------------------
    
    void sauvegardeMouvement(int dernierMouvement)
    {
    	FILE* sauvegarde_mouvement = fopen("src/sauvegarde_mouvement.txt", "a");
        
        if(sauvegarde_mouvement == NULL)
        {
          printf("Impossible d'ouvrir le fichier sauvegarde_mouvement.txt");
          exit(EXIT_FAILURE);
        }
    
      	fprintf(sauvegarde_mouvement, "%d", dernierMouvement); //Ecriture dans le fichier du dernier mouvement
    	fclose(sauvegarde_mouvement);
    }
    
    //--------------------------------------------------------------------------------------------------------------------------
    
    int annulerMouvement(void)
    {
    	int i =0, nombreMouvement = 0;
    	int dernierMouvement = 0, tmp =0;
    
    	FILE* sauvegarde_mouvement = fopen("src/sauvegarde_mouvement.txt", "r");
        if(sauvegarde_mouvement == NULL)
        {
          printf("Impossible d'ouvrir le fichier sauvegarde_mouvement.txt");
          exit(EXIT_FAILURE);
        }
    
    	FILE* mouvement_tmp = fopen("src/mouvement_tmp.txt", "w+");
    	if(mouvement_tmp == NULL)
        {
          printf("Impossible d'ouvrir le fichier mouvement_tmp.txt");
          exit(EXIT_FAILURE);
        }
    
    	while ((dernierMouvement = fgetc(sauvegarde_mouvement)) != EOF ) //On compte le nombre de mouvements dans le fichier de sauvegarde
    		nombreMouvement ++; 
        
    	fseek(sauvegarde_mouvement, -1, SEEK_END); //On positionne le curseur au dernier mouvement et on l'enregistre
    	dernierMouvement = fgetc(sauvegarde_mouvement);
    
    	switch(dernierMouvement)
    	{
    		case '0' :
    		dernierMouvement = 0;
    			break;
    		
    		case '1' :
    		dernierMouvement = 1;
    			break;
    		
    		case '2' :
    		dernierMouvement = 2;
    			break;
    
    		case '3' :
    		dernierMouvement = 3;
    			break;
    		
    		default:
    			break;
    	}
    
    	rewind(sauvegarde_mouvement);
       	
    	for (i=0; i <nombreMouvement-1; i++) //Suppression du dernier mouvement dans le fichier
       	{
    	   tmp = fgetc(sauvegarde_mouvement);
    	   fprintf(mouvement_tmp, "%c", tmp); //On copie la chaîne de mouvements sans le dernier dans le fichier temporaire
        }
    	
    	fclose(sauvegarde_mouvement);
    	fclose(mouvement_tmp);
    
    	copierFichierSauvegarde();  //On copie le fichier temporaire dans le fichier de sauvegarde et on le supprime
    
    	return dernierMouvement;
    }
    
    //--------------------------------------------------------------------------------------------------------------------------
    
    void copierFichierSauvegarde(void)
    {
    	int dernierMouvement = 0;
    
    	FILE* sauvegarde_mouvement = fopen("src/sauvegarde_mouvement.txt", "w+");
        if(sauvegarde_mouvement == NULL)
        {
          printf("Impossible d'ouvrir le fichier sauvegarde_mouvement.txt");
          exit(EXIT_FAILURE);
        }
    
    	FILE* mouvement_tmp = fopen("src/mouvement_tmp.txt", "r");
    	if(mouvement_tmp == NULL)
        {
          printf("Impossible d'ouvrir le fichier mouvement_tmp.txt");
          exit(EXIT_FAILURE);
        }
    
    	while ((dernierMouvement = fgetc(mouvement_tmp)) != EOF )
        {
    		 fprintf(sauvegarde_mouvement, "%c", dernierMouvement);
        }
    
    	fclose(sauvegarde_mouvement);
    	fclose(mouvement_tmp);
    
        remove("src/mouvement_tmp.txt");
    }

     Chargements.c :

    #include <SDL.h>
    #include <SDL_image.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    #include "constantes.h"
    #include "chargements.h"
    
    
    void SDL_ExitWithError(const char *message)
    {
    	SDL_Log("ERREUR : %s > %s\n", message, SDL_GetError());
    	SDL_Quit();
    	exit(EXIT_FAILURE);
    }
    
    //--------------------------------------------------------------------------------------------------------------------------
    
    SDL_Texture* loadTexture(SDL_Renderer* rendu,const char* path, SDL_Rect * pos)
    {
     SDL_Texture* texture = NULL;
     SDL_Surface* tmp = IMG_Load(path);//temporaire
     
     if(tmp == 0)//erreur de chargement
     {
        SDL_DestroyRenderer(rendu);
        SDL_ExitWithError("Impossible de charger l'image");
     }
        texture = SDL_CreateTextureFromSurface(rendu,tmp);
        SDL_FreeSurface(tmp);
    
     if(texture==NULL)//problème
     {
        SDL_DestroyRenderer(rendu);
        SDL_ExitWithError("Impossible de créer la texture");
     }
    
     if(SDL_QueryTexture(texture, NULL, NULL, &pos->w, &pos->h) != 0)
    {
        SDL_DestroyTexture(texture);
        SDL_DestroyRenderer(rendu);
        SDL_ExitWithError("Impossible de charger la texture");
    }
    return texture;
    }
    
    //--------------------------------------------------------------------------------------------------------------------------
    
    void renderCopy(SDL_Renderer* rendu,SDL_Texture *texture, SDL_Rect *coord)
    {
    
    if(SDL_RenderCopy(rendu, texture, NULL, coord)!=0)
        {
        SDL_DestroyTexture(texture);
        SDL_DestroyRenderer(rendu);
        SDL_ExitWithError("Impossible d'.............afficher la texture");
        }
    }
    
    //--------------------------------------------------------------------------------------------------------------------------
    
    void afficherNiveau(SDL_Renderer* rendu, SDL_Texture* image[], int carte[][NB_BLOC_LARGEUR], SDL_Rect *pos, SDL_Rect *posPortail1, SDL_Rect *posPortail2, int *objectifsRestants)
    {
        int i, j;
        for (i = 0 ; i < NB_BLOC_HAUTEUR ; i++)
        {
            for (j = 0 ; j < NB_BLOC_LARGEUR ; j++)
            {
                pos->x = i * TAILLE_BLOC;
                pos->y = j * TAILLE_BLOC;
              
    
                if(VIDE != carte[i][j])
                    renderCopy(rendu, image[carte[i][j]], pos);
                if (OBJECTIF == carte[i][j])
                    *objectifsRestants =1;
                if (carte[i][j] == PORTAIL1)
    			{
    				posPortail1->x = i;
                	posPortail1->y = j;
    			}
    			else if (carte[i][j] == PORTAIL2)
    			{
    				posPortail2->x = i;
                	posPortail2->y = j;
    			} 
            }
        }
                   	
    }
    
    void afficherNiveauEditeur(SDL_Renderer* rendu, SDL_Texture* image[], int carte[][NB_BLOC_LARGEUR], SDL_Rect *pos)
    {
        int i, j;
        for (i = 0 ; i < NB_BLOC_HAUTEUR ; i++)
        {
            for (j = 0 ; j < NB_BLOC_LARGEUR ; j++)
            {
                pos->x = i * TAILLE_BLOC;
                pos->y = j * TAILLE_BLOC;
              
                if(VIDE != carte[i][j])
                    renderCopy(rendu, image[carte[i][j]], pos);
              
            }
        }
                   	
    }
    
    
    
    
    
    

    Editeur.c :

    #include <SDL.h>
    #include <SDL_image.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    #include "constantes.h"
    #include "editeur.h"
    #include "chargements.h"
    #include "fichier.h"
    
    void editeur (SDL_Renderer * rendu, SDL_Texture * image[], SDL_Rect * positionElement)
    {
    
        SDL_Texture *imageActuelle = NULL, *barreControleEditeur = NULL;
        SDL_Rect positionObjetActuel, positionBarreControleEditeur;
    
        positionObjetActuel.x = 0;
        positionObjetActuel.y = 0;
        positionBarreControleEditeur.x = 0;
    	positionBarreControleEditeur.y = TAILLE_BLOC*NB_BLOC_HAUTEUR;
    
        SDL_bool lancement_programme = SDL_TRUE;
        SDL_Event event;
    
        int carte [NB_BLOC_HAUTEUR][NB_BLOC_LARGEUR] = {0};
        int i = 0, j = 0;
        int objetActuel = MUR, marioPlace = 0;
        int clicGaucheEnCours = 0, clicDroitEnCours = 0;
        int niveau = 1;
    
        barreControleEditeur = loadTexture(rendu,"src/images/barre_controle_editeur.jpg", &positionBarreControleEditeur);
        imageActuelle = image[MUR];
        if(SDL_QueryTexture(imageActuelle, NULL, NULL, &positionObjetActuel.w, &positionObjetActuel.h) != 0)
            {
                SDL_DestroyTexture(imageActuelle);
                SDL_DestroyRenderer(rendu);
                SDL_ExitWithError("Impossible de charger la texture");
            }
     
        //-------------------------------------------------------------------------------
        //DEBUT BOUCLE EVENT
       
        while (lancement_programme)
        {
            while (SDL_PollEvent(&event))
            {
                switch(event.type)
                {
                    case SDL_QUIT:
                    SDL_Quit();
                    break; 
                    
                    case SDL_MOUSEBUTTONDOWN :
                        if (event.button.button == SDL_BUTTON_LEFT)
                        {
                            testMario(objetActuel, carte);                                                                      
                            carte[event.button.x/TAILLE_BLOC][event.button.y/TAILLE_BLOC] = objetActuel;     //Placer dans le tableau "carte" l'élément sélectionné au préalable
                            clicGaucheEnCours = 1;
                        }
                            
                        else if(event.button.button == SDL_BUTTON_RIGHT)
                        {
                            carte[event.button.x/TAILLE_BLOC][event.button.y/TAILLE_BLOC] = VIDE ;  //Placer du VIDE dans le tableau "carte"
                            clicDroitEnCours = 1;
                        }         
                        break;
                    
                    case SDL_MOUSEBUTTONUP :
                        if (event.button.button == SDL_BUTTON_LEFT)
                            clicGaucheEnCours = 0;                      //Remise à zero du boolen ClicGaucheEnCours    
                        else if(event.button.button == SDL_BUTTON_RIGHT)
                            clicDroitEnCours = 0;                       //Remise à zero du boolen ClicDroitEnCours  
                        break;
    
                    case SDL_MOUSEMOTION :
                        positionObjetActuel.x = event.motion.x;
                        positionObjetActuel.y = event.motion.y;
    
                        if (clicGaucheEnCours)
                        {
                            testMario(objetActuel, carte);
                            carte[event.motion.x/TAILLE_BLOC][event.motion.y/TAILLE_BLOC] = objetActuel;  //Placer dans le tableau "carte" l'élément sélectionné au préalable                             
                        }   
                            
                        else if(clicDroitEnCours)
                        {    
                            carte[event.motion.x/TAILLE_BLOC][event.motion.y/TAILLE_BLOC] = VIDE ; //Placer du VIDE dans le tableau "carte"   
                        }
                        break;
                
                    case SDL_KEYDOWN:
                        switch(event.key.keysym.sym)
                        {
                            case SDLK_ESCAPE: 
                                lancement_programme = SDL_FALSE;
                                break;
    
                            case SDLK_SPACE: 
                                initialisationEditeur(carte);  	
    							break;
    
                            case SDLK_s:
                                sauvegarderNiveau(carte, niveau);				
                                break;
                            
                            case SDLK_RETURN :
                                sauvegarderNiveau(carte, niveau);
                                niveau++;
                                initialisationEditeur(carte);
                                break;
    
                            case SDLK_1:
                                //Changer pour MUR 
                                objetActuel = MUR;
                                imageActuelle = image[MUR];
                                break;
    
                            case SDLK_2:
                                //Changer pour CAISSE
                                objetActuel = CAISSE;
                                imageActuelle = image[CAISSE];								 								
                                break;
    
                            case SDLK_3:
                                //Changer pour OBJECTIF 
                                objetActuel = OBJECTIF;
                                imageActuelle = image[OBJECTIF];																
                                break;
    
                            case SDLK_4:
                                //Changer pour MARIO 
                                objetActuel = MARIO;
                                imageActuelle = image[MARIO];	
                                break;
                            
                            case SDLK_5:
                                //Changer pour CAISSE_OK 
                                objetActuel = CAISSE_OK;
                                imageActuelle = image[CAISSE_OK];	
                                break;
                            
                            case SDLK_6:
                                //Changer pour PORTAIL1 
                                objetActuel = PORTAIL1;
                                imageActuelle = image[PORTAIL1];	
                                break;
    
                            case SDLK_7:
                                //Changer pour PORTAIL2 
                                objetActuel = PORTAIL2;
                                imageActuelle = image[PORTAIL2];	
                                break;
    
                            default:
                                break;
                        }
                        break;                       	
                        
                    default:
                        break; 
                } 
            }
    
            if(SDL_RenderClear(rendu) != 0)
            {
                SDL_DestroyRenderer(rendu);
                SDL_ExitWithError("Impossible d'effacer le rendu");
            }
    
            if(SDL_SetRenderDrawColor(rendu, 255, 255, 255, SDL_ALPHA_OPAQUE) !=0)
            {
                SDL_DestroyRenderer(rendu);
                SDL_ExitWithError("Impossible de changer la couleur");
            }
    
            afficherNiveauEditeur(rendu, image, carte, positionElement);
            renderCopy(rendu, imageActuelle, &positionObjetActuel);
            renderCopy(rendu, barreControleEditeur, &positionBarreControleEditeur);
            SDL_RenderPresent(rendu);
        }
        
    SDL_DestroyTexture(barreControleEditeur);    
    }
    
    //--------------------------------------------------------------------------------------------------------------------------
    
    void testMario(int objetActuel, int carte[][NB_BLOC_LARGEUR])
    {  
      int i, j;
    
      if(MARIO == objetActuel)                           
        for (i = 0; i < NB_BLOC_HAUTEUR ; i++)                               
            for (j = 0; j < NB_BLOC_LARGEUR ; j++)                                    
                if (carte[i][j] == MARIO)                                        
                    carte[i][j] = VIDE;
    }
    
    //--------------------------------------------------------------------------------------------------------------------------
    
    void initialisationEditeur(int carte[][NB_BLOC_LARGEUR])
    {    
    	int i, j;
    	
    	for (i = 0; i < NB_BLOC_HAUTEUR ; i++)
            for (j = 0; j < NB_BLOC_LARGEUR ; j++)
    				carte[i][j] = VIDE;
    }
    

    Constantes.h :

    #ifndef DEF_CONSTANTES
    #define DEF_CONSTANTES
    
        #define TAILLE_BLOC         34
        #define NB_BLOC_LARGEUR     12
        #define NB_BLOC_HAUTEUR     12
        #define HAUTEUR_BARRE_CONTROLE 34
        #define LAGEUR_BARRE_CONTROLE  TAILLE_BLOC*NB_BLOC_LARGEUR
        #define LARGEUR_FENETRE     TAILLE_BLOC*NB_BLOC_LARGEUR 
        #define HAUTEUR_FENETRE     (TAILLE_BLOC*NB_BLOC_HAUTEUR)+HAUTEUR_BARRE_CONTROLE
    
        enum {HAUT, BAS, GAUCHE, DROITE};
        enum {VIDE, MUR, CAISSE, OBJECTIF, MARIO, CAISSE_OK, PORTAIL1, PORTAIL2};
    
    #endif



    -
    Edité par Plixel 16 janvier 2020 à 17:40:39

    • Partager sur Facebook
    • Partager sur Twitter
      19 janvier 2020 à 14:11:15

      Bonjour,

      Personne ne peut m'aider?

      En fait, j'ai compris d'où vient le problème. Prenons l'exemple suivant

      -Mario (0;0) se déplace d'une case vide vers le bas (0;1), puis de deux cases vides vers la droite(2;1), arrive devant une caisse et la pousse d'une case vers la droite(Mario : 3;1 / Caisse : 4;1).

      -En appuyant sur Tab, Mario recule d'une case vers la gauche(2;1) et la caisse également (3;1). Jusque là tout va bien, la caisse est à sa position initiale.

      -Mais en appuyant à nouveau deux fois sur Tab, pour faire revenir Mario à la position (0;1), la caisse suit le mouvement car la fonction deplacerCaisse() est vérifiée (carte[pos->x+2][pos->x] contient bien une caisse) et donc effectuée.

      -Le dernier mouvement de retour, vers le haut (0;0) ne permet pas de vérifier déplacerCaisse donc la caisse reste à son emplacement.

      (J'espère avoir été clair ^^)

      Du coup, il faudrait pouvoir garder en mémoire le nombre de déplacement qu'une caisse effectue dans chaque direction et décrémenter ce nombre si le joueur annule ses coups. Si le nombre de déplacement atteint 0, on ne déplace plus la caisse.

      Mais ça me semble très compliqué à mettre en place, d'autant qu'il y a plusieurs caisses parfois par niveau, donc il faudrait pouvoir également distinguer les mouvements de chacune d'entre elles...

      Bref, si vous avez un début d'idée ou de piste, je suis preneur. Peut-être que je complique trop la tête et qu'une solution plus simple peut-être trouvée, mais là je ne vois pas pas

      Merci :)

      • Partager sur Facebook
      • Partager sur Twitter
        19 janvier 2020 à 16:19:57

        Bonjour,

        pour attaquer dans le vif du sujet, je vais m'en prendre au TP du sokoban : Il ne s'agît là que d'un petit exercice qui permet peu de sortir des règles fixées. Je suis globalement autodidacte en la matière, même si je profite toujours de l'aide des autres, mais l'expérience m'a amené à croire que mélanger une carte (tilemap) et les éléments actifs (ou mobiles) est une très mauvaise idée, la gestion proposée par ce TP est, selon moi, très mauvaise.

        Pour faire ce que tu souhaites sans péter tout le code, j'utiliserais une structure de mémorisation d'un coup joué puis une table de cette structure.

        Il suffirait de "remonter" dans la table pour suivre l'historique des coups, quelque chose comme ça :

        typedef struct S_Position
        {
           int x,
               y;
        }
        Position;
        
        typedef struct S_Memoire
        {
          Position mario,
                   caisse[10];
        }
        Memoire;
        
        //*dans le programme :
        
        Memoire historique[50];

        Idéalement, il faudrait mettre des tables dynamiques pour adapter le nombre de caisses et "agandir" l'historique au fur et à mesure.

        à chaque coup joué, tu mémorises la position de mario et des caisses que tu n'auras plus qu'à relire pour revenir en arrière.

        Bonne continuation.

        • Partager sur Facebook
        • Partager sur Twitter

        Bonhomme !! | Jeu de plateforme : Prototype.

          20 janvier 2020 à 15:05:53

          Bonjour,

          Merci beaucoup pour ta réponse.

          Je n'avais pas encore atteint la dernière partie du cours et en la lisant aujourd'hui, je me rends compte que je pourrai effectivement me simplifier la vie avec les structures de données. Je vais potasser tout ça et voir ce que j'arrive à faire :)

          Pour ta remarque sur le TP en lui-même, si je comprends bien, ce que tu conseillerais c'est de séparer tout ce qui concerne l'affichage de la map des déplacements du joueur/caisse ?

          Merci

          • Partager sur Facebook
          • Partager sur Twitter

          TP Mario Sokoban - annuler les coups

          × 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