Je suis actuellement débutant dans le domaine du codage et je me planche sur le TP Mario sokoban (je suis en SDL2) et voila plusieurs jours que je bloque au moment de lancer ma partie.
Je peut lancer mon éditeur de map et sauvegarder sans le moindre soucis mais quand je lance ma partie je reste sur le menu, puis le jeux crash si j'utilise une input, la compilation manuelle et via CodeBlocks ne me retourne aucun warning ou erreur. Je n'arrive pas a trouver ce qu'il ne va pas pourtant mon code est quasiment identique a celui du cours.
Dans l'espoir que quelqu'un puisse m'éclairer ou m'orienter sur mon problème !
jeu.c
#include <stdlib.h>
#include <stdio.h>
#include <SDL.h>
#include "SDL_image.h"
#include "constantes.h"
#include "jeu.h"
#include "editeur.h"
#include "fichier.h"
void jouer(SDL_Window *pWindow)
{
SDL_bool partieLancer = SDL_TRUE;
int objectifsRestants = 0, i = 0, j = 0;
int carte[NB_BLOCS_LARGEUR][NB_BLOCS_HAUTEUR] = {0};
SDL_Surface *directionMario[4] = {NULL}; // 4 surfaces pour 4 directions de mario
SDL_Surface *mur = NULL, *caisse = NULL, *caisseOK = NULL, *objectif = NULL, *marioActuel = NULL;
SDL_Surface *ecran = NULL;
SDL_Rect position, positionJoueur;
SDL_Event event;
ecran = SDL_GetWindowSurface(pWindow);
directionMario[HAUT] = IMG_Load("src/marioHAUT.gif");
directionMario[BAS] = IMG_Load("src/marioBAS.gif");
directionMario[GAUCHE] = IMG_Load("src/marioGAUCHE.gif");
directionMario[DROITE] = IMG_Load("src/marioDROITE.gif");
caisse = IMG_Load("src/caisse.jpg");
mur = IMG_Load("src/mur.jpg");
caisseOK = IMG_Load("src/caisseSurObjectif.jpg");
objectif = IMG_Load("src/objectif.png");
marioActuel = directionMario[BAS];
if (!chargerNiveau(carte))
exit(EXIT_FAILURE);
// Recherche de la position de Mario au départ
for (i = 0 ; i < NB_BLOCS_LARGEUR ; i++)
{
for (j = 0 ; j < NB_BLOCS_HAUTEUR ; j++)
{
if (carte[i][j] == MARIO) // Si Mario se trouve à cette position sur la carte
{
positionJoueur.x = i;
positionJoueur.y = j;
carte[i][j] = VIDE;
}
}
}
while (partieLancer)
{
SDL_WaitEvent(&event);
switch(event.type)
{
case SDL_QUIT:
partieLancer = SDL_FALSE;
break;
case SDL_KEYDOWN:
switch(event.key.keysym.sym)
{
case SDLK_UP:
marioActuel = directionMario[HAUT];
deplacerJoueur(carte, &positionJoueur, HAUT);
break;
case SDLK_DOWN:
marioActuel = directionMario[BAS];
deplacerJoueur(carte, &positionJoueur, BAS);
break;
case SDLK_RIGHT:
marioActuel = directionMario[DROITE];
deplacerJoueur(carte, &positionJoueur, DROITE);
break;
case SDLK_LEFT:
marioActuel = directionMario[GAUCHE];
deplacerJoueur(carte, &positionJoueur, GAUCHE);
break;
case SDLK_ESCAPE:
partieLancer = SDL_FALSE;
break;
}
default:
continue;
}
SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 255, 255, 255));
objectifsRestants = 0;
for (i = 0 ; i < NB_BLOCS_LARGEUR ; i++)
{
for (j = 0 ; j < NB_BLOCS_HAUTEUR ; j++)
{
position.x = i * TAILLE_BLOC;
position.y = j * TAILLE_BLOC;
switch(carte[i][j])
{
case MUR:
SDL_BlitSurface(mur, NULL, ecran, &position);
break;
case CAISSE:
SDL_BlitSurface(caisse, NULL, ecran, &position);
break;
case CAISSE_OK:
SDL_BlitSurface(caisseOK, NULL, ecran, &position);
break;
case OBJECTIF:
SDL_BlitSurface(objectif, NULL, ecran, &position);
objectifsRestants = 1;
break;
}
}
}
// Si on n'a trouvé aucun objectif sur la carte, c'est qu'on a gagné
if (!objectifsRestants)
{
printf("partie gagner \n");
partieLancer = SDL_FALSE;
}
// On place le joueur à la bonne position
position.x = positionJoueur.x * TAILLE_BLOC;
position.y = positionJoueur.y * TAILLE_BLOC;
SDL_BlitSurface(marioActuel, NULL, ecran, &position);
SDL_UpdateWindowSurface(pWindow);
}
SDL_FreeSurface(mur);
SDL_FreeSurface(caisse);
SDL_FreeSurface(caisseOK);
SDL_FreeSurface(objectif);
for (i = 0 ; i < 4 ; i++)
SDL_FreeSurface(directionMario[i]);
SDL_FreeSurface(ecran);
}
void deplacerJoueur(int carte[][NB_BLOCS_HAUTEUR], SDL_Rect *pos, int direction)
{
switch(direction)
{
case HAUT:
{
if(pos->y - 1 < 0)
break;
if (carte[pos->x][pos->y - 1] == MUR)
break;
// Si on veut pousser une caisse, il faut vérifier qu'il n'y a pas de mur derrière (ou une autre caisse, ou la limite du monde)
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))
break;
deplacerCaisse(&carte[pos->x][pos->y - 1], &carte[pos->x][pos->y - 2]);
pos->y--;
break;
}
case BAS:
{
if(pos->y + 1 < HAUTEUR_FENETRE)
break;
if (carte[pos->x][pos->y + 1] == MUR)
break;
// Si on veut pousser une caisse, il faut vérifier qu'il n'y a pas de mur derrière (ou une autre caisse, ou la limite du monde)
if((carte[pos->x][pos->y + 1] == CAISSE || carte[pos->x][pos->y + 1] == CAISSE_OK) && (pos->y + 2 < HAUTEUR_FENETRE ||
carte[pos->x][pos->y + 2] == MUR ||carte[pos->x][pos->y + 2] == CAISSE || carte[pos->x][pos->y + 2] == CAISSE_OK))
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;
// Si on veut pousser une caisse, il faut vérifier qu'il n'y a pas de mur derrière (ou une autre caisse, ou la limite du monde)
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;
deplacerCaisse(&carte[pos->x - 1][pos->y], &carte[pos->x - 2][pos->y]);
pos->x--;
break;
}
case DROITE:
{
if(pos->x + 1 < LARGEUR_FENETRE)
break;
if (carte[pos->x + 1][pos->y] == MUR) // S'il y a un mur, on arrête
break;
// Si on veut pousser une caisse, il faut vérifier qu'il n'y a pas de mur derrière (ou une autre caisse, ou la limite du monde)
if((carte[pos->x + 1][pos->y] == CAISSE || carte[pos->x + 1][pos->y] == CAISSE_OK) && (pos->x + 2 < LARGEUR_FENETRE ||
carte[pos->x + 2][pos->y] == MUR ||carte[pos->x + 2][pos->y] == CAISSE || carte[pos->x + 2][pos->y] == CAISSE_OK))
break;
deplacerCaisse(&carte[pos->x + 1][pos->y], &carte[pos->x + 2][pos->y]);
pos->x++;
break;
}
}
}
void deplacerCaisse(int *premiereCase, int *secondeCase)
{
if (*premiereCase == CAISSE || *premiereCase == CAISSE_OK)
{
if (*secondeCase == OBJECTIF)
*secondeCase = CAISSE_OK;
else
*secondeCase = CAISSE;
if(*premiereCase == CAISSE_OK)
*premiereCase = OBJECTIF;
else
*premiereCase = VIDE;
}
}
fichier.c
#include <stdlib.h>
#include <stdio.h>
#include "constantes.h"
int chargerNiveau(int niveau[][NB_BLOCS_HAUTEUR])
{
FILE *fichier = NULL;
char ligneFichier[NB_BLOCS_LARGEUR * NB_BLOCS_HAUTEUR + 1] = {0};
int i = 0, j = 0;
fichier = fopen("src/niveau.lvl", "r");
if(fichier == NULL)
{
printf("fichier non charger");
return 0;
}
fgets(ligneFichier, NB_BLOCS_LARGEUR * NB_BLOCS_HAUTEUR + 1, fichier);
printf("niveau charger \n");
for (i = 0; i < NB_BLOCS_LARGEUR; i++)
{
for (j = 0; j < NB_BLOCS_HAUTEUR; j++)
{
switch (ligneFichier[(i * NB_BLOCS_LARGEUR) + j])
{
case '0':
niveau[j][i] = 0;
break;
case '1':
niveau[j][i] = 1;
break;
case '2':
niveau[j][i] = 2;
break;
case '3':
niveau[j][i] = 3;
break;
case '4':
niveau[j][i] = 4;
break;
}
}
}
fclose(fichier);
return 1;
}
int sauvegarderNiveau(int niveau[][NB_BLOCS_HAUTEUR])
{
FILE* fichier = NULL;
int i = 0, j = 0;
fichier = fopen("src/niveau.lvl", "w");
if (fichier == NULL)
return 0;
for (i = 0 ; i < NB_BLOCS_LARGEUR ; i++)
{
for (j = 0 ; j < NB_BLOCS_HAUTEUR ; j++)
{
fprintf(fichier, "%d", niveau[j][i]);
}
}
printf("sauvegarde effectué !\n");
fclose(fichier);
return 1;
}
Fais plus de fonctions. Des petites fonctions qui font une chose et le font bien, c'est parfait (tes fonctions ne devraient pas faire plus d'une vingtaine de ligne dans l'idéal).
Vérifie le retour des fonctions à risques (chargement d'images, initialisation tout ça).
Pourquoi tes images sont dans le dossier src ? Dans un dossier rsc (pour « ressources » je voudrais bien, mais src, c'est généralement pour les sources).
Utilise la SDL 2 « pour de vrai », utilise des textures et pas des surfaces, un renderer et pas la surface de l'écran.
Dans ta fonction de chargement de niveau, ce que tu fais en gros c'est niveau[i][j] = fichier[i * NB_LARGEUR + I] - '0'. Néanmoins, pour quelque chose de mieux et de plus simple, je t'invite à te pencher sur le tutoriel de @Fvirtman sur le tile mapping.
Code en français ou en anglais, mais pas les deux.
Faute de frappe, ce n'est pas I mais j. Le truc, c'est que (en tout cas en ASCII) 0 = '0' - '0', 1 = '1' - '0', ..., 9 = '9' - '0', donc plutôt que de faire plusieurs cas (regarder si c'est un '1', un 2, etc.), il te suffit de soustraire '0'.
Tu as une fuite mémoire ; la surface que tu charges pour ton icône n'est jamais libérée (encore une mauvaise pratique du tutoriel d'OC...). Et aucun de tes chargements d'image n'est vérifié.
je viens de finir la version SDL2, mais j'ai toujours se problème de partie qui ne se lance pas (le jeu reste sur le menu) j'ai pourtant un retour positif sur le chargement de la map et encore une fois mon éditeur fonctionne. ps: je sais me reste 2 ou 3 truc a réécrire en anglais.
Si jamais quelq'un a une idée ou une reponse a mon problème !
Je n'ai pas tout analysé, les n° des lignes indiqués sont ceux de jeu.c
Ligne 111, tu mets remainObjective à 0. J'imagine que tu n'arrives ligne 132 (case OBJECTIF) que si mario se déplace sur son objectif. À ce moment seulement, tu mets remainObjective à 1.
Donc, si mario n'est pas sur l'objectif, le test ligne 145 est vrai (!0 est vrai), donc game_lauch est mis à faux, donc tu quittes le while, et bye bye la fonction jeu().
- Edité par edgarjacobs 10 juillet 2018 à 22:28:33
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
Le conseil le plus important n'a pas été pris en compte, faire des petites fonctions. En faisant des petites fonctions, tu peux les tester une à une plus facilement, et ça t'aurait permis de te rendre compte que ton affichage n'est pas fait correctement.
Tu ne donnes jamais la couleur à utiliser pour nettoyer l'écran (=> SDL_SetRenderDrawColor).
Tu utilises SDL_RenderCopy, mais tu ne donnes pas de dimensions au rectangle à utiliser ( => donner des valeurs au champ w et h de position).
Ligne 111, tu mets remainObjective à 0. J'imagine que tu n'arrives ligne 132 (case OBJECTIF) que si mario se déplace sur son objectif. À ce moment seulement, tu mets remainObjective à 1.
Donc, si mario n'est pas sur l'objectif, le test ligne 145 est vrai (!0 est vrai), donc game_launch est mis à faux, donc tu quittes le while, et bye bye la fonction jeu().
j'ai vérifier, pas de soucis de se coter la (j'ai enlever la condition temporairement), enfaite quand je lance ma fonction "play()" cela ne s'actualise pas (le menu reste afficher), par contre si j'appuis sur les Fleche de direction le jeux crash quand je rencontre une caisse et que j'essaie de la déplacer avec pour message dans ma console "Surface doesn't have a colorkey".
Pour ce qui est de "w" et "h" je les déclarer au début en même temps que le rectangle position j'ai tester de les redéclarer en même temps que x et y dans mon coter mais cela ne change rien.
PS : ce serait mieux d'avoir le code sur un paste ou encore mieux sur Github avec tous les fichiers nécessaires histoire qu'on puisse compiler et tester.
Dans le default du switch de ta boucle principale, regarde ce que tu as mis.
Pourquoi &*pos dans tes appels à hitBox ? Envoie pos.
Pourquoi appeler SDL_ExitWithError s'il y a une erreur de déplacement de la caisse ? S'il y a un problème, il n'a aucun rapport avec la SDL, et pourtant ça fait que tu appelles SDL_GetError. De plus, pourquoi vérifier la fonction moveBox.
Ta fonction hitBox n'est pas correcte. Que se passe-t-il s'il n'y a rien devant toi, pas de caisse, pas de mur, mais juste du vide ? Tu renvoies 1 et donc on essaie ensuite de bouger la caisse, ce qui conduit à l'échec de moveBox et donc à l'appel de SDL_ExitWiethEroor (ce serait mieux avec Error).
Effectivement c'était bien le "continue" du "switch" qui empêchait l'affichage des Texture , j'ai aussi corriger ma fonction "hitBox()" de manière a pouvoir me déplacer en cas de case vide, par contre si j'envoie "pos" en paramètre sa ne fonctionne pas j'obtiens une erreur.
j'ai encore un soucis sur les déplacement des caisse en direction bas et droite mais le gros de mon soucis est réglé.
Je viens d'essayer avec pos, pas de problème. Pour les problèmes de déplacement des caisses, regarde du côté de moveBox, de hitBox et des arguments que tu donnes.
Après, tes fonctions sont plutôt compliquées. Notamment, pourquoi retourner 1 ou 2 dans hitBox si on ne touche rien (d'ailleurs, il manque aussi le cas de l'objectif). En fait, on pourrait même avoir beaucoup, mais beaucoup plus de fonctions.
Une fonction qui dit si une case est vide (c'est-à-dire VIDE ou OBJECTIF).
Une fonction qui dit si une case est une caisse.
Une fonction qui dit si la case devant nous est libre.
Un fonction qui nous dit si la case encore après est libre.
Une fonction qui nous dit s'il y a une caisse devant nous.
Avec tout ça il est facile de savoir si on peut se déplacer.
Si devant nous c'est libre
C'est OK, on le déplace
Sinon si devant nous il y a une caisse
Si la case encore après est libre
C'est OK, on déplace la caisse, et on le déplace
× 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.
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent