Je suis actuellement sur le tuto "Apprenez a programmer en C !" au niveau du Mario Sokoban et étant sur Mac je suis obliger de suivre le cours avec la SDL2. J'adapte donc tout au fur et à mesure.
Cependant impossible de faire fonctionner le Mario Sokoban :/
J'ai bien la page d'accueil qui charge avec le menu et le switch fonctionne, cependant lorsque que je lance le jeu le niveau ne se charge pas et du coup reviens sur la page du menu, dans l'éditeur les éléments ne s'affiche pas non plus.
De plus je ne comprend pas comment la suite de chiffre du fichier niveaux.txt, peut charger les éléments du niveau.
Merci de votre aide
main.c
#include <stdlib.h>
#include <stdio.h>
#include <SDL2/SDL.h>
#include <SDL2_image/SDL_image.h>
#include "constantes.h"
#include "jeu.h"
#include "editeur.h"
int main(int argc, const char * argv[]) {
SDL_Window *window = NULL;
SDL_Renderer* renderer = NULL;
SDL_Surface *imageTmp, *icon = NULL;
SDL_Texture *menu, *ecran = NULL;
// SDL_Rect positionMenu;
SDL_Event event;
int continuer = 1;
// Initialisation de la SDL
SDL_Init(SDL_INIT_VIDEO);
// Création de la fenêtre et du renderer
window = SDL_CreateWindow("Mario Sokoban", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, LARGEUR_FENETRE, HAUTEUR_FENETRE, SDL_SWSURFACE);
if (window == NULL){ // Si l'ouverture a échoué, on le note et on arrête
fprintf(stderr, "Impossible de charger le mode vidéo : %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
renderer = SDL_CreateRenderer(window, -1, 0); // Création du renderer
icon = IMG_Load("/Users/Mickahell/Documents/Xcode/C/sokoban/sokoban/caisse.jpg");
SDL_SetWindowIcon(window, icon);
SDL_FreeSurface(icon);
//Menu
imageTmp = IMG_Load("/Users/Mickahell/Documents/Xcode/C/sokoban/sokoban/menu.jpg");
menu = SDL_CreateTextureFromSurface(renderer, imageTmp);
SDL_FreeSurface(imageTmp);
SDL_Rect positionMenu = {0, 0, 408, 408};
while (continuer)
{
SDL_WaitEvent(&event);
switch(event.type)
{
case SDL_QUIT:
continuer = 0;
break;
case SDL_KEYDOWN:
switch(event.key.keysym.sym)
{
case SDLK_ESCAPE: // Veut arrêter le jeu
continuer = 0;
break;
case SDLK_1: // Demande à jouer
jouer(window, renderer);
break;
case SDLK_2: // Demande l'éditeur de niveaux
editeur(window, renderer);
break;
}
break;
}
//Fond
// SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); // Selection couleur
// SDL_RenderClear(renderer); // Peigner TOUT le renderer avec la couleur
SDL_SetRenderTarget(renderer, menu); /* La cible de rendu est maintenant menu. */
SDL_RenderCopy(renderer, menu, NULL, &positionMenu); // On copie menu sur le renderer
// Update renderer
SDL_RenderPresent(renderer); // Mise à jour du renderer
}
SDL_DestroyTexture(menu);
SDL_DestroyTexture(ecran);
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit(); // Arrêt de la SDL
return EXIT_SUCCESS; // Fermeture du programme
}
jeu.c
#include "jeu.h"
#include "constantes.h"
#include <SDL2/SDL.h>
#include <SDL2_image/SDL_image.h>
#include "fichiers.h"
void jouer(SDL_Window* window, SDL_Renderer* renderer){
SDL_Texture *mario[4] = {NULL}; // 4 surfaces pour 4 directions de mario
SDL_Texture *mur = NULL, *caisse = NULL, *caisseOK = NULL, *objectif = NULL, *marioActuel = NULL;
SDL_Rect position, positionJoueur;
SDL_Event event;
SDL_Surface *imageTmp = NULL;
int continuer = 1, objectifsRestants = 0, i = 0, j = 0;
int carte[NB_BLOCS_LARGEUR][NB_BLOCS_HAUTEUR] = {0};
//Images
imageTmp = IMG_Load("/Users/Mickahell/Documents/Xcode/C/sokoban/sokoban/mur.jpg");
mur = SDL_CreateTextureFromSurface(renderer, imageTmp);
SDL_FreeSurface(imageTmp);
imageTmp = IMG_Load("/Users/Mickahell/Documents/Xcode/C/sokoban/sokoban/caisse.jpg");
caisse = SDL_CreateTextureFromSurface(renderer, imageTmp);
SDL_FreeSurface(imageTmp);
imageTmp = IMG_Load("/Users/Mickahell/Documents/Xcode/C/sokoban/sokoban/caisseOK.jpg");
caisseOK = SDL_CreateTextureFromSurface(renderer, imageTmp);
SDL_FreeSurface(imageTmp);
imageTmp = IMG_Load("/Users/Mickahell/Documents/Xcode/C/sokoban/sokoban/objectif.png");
objectif = SDL_CreateTextureFromSurface(renderer, imageTmp);
SDL_FreeSurface(imageTmp);
imageTmp = IMG_Load("/Users/Mickahell/Documents/Xcode/C/sokoban/sokoban/mario_bas.gif");
mario[BAS] = SDL_CreateTextureFromSurface(renderer, imageTmp);
SDL_FreeSurface(imageTmp);
imageTmp = IMG_Load("/Users/Mickahell/Documents/Xcode/C/sokoban/sokoban/mario_gauche.gif");
mario[GAUCHE] = SDL_CreateTextureFromSurface(renderer, imageTmp);
SDL_FreeSurface(imageTmp);
imageTmp = IMG_Load("/Users/Mickahell/Documents/Xcode/C/sokoban/sokoban/mario_haut.gif");
mario[HAUT] = SDL_CreateTextureFromSurface(renderer, imageTmp);
SDL_FreeSurface(imageTmp);
imageTmp = IMG_Load("/Users/Mickahell/Documents/Xcode/C/sokoban/sokoban/mario_droite.gif");
mario[DROITE] = SDL_CreateTextureFromSurface(renderer, imageTmp);
SDL_FreeSurface(imageTmp);
marioActuel = mario[BAS]; // Mario sera dirigé vers le bas au départ
// Chargement du niveau
if (!chargerNiveau(carte))
exit(EXIT_FAILURE); // On arrête le jeu si on n'a pas pu charger le niveau
// 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
{
positionJoueur.x = i;
positionJoueur.y = j;
carte[i][j] = VIDE;
}
}
}
while (continuer)
{
SDL_WaitEvent(&event);
switch(event.type)
{
case SDL_QUIT:
continuer = 0;
break;
case SDL_KEYDOWN:
switch(event.key.keysym.sym)
{
case SDLK_ESCAPE:
continuer = 0;
break;
case SDLK_UP:
marioActuel = mario[HAUT];
deplacerJoueur(carte, &positionJoueur, HAUT);
break;
case SDLK_DOWN:
marioActuel = mario[BAS];
deplacerJoueur(carte, &positionJoueur, BAS);
break;
case SDLK_RIGHT:
marioActuel = mario[DROITE];
deplacerJoueur(carte, &positionJoueur, DROITE);
break;
case SDLK_LEFT:
marioActuel = mario[GAUCHE];
deplacerJoueur(carte, &positionJoueur, GAUCHE);
break;
}
break;
}
//Effacage de l'écran pour du blanc
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); // Selection couleur
SDL_RenderClear(renderer); // Peigner TOUT le renderer avec la couleur
printf("Blanc\n");
// Placement des objets à l'écran
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_SetRenderTarget(renderer, NULL);
SDL_RenderCopy(renderer, mur, NULL, &position);
break;
case CAISSE:
SDL_SetRenderTarget(renderer, NULL);
SDL_RenderCopy(renderer, caisse, NULL, &position);
break;
case CAISSE_OK:
SDL_SetRenderTarget(renderer, NULL);
SDL_RenderCopy(renderer, caisseOK, NULL, &position);
break;
case OBJECTIF:
SDL_SetRenderTarget(renderer, NULL);
SDL_RenderCopy(renderer, objectif, NULL, &position);
objectifsRestants = 1;
break;
}
}
}
printf("Chargement niveau\n");
// Si on n'a trouvé aucun objectif sur la carte, c'est qu'on a gagné
if (!objectifsRestants){
continuer = 0;
}
// On place le joueur à la bonne position
position.x = positionJoueur.x * TAILLE_BLOC;
position.y = positionJoueur.y * TAILLE_BLOC;
SDL_SetRenderTarget(renderer, NULL);
SDL_RenderCopy(renderer, marioActuel, NULL, &position);
// Update renderer
SDL_RenderPresent(renderer); // Mise à jour du renderer
}
SDL_DestroyTexture(mur);
SDL_DestroyTexture(caisse);
SDL_DestroyTexture(caisseOK);
SDL_DestroyTexture(objectif);
for (i = 0 ; i < 4 ; i++)
SDL_DestroyTexture(mario[i]);
}
void deplacerJoueur(int carte[][NB_BLOCS_HAUTEUR], SDL_Rect *pos, int direction){
switch(direction)
{
case HAUT:
if (pos->y - 1 < 0) // Si le joueur dépasse l'écran, on arrête
break;
if (carte[pos->x][pos->y - 1] == 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][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;
// Si on arrive là, c'est qu'on peut déplacer le joueur !
// On vérifie d'abord s'il y a une caisse à déplacer
deplacerCaisse(&carte[pos->x][pos->y - 1], &carte[pos->x][pos->y - 2]);
pos->y--; // On peut enfin faire monter le joueur (oufff !)
break;
case BAS:
if (pos->y + 1 >= NB_BLOCS_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_BLOCS_HAUTEUR || 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;
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 >= NB_BLOCS_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_BLOCS_LARGEUR || 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;
}
}
editeur.c
#include "editeur.h"
#include "constantes.h"
#include "fichiers.h"
#include <SDL2/SDL.h>
#include <SDL2_image/SDL_image.h>
void editeur(SDL_Window* window, SDL_Renderer* renderer)
{
SDL_Texture *mur = NULL, *caisse = NULL, *objectif = NULL, *mario = NULL;
SDL_Surface *imageTmp = NULL;
SDL_Rect position;
SDL_Event event;
int continuer = 1, clicGaucheEnCours = 0, clicDroitEnCours = 0;
int objetActuel = MUR, i = 0, j = 0;
int carte[NB_BLOCS_LARGEUR][NB_BLOCS_HAUTEUR] = {0};
// Chargement des objets et du niveau
imageTmp = IMG_Load("/Users/Mickahell/Documents/Xcode/C/sokoban/sokoban/mur.jpg");
mur = SDL_CreateTextureFromSurface(renderer, imageTmp);
SDL_FreeSurface(imageTmp);
imageTmp = IMG_Load("/Users/Mickahell/Documents/Xcode/C/sokoban/sokoban/caisse.jpg");
caisse = SDL_CreateTextureFromSurface(renderer, imageTmp);
SDL_FreeSurface(imageTmp);
imageTmp = IMG_Load("/Users/Mickahell/Documents/Xcode/C/sokoban/sokoban/objectif.png");
objectif = SDL_CreateTextureFromSurface(renderer, imageTmp);
SDL_FreeSurface(imageTmp);
imageTmp = IMG_Load("/Users/Mickahell/Documents/Xcode/C/sokoban/sokoban/mario_bas.gif");
mario = SDL_CreateTextureFromSurface(renderer, imageTmp);
SDL_FreeSurface(imageTmp);
if (!chargerNiveau(carte))
exit(EXIT_FAILURE);
while (continuer) {
SDL_WaitEvent(&event);
switch(event.type)
{
case SDL_QUIT:
continuer = 0;
break;
case SDL_MOUSEBUTTONDOWN:
if (event.button.button == SDL_BUTTON_LEFT)
{
// On met l'objet actuellement choisi (mur, caisse...) à l'endroit du clic
carte[event.button.x / TAILLE_BLOC][event.button.y / TAILLE_BLOC] = objetActuel;
clicGaucheEnCours = 1; // On retient qu'un bouton est enfoncé
}
else if (event.button.button == SDL_BUTTON_RIGHT) // Clic droit pour effacer
{
carte[event.button.x / TAILLE_BLOC][event.button.y /TAILLE_BLOC] = VIDE;
clicDroitEnCours = 1;
}
break;
case SDL_MOUSEBUTTONUP: // On dÈsactive le boolÈen qui disait qu'un bouton Ètait enfoncÈ
if (event.button.button == SDL_BUTTON_LEFT)
clicGaucheEnCours = 0;
else if (event.button.button == SDL_BUTTON_RIGHT)
clicDroitEnCours = 0;
break;
case SDL_MOUSEMOTION:
if (clicGaucheEnCours) // Si on dÈplace la souris et que le bouton gauche de la souris est enfoncÈ
{
carte[event.motion.x / TAILLE_BLOC][event.motion.y / TAILLE_BLOC] = objetActuel;
}
else if (clicDroitEnCours) // Pareil pour le bouton droit de la souris
{
carte[event.motion.x / TAILLE_BLOC][event.motion.y / TAILLE_BLOC] = VIDE;
}
break;
case SDL_KEYDOWN:
switch(event.key.keysym.sym)
{
case SDLK_ESCAPE:
continuer = 0;
break;
case SDLK_s:
sauvegarderNiveau(carte);
break;
case SDLK_c:
chargerNiveau(carte);
break;
case SDLK_1:
objetActuel = MUR;
printf("Mur");
break;
case SDLK_2:
objetActuel = CAISSE;
break;
case SDLK_3:
objetActuel = OBJECTIF;
break;
case SDLK_4:
objetActuel = MARIO;
break;
}
break;
}
// Effacement de l'écran
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); // Selection couleur
SDL_RenderClear(renderer); // Peigner TOUT le renderer avec la couleur
// Placement des objets à l'écran
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_SetRenderTarget(renderer, NULL);
SDL_RenderCopy(renderer, mur, NULL, &position);
printf("pose");
break;
case CAISSE:
SDL_SetRenderTarget(renderer, NULL);
SDL_RenderCopy(renderer, caisse, NULL, &position);
break;
case OBJECTIF:
SDL_SetRenderTarget(renderer, NULL);
SDL_RenderCopy(renderer, objectif, NULL, &position);
break;
case MARIO:
SDL_SetRenderTarget(renderer, NULL);
SDL_RenderCopy(renderer, mario, NULL, &position);
break;
}
}
}
// Mise à jour de l'écran
SDL_RenderPresent(renderer); // Mise à jour du renderer
}
SDL_DestroyTexture(mur);
SDL_DestroyTexture(caisse);
SDL_DestroyTexture(objectif);
SDL_DestroyTexture(mario);
}
fichiers.c
#include "fichiers.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("/Users/Mickahell/Documents/Xcode/C/sokoban/sokoban/niveaux.txt", "r");
if (fichier == NULL){
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("/Users/Mickahell/Documents/Xcode/C/sokoban/sokoban/niveaux.txt", "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]);
}
}
fclose(fichier);
return 1;
}
Tu devrais commencer par tester si tes images se chargent (verifier que imagetmp ne soit pas NULL).
Ensuite, ta fonction chargerNiveau() n'est pas correcte: d'abord si fichier est NULL, alors on ne sait pas le lire et il faut renvoyer 0, et si le fichier !=NULL, où vois-tu une instruction qui lit qqchose dans ton fichier ?
- Edité par edgarjacobs 20 mai 2018 à 18:34:58
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
où vois-tu une instruction qui lit qqchose dans ton fichier ?
Car, vouip, le fichier est bien ouvert, mais tu n'y lis rien. Alors ce qui se passe: comme tu as initialisé lignefichier avec tous des zéros, ben tu passes NB_BLOCS_LARGEUR * NB_BLOCS_HAUTEUR fois par le case '0'. Donc ta variable niveau est remplie de zéros.
Au fait, au sujet de ce switch, je vais te refiler un truc: tu peux l'éviter si tu écris niveau[i][j]=ligneFichier[....]-'0';
.
- Edité par edgarjacobs 20 mai 2018 à 19:41:03
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
Au fait, au sujet de ce switch, je vais te refiler un truc: tu peux l'éviter si tu écris niveau[i][j]=ligneFichier[....]-'0';
T'aurais un exemple de comment l'utiliser à la place de mon switch, là je te ne suis pas ...
Tu remarqueras qu'avec ton switch, tu transformes '0' en 0, '1' en 1, '2' en 2, etc. Donc les lignes 17 à 34 (incluses) peuvent être remplacées par niveau[i][j]=lignefichier[....]-'0'; : '0' - '0' → 0, '1' - '0' → 1, '2' - '0' → 2, etc.
- Edité par edgarjacobs 22 mai 2018 à 22:28:02
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
[SDL2] Mario Sokoban
× 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.
©Mickahell
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
©Mickahell
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent
©Mickahell
On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent