Bon alrs c'est un tétris tout simple. C'est mon premier programme en C/C++, je me suis basé sur les sources du PinkTetris de Hylvenir (
http://www.cppfrance.com/codes/PINKTRIS-SIMPLE-TETRIS-SDL_25010.aspx)
J'ai totalement refais le jeu. Refais la gestion d'une partie, des scores, des blocs. J'ai mis des variables un peu partout dans le codes pour pouvoir plus simplement modifié le code.
Une version 2 est en préparation dans laquelle vous pourrez changer plusieurs options du jeu ; par exemple, les blocs, le nombre de lignes pour changer de niveau, la taille du plateau de jeu.
Dans cette version, je distribuerais également les sources qui cette fois seront intégralement commentées.
-------------------------------------------------------
19/08/2007 16h00
Tetris V2.0 Par Thierry POINOT
Sources initiales du PinkTetris de Hylvenir sur
http://www.cppfrance.com :
http://www.cppfrance.com/codes/PINKTRIS-SIMPLE-TETRIS-SDL_25010.aspx
Ce programme à été développé en C++ avec Dev-cpp. Il utilise les librairie SDL (pour l'affichage) et SDL_TTF pour l'affichage de texte (genre les scores), ainsi que la librairie FMOD pour la gestion du son.
Et voilà la version 2 de mon Tétris ! Une interface remanié, les bloc sont, à mon goût, d'une plus jolie couleur (dégradé blanc) que dans la version 1.
Les sons ont été changés : il n'y a plus de son pour les déplacements latéraux de blocs.
Un bug de fin de partie à été corrigé; lorsqu'une partie était perdu, et que le jeu était figé, à chaque fois que l'utilisateur faisait une action sur la fenêtre, le son de fin de partie se répétait.
Désormais, il est possible de jouer avec ses propres blocs !
Le fichier 'blocs.txt' contient les blocs du jeu, et le fichier 'special_blocs.txt' contient les blocs pour généré les bordures et le fond coloré ^^
Il y a également un fichier de configuration 'options.txt' qui contient les principales variable du jeu pour personnalisé votre tétris (taille de la zone de jeu, nombre de ligne pour monter d'un niveau...)
Si les fichiers de configuration n'existe pas, ce n'est pas un problème, les options par défaut du programme seront utilisé.
Il y a aussi l'affichage du meilleur score sur le plateau de jeu pour vous situer par rapport au meilleur !
Bref cette version est plus personnalisable, plus intéractive, vous pouvez jouez avec les blocs que vous voulez, ce qui donne une nouvelle dimension au jeu !
A VENIR, une version 3 j'espère bien ! avec des blocs plus que spécial qui auront une action spéciale sur le jeu ! Par exemple le bloc point '.' pourra bouché les trous dans votre jeu et compléter les lignes que vous avez raté !
J'espère bien faire aussi un tableau de score, et crypter les score pour éviter la triche, qui donnera un esprit de compétition au jeu.
Je prévois dans une version supérieur de faire un éditeur de blocs et de niveau ! comme au snake, après chaque niveau possèdera des murs impossible à enlever, qu'il faudra contourner !
Je prévois également de faire en sorte d'envoyer les score sur le net pour un classement général du jeu, ce qui me permettra avec cette fonctionnalité d'ouvrir un site web.
Bref tout ça ne sont que des prévisions et des idées, je ne garantit rien mais bon....
Je remercie encore une fois Hylvenir pour sa source initiale, et Funto qui m'a fait découvrir la lib <vector> tableau multidimensionnel redimensionnable.
http://thierry.poinot.fr/
http://dev.thierry.poinot.fr/
P.S. : regarder les touches du pavé numérique ya un ptit truc nul certes mais marrant, c'était juste pour déconner :P
Source / Exemple :
########TETRIS.CPP########
#include "tetris.h"
// Fonction principale ----------------------------------------------------------------------------------------------------
int main( int, char** ) try
{
srand( time(NULL) ); // Randomize
// Initialise l'affichage (librairie SDL)
if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER )== -1 )
throw runtime_error( SDL_GetError() );
// initialise la librairie qui gère le son (Fmod)
if ( FSOUND_Init(44100, 32, 0) == -1 )
throw runtime_error( "FMOD n'a pas pu s'initialiser" );
// initialise la librairie qui gère l'affichage de texte
if ( TTF_Init() == -1 ) // si la lib ne s'initialise pas...
throw runtime_error( TTF_GetError() ); // on arrête le programme en renvoyant l'erreur
init_options(); // appel de la fonction qui initialise toutes les variables du jeu
police = TTF_OpenFont("fonts/courbd.ttf", tetris.case_unit - 4); // on charge la police (le fichier doit obligatoirement exister !!)
if (!police) // si il y a une erreur dans le chargement de la police...
throw runtime_error( TTF_GetError() ); // on arrête le programme en renvoyant l'erreur
police_m = TTF_OpenFont("fonts/courbd.ttf", 15); // on charge la police (ici la taille est plus petite) (le fichier doit obligatoirement exister !!)
/* jouer un son court avec FMOD
FSOUND_SAMPLE *grudge = NULL;
grudge = FSOUND_Sample_Load(FSOUND_FREE, "sounds/the grudge.mp3", 0, 0, 0);
FSOUND_PlaySound(FSOUND_FREE, grudge);
//*/
/* jouer un son long (musique) avec FMOD
FSOUND_STREAM *musique = NULL;
FSOUND_Stream_SetLoopCount(musique, -1); // répétition à l'infini
//musique = FSOUND_Stream_Open("musics/Gabry Ponte Dance - Tetris RMX.MP3", FSOUND_LOOP_NORMAL, 110000, 219500); // on charge la musique
musique = FSOUND_Stream_Open("musics/Gabry Ponte Dance - Tetris RMX.MP3", FSOUND_LOOP_NORMAL, 5 * 109500, 20 * 219500); // on charge la musique
//FSOUND_Stream_Play(FSOUND_FREE, musique); // on lit la musique
//FSOUND_Stream_Stop(musique); // Arrêt de la musique
//FSOUND_Stream_Close(musique); // On libère la mémoire (décharge la musique de la mémoire)
//*/
/* Faire une pause avec FMOD
// remplacer FSOUND_ALL par le numéro du canal à mettre en pause
if (FSOUND_GetPaused(0)) // Si le canal 0 est en pause
FSOUND_SetPaused(FSOUND_ALL, 0); // On enlève la pause de tous les canaux
else // Sinon, elle est en cours de lecture
FSOUND_SetPaused(FSOUND_ALL, 1); // On met en pause tous les canaux
//*/
/* jouer un midi
FMUSIC_MODULE *musique = NULL;
musique = FMUSIC_LoadSong("musics/tetris.mid");
FMUSIC_SetLooping(musique, 1); // répétition à l'infini
FMUSIC_PlaySong(musique);
FMUSIC_SetMasterVolume(musique, 120); // volume
//FMUSIC_StopSong(musique); // stopper la lecture du midi
//FMUSIC_FreeSong(musique); // on libère la mémoire (décharge le midi de la mémoire)
//*/
/* mettre en pause un midi
if (FMUSIC_GetPaused(musique)) // Si la chanson est en pause
FMUSIC_SetPaused(musique, 0); // On enlève la pause
else // Sinon, elle est en cours de lecture
FMUSIC_SetPaused(musique, 1); // On active la pause
//*/
FSOUND_SetVolume(FSOUND_ALL, 255); // change le volume de tous les canaux ( de 0 à 255)
screen = SDL_SetVideoMode( tetris.board_width + tetris.right_panel_width + tetris.grid_width, tetris.board_height + (tetris.case_unit + tetris.grid_width) + tetris.grid_width, 32, /*SDL_FULLSCREEN | */SDL_HWSURFACE | SDL_DOUBLEBUF ); // création de la fenêtre
if ( !screen ) // Si il y a une erreur sur la création de la fenêtre... on envoie un runtime error (erreur d'éxécution)
throw runtime_error( SDL_GetError() );
SDL_EnableKeyRepeat(500,30); // active la répétition des touches du clavier (rester appuyer pour faire plusieurs fois la même action)
init_colors(screen); // on initialise les couleurs
init_blocs(); // on initialise les blocs
SDL_WM_SetCaption( tetris.window_title, 0 ); // Attribut le titre de la fenêtre (voir 'init_options()')
SDL_WM_SetIcon( SDL_LoadBMP( "icon.bmp" ), 0 ); // Chargement de l'icône de la fenêtre
init_window_style();
new_game();
SDL_Event event;
//while( SDL_PollEvent( &event ) )
while( SDL_WaitEvent( &event ) )
{
switch( event.type )
{
case SDL_KEYDOWN:
switch( event.key.keysym.sym )
{
// -- MOUVEMENT --
case SDLK_RIGHT:
userMode = goRight; // déplacement du bloc à droite
break;
case SDLK_LEFT:
userMode = goLeft; // déplacement du bloc à gauche
break;
case SDLK_DOWN:
userMode = goDown; // déplacement du bloc en bas
break;
case SDLK_UP:
//userMode = goUp; break;
//FSOUND_PlaySound(FSOUND_FREE, tetris.bloc_is_fixed); break; // on joue le son qui correspond au fait que le joueur souhaite faire descendre le bloc
case SDLK_KP0:
userMode = turnRight; // rotation du bloc
break;
//* SONS BONUS !!!!
case SDLK_KP1:
FSOUND_PlaySound(FSOUND_FREE, tetris.sound_one);
break;
case SDLK_KP2:
FSOUND_PlaySound(FSOUND_FREE, tetris.sound_two);
break;
case SDLK_KP3:
FSOUND_PlaySound(FSOUND_FREE, tetris.sound_three);
break;
case SDLK_KP4:
FSOUND_PlaySound(FSOUND_FREE, tetris.sound_go);
break;
case SDLK_RCTRL:
// remplacer FSOUND_ALL par le numéro du canal à mettre en pause
if (FSOUND_GetPaused(0)) // Si le canal 0 est en pause
FSOUND_SetPaused(FSOUND_ALL, 0); // On enlève la pause de tous les canaux
else // Sinon, elle est en cours de lecture
FSOUND_SetPaused(FSOUND_ALL, 1); // On met en pause tous les canaux
FSOUND_Stream_Play(FSOUND_FREE, tetris.musique);
break;
case SDLK_RSHIFT:
FSOUND_Stream_Stop(tetris.musique); // Arrêt de la musique
FSOUND_SetPaused(FSOUND_ALL, 1); // On met la pause
break;
//*/
case SDLK_F2: new_game(); break;
// -- PAUSE --
case SDLK_SPACE:
case SDLK_p: pause = !pause; break;
// -- EXIT --
case SDLK_ESCAPE: userMode = quit; break;
}
break;
case SDL_KEYUP: userMode = none; break;
case SDL_QUIT: userMode = quit; continue;
}
if ( pause )
{
update_surface(screen); // Mise à jour de l'écran
continue;
}
MoveBloc( userMode );
update_game();
}
quit_game();
return 0;
}
catch( exception& e )
{
ofstream cerr( "program_error.txt" );
cerr << e.what();
return 1;
}
// Fonction d'initialisation des variables principales du jeu ----------------------------------------------------------------------------------------------------
void init_options()
{
tetris.case_unit = 25; // la longueur en pixel du côté du carré qui forme une tuile (la tuile est ce qui compose un bloc ce sont les cases unitaires...)
tetris.board_size_x = 10 + 2; // la largeur de la matrice (zone de jeu) en 'case_unit' + les 2 côtés qui forment les bords (droit et gauche)
tetris.board_size_y = 22 + 1; // la hauteur de la matrice en 'case_unit' + le bas de la zone de jeu (le sol)
tetris.grid_width = 1; // la largeur en pixel de la grille, du cadrillage
tetris.line_number_to_level_up = 10; // nombre de lignes à compléter pour monter d'un niveau (mettez la valeur que vous souhaitez, la valeur officielle est 10 lignes pour monter d'un niveau, mais si vous souhaitez que vos parties durent plus longtemps mettez 20)
//* chargement des options dans le fichier de configuration
ifstream fichier;
fichier.open("options.txt", ios::in);
if(fichier)
{
fichier >> tetris.case_unit >> tetris.board_size_x >> tetris.board_size_y >> tetris.grid_width >> tetris.line_number_to_level_up;
/*
vector <string> file_content; // variable qui contiendra le fichier (tableau avec une ligne par entrée du tableau)
string ligne;
while(getline(fichier, ligne)) {
file_content.push_back( ligne );
}
//*/
}
else
{
throw runtime_error( "Impossible d'ouvrir le fichier de configuration !" );
cout << "Impossible d'ouvrir le fichier de configuration !" << endl;
}
fichier.close();
//*/
tetris.init_posY = 0; // position initiale d'un nouveau bloc (ordonnée)
tetris.init_posX = (tetris.board_size_x - 2) / 2; // position initiale d'un nouveau bloc (abscisse) : ici un bloc nouveau apparaîtra toujours centré dans la zone de jeu (-2 pour les bordures de droite et gauche)
tetris.bloc_number = 0; // initialise le nombre de blocs (laissé à 0 car cette variable est automatiquement incrémenté lors de l'ajout de bloc avec la fonction 'add_bloc()')
tetris.special_bloc_number = 0; // initialise le nombre de blocs spéciaux (laissé à 0 car cette variable est automatiquement incrémenté lors de l'ajout de bloc avec la fonction 'add_special_bloc()')
tetris.board_width = tetris.board_size_x * (tetris.case_unit + tetris.grid_width); // calcul de la largeur de la matrice en pixel
tetris.board_height = tetris.board_size_y * (tetris.case_unit + tetris.grid_width); // calcul de la hauteur de la matrice en pixel
tetris.right_panel_width = (tetris.case_unit + tetris.grid_width) * 10; // taille de la zone à droite de la matrice en pixel (ici la zone fait 10 tuiles de largeur)
tetris.next_bloc_preview_x = tetris.board_width; // abscisse du coin supérieur gauche de la zone d'aperçu du bloc suivant (ici, c'est juste à côté de la matrice)
tetris.next_bloc_preview_y = 0; // ordonée du coin supérieur gauche de la zone d'aperçu du bloc suivant (ici, c'est tout en haut)
tetris.next_bloc_preview_size_x = 5; // largeur en 'case_unit' de la zone d'aperçu du bloc suivant
tetris.next_bloc_preview_size_y = 5; // hauteur en 'case_unit' de la zone d'aperçu du bloc suivant
tetris.next_bloc_preview_width = tetris.next_bloc_preview_size_x * (tetris.case_unit + tetris.grid_width); // largeur en pixel de la zone d'aperçu du bloc suivant
tetris.next_bloc_preview_height = tetris.next_bloc_preview_size_y * (tetris.case_unit + tetris.grid_width); // hauteur en pixel de la zone d'aperçu du bloc suivant
tetris.window_title = "* Tetris V2 * ...du 18/08/2007 15h45..."; // titre de la fenêtre
tetris.musique = FSOUND_Stream_Open("musics/Gabry Ponte Dance - Tetris RMX.MP3", FSOUND_LOOP_NORMAL, 5 * 109500, 20 * 219500); // on charge la musique
FSOUND_Stream_SetLoopCount(tetris.musique, 0); // répétition à l'infini
FSOUND_SetPaused(FSOUND_ALL, 1); // On met la pause
tetris.sound_bloc_rotate_right = FSOUND_Sample_Load(FSOUND_FREE, "sounds/user_rotate_bloc_at_right.sound", 0, 0, 0);
tetris.sound_bloc_rotate_left = FSOUND_Sample_Load(FSOUND_FREE, "sounds/user_rotate_bloc_at_left.sound", 0, 0, 0);
tetris.sound_bloc_go_right_user = FSOUND_Sample_Load(FSOUND_FREE, "sounds/user_move_bloc_at_right.sound", 0, 0, 0);
tetris.sound_bloc_go_left_user = FSOUND_Sample_Load(FSOUND_FREE, "sounds/user_move_bloc_at_left.sound", 0, 0, 0);
tetris.sound_bloc_go_down_user = FSOUND_Sample_Load(FSOUND_FREE, "sounds/when_bloc_go_down_by_user.sound", 0, 0, 0);
tetris.sound_bloc_go_up_user = FSOUND_Sample_Load(FSOUND_FREE, "sounds/when_bloc_go_up_by_user.sound", 0, 0, 0);
tetris.sound_bloc_go_down = FSOUND_Sample_Load(FSOUND_FREE, "sounds/when_bloc_go_down_auto.sound", 0, 0, 0);
tetris.sound_bloc_go_up = FSOUND_Sample_Load(FSOUND_FREE, "sounds/when_bloc_go_up_auto.sound", 0, 0, 0);
tetris.sound_bloc_is_fixed = FSOUND_Sample_Load(FSOUND_FREE, "sounds/when_bloc_is_fixed_on_the_floor.sound", 0, 0, 0);
tetris.sound_line_completed = FSOUND_Sample_Load(FSOUND_FREE, "sounds/when_line_is_completed.sound", 0, 0, 0);
tetris.sound_level_up = FSOUND_Sample_Load(FSOUND_FREE, "sounds/level_up.sound", 0, 0, 0);
tetris.sound_loose_game = FSOUND_Sample_Load(FSOUND_FREE, "sounds/loose_game.sound", 0, 0, 0);
tetris.sound_new_game = FSOUND_Sample_Load(FSOUND_FREE, "sounds/new_game.sound", 0, 0, 0);
//* Sons bonus (3...2...1...GO)
tetris.sound_three = FSOUND_Sample_Load(FSOUND_FREE, "sounds/three.ogg", 0, 0, 0);
tetris.sound_two = FSOUND_Sample_Load(FSOUND_FREE, "sounds/two.ogg", 0, 0, 0);
tetris.sound_one = FSOUND_Sample_Load(FSOUND_FREE, "sounds/one.ogg", 0, 0, 0);
tetris.sound_go = FSOUND_Sample_Load(FSOUND_FREE, "sounds/go.ogg", 0, 0, 0);
//*/
}
// Fonction d'initialisation des couleurs du jeu ----------------------------------------------------------------------------------------------------
void init_colors (SDL_Surface* screen)
{
tetris.bloc_border_color = SDL_MapRGB(screen->format, 0, 0, 0); // couleur de bordure d'un bloc (a utilisé uniquement sans la génération automatique du dégradé sur les bloc : voir code commenté dans la fonction addBloc)
tetris.background_color = SDL_MapRGB(screen->format, 212, 208, 200); // On créé une variable qui contient la couleur du background (fond d'écran) en format RGB ou RVB (Rouge, Vert, Bleu)
tetris.matrice_color = SDL_MapRGB(screen->format, 255, 255, 255); // On créé une variable qui contient la couleur du background (fond d'écran) en format RGB ou RVB (Rouge, Vert, Bleu)
tetris.grid_color = SDL_MapRGB(screen->format, 150, 150, 150); // On créé une variable qui contient la couleur du background (fond d'écran) en format RGB ou RVB (Rouge, Vert, Bleu)
}
// Fonction d'initialisation des blocs utilisant la fonction addBloc ----------------------------------------------------------------------------------------------------
void init_blocs ()
{
if (!get_blocs_by_file(true)) { // Si l'initialisation par fichier de configuration a échouée, on créé les blocs
//*
add_special_bloc( 1, "1", 50, 50, 50 ); // bloc unitaire pour les bordures (tétrion)
//* blocs unitaires pour le fond aléatoire
add_special_bloc( 1, "1", 255, 0, 0 );
add_special_bloc( 1, "1", 51, 102, 255 );
add_special_bloc( 1, "1", 255, 220, 0 );
add_special_bloc( 1, "1", 255, 0, 255 );
add_special_bloc( 1, "1", 210, 210, 200 );
add_special_bloc( 1, "1", 0, 255, 0 );
add_special_bloc( 1, "1", 0, 0, 255 );
/*
for (int x = 0; x < 50; x++) // ajout de 50 blocs spéciaux unitaires dont la couleur est aléatoire
add_special_bloc( 1, "1" );
//*/
//*/
}
if (!get_blocs_by_file()) { // Si l'initialisation par fichier de configuration a échouée, on créé les blocs
//*
//* Blocs originaux
add_bloc( 4, "0010001000100010", 255, 0, 0 ); // barre I
add_bloc( 2, "1111", 51, 102, 255 ); // carré O
add_bloc( 3, "010111000", 153, 51, 0 ); // T
add_bloc( 3, "001111000", 255, 0, 255 ); // L
add_bloc( 3, "100111000", 200, 200, 200 ); // J couleur originale : le blanc
add_bloc( 3, "100110010", 0, 255, 0 ); // S
add_bloc( 3, "001011010", 0, 204, 255 ); // Z
//*/
/* blocs du tétris B
add_bloc( 1, "1"); // le point .
add_bloc( 2, "1011", 255, 220, 0 ); // mini L
//add_bloc( 3, "111010010" ); // T (grand)
//add_bloc( 3, "010111010" ); // +
add_bloc( 3, "010010010" ); // la barre de 3
add_bloc( 2, "0101" ); // la barre de 2
add_bloc( 3, "101111000" ); // la cuvette de 3
//*/
//*/
}
}
// Fonction appelée lors d'une nouvelle partie ----------------------------------------------------------------------------------------------------
void new_game()
{
if (game == true) // Si il y a une partie en cours...
end_game(); // on termine la partie
pause = false; // On enlève la pause au cas où elle serait activée
init_window_style(); // on réinitialise l'affichage de la fenêtre pour afficher un nouveau fond aléatoire
FSOUND_PlaySound(FSOUND_FREE, tetris.sound_new_game); // on joue le son qui correspond à une nouvelle partie
//* chargement du score maximal
ifstream scoreFile( "score.txt" ); // on ouvre le fichier qui contient le record
if ( scoreFile ) // si le fichier existe...
scoreFile >> scoreMax >> lineMax; // on met la première ligne du fichier comme score max et la deuxième ligne du fichier comme nombre de lignes max
//*/
board.init_board(); // Initialise le tableau de jeu (objet voir 'board.h')
currentBloc = blocs[ rand() % tetris.bloc_number ]; // On sélectionne un bloc au hasard pour le bloc courant
nextBloc = blocs[ rand() % tetris.bloc_number ]; // On sélectionne un bloc au hasard pour le prochain bloc
tetris.posX = tetris.init_posX; // On initialise la position du bloc à sa position initiale (abscisse)
tetris.posY = tetris.init_posY; // On initialise la position du bloc à sa position initiale (ordonnée)
tetris.score = 0; // initialise le score à 0 (laisser à 0 sinon vous triché :P)
tetris.lines = 0; // initialise le nombre de lignes complétées (laisser à 0, changer la valeur n'a aucune influence sur le score, c'est juste indicatif)
tetris.level = 1; // initialise le niveau on commence au niveau 1 et pas 0 sinon les blocs ne descendent pas ^^ (augmenter le niveau de départ d'une partie influe sur la vitesse de descente du bloc)
game = true; // On met true à la variable qui dit qu'une partie est en cours
SDL_Delay( 500 ); // On met en pause le programme pour une demie seconde pour donner le temps au joueur de se mettre en place (utile pour ceux qui ne connaissent pas par coeur le clavier :P)
//* On créé le timer pour la descente automatique du bloc
GAMES_MODE tmp = goDown;
timer_MoveBloc_auto = SDL_AddTimer(1000 / tetris.level, MoveBloc_auto, &tmp); // Démarrage du Timer
//*/
}
// Fonction appelée à la fin d'une partie ----------------------------------------------------------------------------------------------------
void end_game(bool loose_game)
{
//* Sauvegarde les informations de la dernière partie (un genre de log)
ofstream cout( "last_game.txt");
time_t ltime;
struct tm *today;
time( <ime );
today = localtime( <ime );
char tmpbuf[128];
strftime(tmpbuf, 128, "%A %d %B %Y à %H:%M:%S", today);
cout << "----------------------------------------------------------------------------------------------------" << endl;
cout << "Partie terminée le " << tmpbuf << endl;
cout << "Score : " << tetris.score << endl;
cout << "Lignes : " << tetris.lines << endl;
cout << "Niveau : " << tetris.level << endl;
//*/
//* Sauvegarde du score maximal (meilleur score)
if (tetris.score > scoreMax) { // Si le score de la partie est supérieur au score maximum atteint...
ofstream scoreFile( "score.txt" );
scoreFile << tetris.score << endl << tetris.lines; // on sauvegarde le score actuel et son nombre de lignes
}
//*/
if (loose_game == true) // si la partie est terminé parce que le joueur vient de perdre...
FSOUND_PlaySound(FSOUND_FREE, tetris.sound_loose_game); // on joue le son qui correspond à la perte de la partie
SDL_RemoveTimer(timer_MoveBloc_auto); // Arrêt du Timer qui fait la descente automatique du bloc
game = false;
}
int update_game()
{
draw_surface( matrice, 0, 0, matrice->w, matrice->h, background, tetris.case_unit + tetris.grid_width, tetris.case_unit + tetris.grid_width ); // Effacement de l'écran
//SDL_BlitSurface( background, 0, screen, 0 ); // Effacement de l'écran
//update_surface(background);
//update_surface(matrice);
draw_surface(background, 0, 0, background->w, background->h, screen, 0, 0);
board.display( screen ); // Affichage du fond d'écran
currentBloc.display( screen, tetris.posX, tetris.posY ); // Affichage de la pièce courante
nextBloc.display( screen, tetris.next_bloc_preview_x / (tetris.case_unit + tetris.grid_width), tetris.next_bloc_preview_y / (tetris.case_unit + tetris.grid_width)); // Affichage de la prochaine pièce
// Affichage du niveau
char level_str[100];
sprintf(level_str, "Niveau = %d", tetris.level);
show_text(level_str, police, screen, tetris.board_width + tetris.grid_width, (tetris.next_bloc_preview_size_y + 1 + 1) * (tetris.case_unit + tetris.grid_width), 0, 0, 0);
// Affichage du score
char score_str[100];
sprintf(score_str, "Score = %d", tetris.score);
show_text(score_str, police, screen, tetris.board_width + tetris.grid_width, (tetris.next_bloc_preview_size_y + 1 + 2) * (tetris.case_unit + tetris.grid_width), 0, 0, 0);
// Affichage des lignes
char lines_str[100];
sprintf(lines_str, "Lignes = %d", tetris.lines);
show_text(lines_str, police, screen, tetris.board_width + tetris.grid_width, (tetris.next_bloc_preview_size_y + 1 + 3) * (tetris.case_unit + tetris.grid_width), 0, 0, 0);
show_text("F2 = Nouvelle partie", police_m, screen, tetris.board_width + tetris.grid_width, (tetris.next_bloc_preview_size_y + 1 + 4 + 1) * (tetris.case_unit + tetris.grid_width), 0, 0, 0);
show_text("Espace = Pause", police_m, screen, tetris.board_width + tetris.grid_width, (tetris.next_bloc_preview_size_y + 1 + 4 + 2) * (tetris.case_unit + tetris.grid_width), 0, 0, 0);
show_text("Echap = Quitter", police_m, screen, tetris.board_width + tetris.grid_width, (tetris.next_bloc_preview_size_y + 1 + 4 + 3) * (tetris.case_unit + tetris.grid_width), 0, 0, 0);
char highScore[100];
sprintf(highScore, "Meilleur score = %d", scoreMax);
show_text(highScore, police_m, screen, tetris.board_width + tetris.grid_width, (tetris.next_bloc_preview_size_y + 1 + 4 + 5) * (tetris.case_unit + tetris.grid_width), 0, 0, 0);
update_surface(screen); // Mise à jour de l'écran
if ( !board.isMouvementValid( tetris.posX, tetris.posY, currentBloc ) && game == true ) // partie terminée
end_game(true);
if (userMode == quit) {
quit_game();
return 0;
}
}
// Fonction d'ajout de bloc : Si les taux des trois couleurs Rouge Vert Bleu ne sont pas spécifié, il y a génération aléatoire du taux de chaque couleur : voir le prototype de la fonction addBloc dans 'tetris.h' ----------------------------------------------------------------------------------------------------
void add_bloc(int blocMaxWidth, string blocShape, int redRate, int greenRate, int blueRate)
{
redRate = (redRate > 255) ? (rand() % 256) : redRate;
greenRate = (greenRate > 255) ? (rand() % 256) : greenRate;
blueRate = (blueRate > 255) ? (rand() % 256) : blueRate;
blocs.push_back( Bloc( tetris.bloc_number, blocMaxWidth, blocShape.c_str(), redRate, greenRate, blueRate ) ); // ajout du bloc avec dégradé vers le noir
tetris.bloc_number++;
}
void add_special_bloc(int blocMaxWidth, string blocShape, int redRate, int greenRate, int blueRate)
{
redRate = (redRate > 255) ? (rand() % 256) : redRate;
greenRate = (greenRate > 255) ? (rand() % 256) : greenRate;
blueRate = (blueRate > 255) ? (rand() % 256) : blueRate;
special_blocs.push_back( Bloc( tetris.special_bloc_number, blocMaxWidth, blocShape.c_str(), redRate, greenRate, blueRate ) ); // ajout du bloc avec dégradé vers le noir
tetris.special_bloc_number++;
}
bool get_blocs_by_file (bool get_special_blocs)
{
//* chargement des blocs à partir du fichier
ifstream blocs_file;
if (!get_special_blocs)
blocs_file.open("blocs.txt", ios::in);
else
blocs_file.open("special_blocs.txt", ios::in);
int len, redRate, greenRate, blueRate;
string shape;
vector <string> file_content; // variable qui contiendra le fichier (tableau avec une ligne par entrée du tableau)
string ligne, tmp;
int i = 0, j = 0, last_pos = 0, num = 0;
bool no_error = false;
if(blocs_file)
{
while(getline(blocs_file, ligne)) {
no_error = false;
file_content.push_back( ligne );
num = 0;
last_pos = 0;
if (file_content[i].substr( 0, 2) != "//") {
for (j = 0; j < file_content[i].size(); j++) {
if (file_content[i].substr( j, 1 ) == ";") {
tmp = file_content[i].substr( last_pos, j - last_pos );
last_pos = j + 1;
num++;
switch (num) {
case 1:
len = atoi(tmp.c_str());
break;
case 2:
shape = tmp.c_str();
break;
case 3:
redRate = atoi(tmp.c_str());
break;
case 4:
greenRate = atoi(tmp.c_str());
break;
case 5:
blueRate = atoi(tmp.c_str());
no_error = true;
break;
}
}
}
if (no_error)
if (!get_special_blocs)
add_bloc( len, shape, redRate, greenRate, blueRate );
else
add_special_bloc( len, shape, redRate, greenRate, blueRate );
}
i++;
}
}
else
{
return false;
}
blocs_file.close();
return true;
//*/
}
void update_surface (SDL_Surface* surface)
{
SDL_UpdateRect( surface, 0, 0, surface->w, surface->h );
SDL_Flip(surface);
}
// Fonction d'affichage de surface sur une surface de destination ----------------------------------------------------------------------------------------------------
void draw_surface (SDL_Surface* src, int X_ori, int Y_ori, int srcWidth, int srcHeight, SDL_Surface* dest, int posX_onDest, int posY_onDest, Uint32 color)
{
// Les coordonnées de la surface sur la surface de destination
SDL_Rect srcPositionOnDestination; // définition de la variable
srcPositionOnDestination.x = posX_onDest; // abscisse
srcPositionOnDestination.y = posY_onDest; // ordonnée
SDL_Rect srcPosition;
srcPosition.x = X_ori;
srcPosition.y = Y_ori;
srcPosition.w = srcWidth;
srcPosition.h = srcHeight;
if (color != 0) {
SDL_FillRect(src, NULL, color); // Remplissage de la surface avec la couleur (color) passée en paramètre
}
SDL_BlitSurface(src, &srcPosition, dest, &srcPositionOnDestination); // Collage de la surface (src) sur la destination (dest)
// SDL_Flip(dest);
}
void init_window_style ()
{
int i = 0; // variables pour les boucles
// Chargement du fond d'écran
SDL_Surface* random_background = generate_random_bmp_tuiles(); // génération aléatoire d'une image remplie de tuiles (special_blocs)
background = SDL_CreateRGBSurface(SDL_HWSURFACE, screen->w, screen->h, 32, 0, 0, 0, 0); // On créé une surface nommée background
SDL_FillRect(background, NULL, tetris.background_color); // Remplissage de la surface avec la couleur (color) passée en paramètre
draw_surface(random_background, 0, 0, random_background->w, random_background->h, background, 0, 0); // On dessine le background sur la fenêtre (screen)
//background = SDL_LoadBMP( "alea.bmp" ); // On charge une image de fond d'écran
draw_surface(background, 0, 0, background->w, background->h, screen, 0, 0); // On dessine le background sur la fenêtre (screen)
if ( !background ) // Si il y a une erreur sur la création du background... on envoie un runtime error (erreur d'éxécution)
throw runtime_error( SDL_GetError() );
// Chargement de la matrice (zone de jeu)
matrice = SDL_CreateRGBSurface(SDL_HWSURFACE, tetris.board_width - (2 * tetris.case_unit) - tetris.grid_width, tetris.board_height - tetris.case_unit, 32, 0, 0, 0, 0); // On créé une surface pour la matrice
draw_surface(matrice, 0, 0, matrice->w, matrice->h, background, tetris.case_unit + tetris.grid_width, tetris.case_unit + tetris.grid_width, tetris.matrice_color); // On dessine la matrice sur le fond d'écran
if ( !matrice )
throw runtime_error( SDL_GetError() );
//*/
//* Chargement du cadrillage
int numberLineY = tetris.board_size_y, numberLineX = tetris.board_size_y;
grid = SDL_CreateRGBSurface(SDL_HWSURFACE, matrice->w, matrice->h, 32, 0, 0, 0, 0); // On créé une surface pour la grille (grid)
SDL_FillRect(grid, NULL, tetris.matrice_color); // on remet la couleur de la matrice comme couleur de fond
SDL_Surface* gridX[numberLineX];
for (i = 0; i < numberLineX; i++) {
gridX[i] = SDL_CreateRGBSurface(SDL_HWSURFACE, numberLineX * (tetris.case_unit + tetris.grid_width), tetris.grid_width, 32, 0, 0, 0, 0); // On créé une surface pour la ligne
draw_surface(gridX[i], 0, 0, gridX[i]->w, gridX[i]->h, grid, 0, i*(tetris.case_unit + tetris.grid_width), tetris.grid_color); // On dessine la ligne (gridX[i]) sur la grille (grid)
if ( !gridX[i] )
throw runtime_error( SDL_GetError() );
}
SDL_Surface* gridY[numberLineY];
for (i = 0; i < numberLineY; i++) {
gridY[i] = SDL_CreateRGBSurface(SDL_HWSURFACE, tetris.grid_width, numberLineY * (tetris.case_unit + tetris.grid_width), 32, 0, 0, 0, 0); // On créé une surface pour la ligne
draw_surface(gridY[i], 0, 0, gridY[i]->w, gridY[i]->h, grid, i*(tetris.case_unit + tetris.grid_width), 0, tetris.grid_color); // On dessine la ligne (gridY[i]) sur la grille (grid)
if ( !gridY[i] )
throw runtime_error( SDL_GetError() );
}
draw_surface(grid, 0, 0, grid->w, grid->h, matrice, 0, 0);
//*/
//* Chargement du fond de la zone d'aperçu du bloc suivant
previewBloc = SDL_CreateRGBSurface(SDL_HWSURFACE, tetris.next_bloc_preview_width + tetris.grid_width, tetris.next_bloc_preview_height + tetris.grid_width, 32, 0, 0, 0, 0); // On créé une surface pour la grille (grid)
draw_surface(grid, 0, 0, grid->w, grid->h, previewBloc, 0, 0);
draw_surface(previewBloc, 0, 0, tetris.next_bloc_preview_width + tetris.grid_width, tetris.next_bloc_preview_height + tetris.grid_width, background, tetris.next_bloc_preview_x, tetris.next_bloc_preview_y + (tetris.case_unit + tetris.grid_width));
//*/
//* Chargement du tétrion (contour de la matrice)
for (i = 0; i < tetris.board_size_x; i++) {
draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width, tetris.grid_width);
draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width, tetris.board_height + tetris.grid_width);
}
for (i = 0; i < tetris.board_size_y; i++) {
draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, tetris.grid_width, i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width);
draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, tetris.board_width - tetris.case_unit, i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width);
}
//*/
//* Chargement du tétrion de la zone d'aperçu du bloc suivant
for (i = 0; i < tetris.next_bloc_preview_size_x; i++) {
draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, tetris.next_bloc_preview_x + i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width, tetris.next_bloc_preview_y + tetris.grid_width);
draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, tetris.next_bloc_preview_x + i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width, (tetris.next_bloc_preview_size_y + 1) * (tetris.case_unit + tetris.grid_width) + tetris.next_bloc_preview_y + tetris.grid_width);
}
for (i = 0; i < tetris.next_bloc_preview_size_y + 2; i++) { // + 2 pour le haut et le bas
draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, tetris.next_bloc_preview_x - tetris.case_unit, tetris.next_bloc_preview_y + i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width);
draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, tetris.next_bloc_preview_x + tetris.next_bloc_preview_width + tetris.grid_width, tetris.next_bloc_preview_y + i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width);
}
//*/
//* Chargement du tétrion de la zone d'affichage du score, des lignes et du niveau
for (i = 0; i < tetris.right_panel_width; i++) {
draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width + tetris.board_width, (tetris.next_bloc_preview_size_y + 1)*(tetris.case_unit + tetris.grid_width) + tetris.grid_width);
draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width + tetris.board_width, (tetris.next_bloc_preview_size_y + 1 + 4)*(tetris.case_unit + tetris.grid_width) + tetris.grid_width);
}
SDL_Surface* score_background = SDL_CreateRGBSurface(SDL_HWSURFACE, tetris.right_panel_width - tetris.grid_width, 3 * (tetris.case_unit + tetris.grid_width) - tetris.grid_width, 32, 0, 0, 0, 0); // On créé une surface pour la matrice
draw_surface( score_background, 0, 0, score_background->w, score_background->h, background, tetris.grid_width + tetris.board_width, (tetris.next_bloc_preview_size_y + 1 + 1)*(tetris.case_unit + tetris.grid_width) + tetris.grid_width, tetris.matrice_color);
//*/
//* Chargement du tétrion de la zone d'affichage des aides
for (i = 0; i < tetris.right_panel_width; i++) {
draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width + tetris.board_width, (tetris.next_bloc_preview_size_y + 1 + 4)*(tetris.case_unit + tetris.grid_width) + tetris.grid_width);
draw_surface( special_blocs[0].get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, background, i * (tetris.case_unit + tetris.grid_width) + tetris.grid_width + tetris.board_width, (tetris.next_bloc_preview_size_y + 1 + 4 + 6)*(tetris.case_unit + tetris.grid_width) + tetris.grid_width);
}
SDL_Surface* help_background = SDL_CreateRGBSurface(SDL_HWSURFACE, tetris.right_panel_width - tetris.grid_width, 5 * (tetris.case_unit + tetris.grid_width) - tetris.grid_width, 32, 0, 0, 0, 0); // On créé une surface pour la matrice
draw_surface( help_background, 0, 0, help_background->w, help_background->h, background, tetris.grid_width + tetris.board_width, (tetris.next_bloc_preview_size_y + 1 + 4 + 1)*(tetris.case_unit + tetris.grid_width) + tetris.grid_width, tetris.matrice_color);
//*/
}
void show_text (char* text, TTF_Font* font, SDL_Surface* dest, int posX, int posY, int redRate, int greenRate, int blueRate, int alpha)
{
SDL_Color color = {redRate, greenRate, blueRate};
SDL_Surface* text_surface = TTF_RenderText_Blended(font, text, color);
SDL_SetAlpha(text_surface, SDL_SRCALPHA, alpha); // Transparence Alpha
draw_surface(text_surface, 0, 0, text_surface->w, text_surface->h, dest, posX, posY);
}
SDL_Surface* generate_random_bmp_tuiles (bool saveBMP)
{
//* Génération d'un fond aléatoire pleins de tuiles avec les blocs spéciaux excepté le premier bloc spécial qui sert pour le tétrion
SDL_Surface* random_background = SDL_CreateRGBSurface(SDL_HWSURFACE, screen->w, screen->h, 32, 0, 0, 0, 0); // On créé une surface nommée background
int num_width = (screen->w / (tetris.case_unit + tetris.grid_width));
int num_height = (screen->h / (tetris.case_unit + tetris.grid_width));
Bloc bloc2;
for (int x = 0; x < num_width; x++) {
for (int y = 0; y < num_height; y++) {
bloc2 = special_blocs[ (rand() % (special_blocs.size() - 1)) + 1 ];
draw_surface( bloc2.get_tuile(), tetris.grid_width, tetris.grid_width, tetris.case_unit, tetris.case_unit, random_background, (x*(tetris.case_unit + tetris.grid_width)) + tetris.grid_width, (y*(tetris.case_unit + tetris.grid_width)) + tetris.grid_width);
}
}
if (saveBMP)
SDL_SaveBMP(random_background, "alea.bmp"); // on sauvegarde l'image créé pour le fun ;)
return random_background;
//*/
}
// Fonction d'arrêt du programme ----------------------------------------------------------------------------------------------------
void quit_game()
{
if (game == true) // Si il y a une partie en cours...
end_game(); // on termine la partie
// Libération des surfaces
SDL_FreeSurface( grid );
SDL_FreeSurface( matrice );
SDL_FreeSurface( background );
SDL_FreeSurface( screen );
FSOUND_Close(); // on arrête FMOD (librairie qui gère le son)
/*
TTF_CloseFont(police); // ferme la police chargée
TTF_CloseFont(police_m); // ferme la police chargée
TTF_Quit(); // arrêt de SDL_TTF
//*/
SDL_Quit(); // On arrête SDL (lib qui gère l'affichage)
}
Uint32 MoveBloc_auto( Uint32 intervalle, void *param )
{
if ( pause )
{
//SDL_BlitSurface( background, 0, screen, 0 ); // Effacement du plateau de jeu
//SDL_BlitSurface(grid, 0,
update_surface(screen); // Mise à jour de l'écran
return intervalle;
}
GAMES_MODE tmp = goDown;
MoveBloc(tmp);
update_game();
return intervalle;
}
void MoveBloc( GAMES_MODE& mode )
{
if (game == true) {
switch( mode )
{
case quit : break;
case goLeft:
FSOUND_PlaySound(FSOUND_FREE, tetris.sound_bloc_go_left_user); // on joue le son qui correspond au fait que le joueur souhaite déplacer le bloc à gauche
GoLeft();
break;
case goRight:
FSOUND_PlaySound(FSOUND_FREE, tetris.sound_bloc_go_right_user); // on joue le son qui correspond au fait que le joueur souhaite déplacer le bloc à droite
GoRight();
break;
case turnRight:
FSOUND_PlaySound(FSOUND_FREE, tetris.sound_bloc_rotate_right); // on joue le son qui correspond à la rotation du bloc
currentBloc.rotationRight();
break;
case turnLeft:
FSOUND_PlaySound(FSOUND_FREE, tetris.sound_bloc_rotate_right); // on joue le son qui correspond à la rotation du bloc
currentBloc.rotationLeft();
break;
case goDown:
FSOUND_PlaySound(FSOUND_FREE, tetris.sound_bloc_go_down_user); // on joue le son qui correspond au fait que le joueur souhaite faire descendre le bloc
GoDown();
break;
case goUp:
GoUp();
break;
}
if ( !board.isMouvementValid( tetris.posX, tetris.posY, currentBloc ) )
{
switch( mode )
{
case goLeft:
FSOUND_PlaySound(FSOUND_FREE, tetris.sound_bloc_go_left_user); // on joue le son qui correspond au fait que le joueur souhaite déplacer le bloc à gauche
GoRight();
break;
case goRight:
FSOUND_PlaySound(FSOUND_FREE, tetris.sound_bloc_go_right_user); // on joue le son qui correspond au fait que le joueur souhaite déplacer le bloc à droite
GoLeft();
break;
case turnRight:
FSOUND_PlaySound(FSOUND_FREE, tetris.sound_bloc_rotate_right); // on joue le son qui correspond à la rotation du bloc
currentBloc.rotationLeft();
userMode = none;
break;
case goDown:
GoUp();
board.addPiece( tetris.posX, tetris.posY, currentBloc );
currentBloc = nextBloc;
nextBloc = blocs[ rand() % blocs.size() ];
tetris.posY = tetris.init_posY;
tetris.posX = tetris.init_posX;
int result = board.reduce();
if (result == 2) {
SDL_RemoveTimer(timer_MoveBloc_auto); // Arrêt du Timer
GAMES_MODE tmp = goDown;
timer_MoveBloc_auto = SDL_AddTimer(1000 / tetris.level, MoveBloc_auto, &tmp); // Démarrage du Timer
FSOUND_PlaySound(FSOUND_FREE, tetris.sound_level_up); // on joue le son pour dire que le bloc à été posé
} else if (result == 1) {
FSOUND_PlaySound(FSOUND_FREE, tetris.sound_line_completed); // on joue le son pour dire que le bloc à été posé
} else if (result == 0 ) {
FSOUND_PlaySound(FSOUND_FREE, tetris.sound_bloc_is_fixed); // on joue le son pour dire que le bloc à été posé
}
userMode = none; // On arrête de descendre
// pour une nouvelle pièce
break;
}
}
}
if ( mode == turnRight ) userMode = none; // On évite de tourner en rond en continue
if ( mode == goLeft ) userMode = none;
if ( mode == goRight ) userMode = none;
if ( mode == goDown ) userMode = none;
}
########TETRIS.H########
#include <SDL/SDL.h> // librairie SDL qui gère l'affichage
#include <SDL/SDL_ttf.h> // librairie SDL_TTF qui gère l'affichage de texte
#include <FMOD/fmod.h> // librairie FMOD qui gère le son
#include <iostream>
#include <fstream>
#include <vector>
#include <stdexcept> // pour la gestion des erreurs
#include <stdlib.h>
#include <string>
using namespace std;
// ------------------- Déclarations des constantes (options du jeu)
struct options
{
int board_size_x;
int board_size_y;
int case_unit;
int board_width;
int board_height;
int grid_width;
int next_bloc_preview_x;
int next_bloc_preview_y;
int next_bloc_preview_size_x;
int next_bloc_preview_size_y;
int next_bloc_preview_width;
int next_bloc_preview_height;
int right_panel_width;
int bloc_border_width;
Uint32 bloc_border_color;
int bloc_number;
int special_bloc_number;
int window_width;
int window_height;
char* window_title;
int score;
int lines;
int line_number_to_level_up;
int level;
int init_posX;
int init_posY;
int posX;
int posY;
Uint32 background_color;
Uint32 matrice_color;
Uint32 tetrion_color;
Uint32 grid_color;
FSOUND_SAMPLE *sound_bloc_rotate_right;
FSOUND_SAMPLE *sound_bloc_rotate_left;
FSOUND_SAMPLE *sound_bloc_go_down;
FSOUND_SAMPLE *sound_bloc_go_down_user;
FSOUND_SAMPLE *sound_bloc_go_up_user;
FSOUND_SAMPLE *sound_bloc_go_up;
FSOUND_SAMPLE *sound_bloc_go_right_user;
FSOUND_SAMPLE *sound_bloc_go_left_user;
FSOUND_SAMPLE *sound_line_completed;
FSOUND_SAMPLE *sound_level_up;
FSOUND_SAMPLE *sound_loose_game;
FSOUND_SAMPLE *sound_new_game;
FSOUND_SAMPLE *sound_bloc_is_fixed;
FSOUND_SAMPLE *sound_three;
FSOUND_SAMPLE *sound_two;
FSOUND_SAMPLE *sound_one;
FSOUND_SAMPLE *sound_go;
FSOUND_STREAM *musique;
};
options tetris;
// -------------------
enum GAMES_MODE { none, quit, turnRight, turnLeft, goDown, goUp, goRight, goLeft };
GAMES_MODE userMode = none;
bool pause = false;
#include "bloc.h"
vector<Bloc> blocs;
vector<Bloc> special_blocs;
Bloc currentBloc; // défini la variable qui contient le bloc qui descend
Bloc nextBloc; // défini la variable qui contient le bloc suivant (afficher en aperçu)
#include "board.h"
Board board; // Initialise le tableau de jeu (objet voir 'board.h')
SDL_Surface* screen; // la fenêtre
SDL_Surface* background; // le fond de la fenêtre
SDL_Surface* matrice; // la matrice (zone de jeu)
SDL_Surface* grid; // la grille de la matrice
SDL_Surface* previewBloc; // la zone d'aperçu du bloc suivant
int scoreMax = 0, lineMax = 0;
SDL_TimerID timer_MoveBloc_auto; // Variable pour stocker le numéro du Timer pout bouger le bloc automatiquement
int game = false; // variable boolean qui détermine si une partie est en cours ou non
TTF_Font* police = NULL;
TTF_Font* police_m = NULL;
void GoDown() { ++tetris.posY; }
void GoUp() { --tetris.posY; }
void GoLeft() { --tetris.posX; }
void GoRight() { ++tetris.posX; }
//* Prototypes des fonction de tetris.cpp
void DisplayNumber( SDL_Surface* screen, SDL_Surface* tuiles, int x, int y, int s, int taille );
void MoveBloc( GAMES_MODE& mode );
Uint32 MoveBloc_auto( Uint32 intervalle, void *param ); // Timer pour le mouvement automatique du bloc
void draw_surface (SDL_Surface* src, int X_ori, int Y_ori, int srcWidth, int srcHeight, SDL_Surface* dest, int posX_onDest, int posY_onDest, Uint32 color = 0);
void update_surface (SDL_Surface* surface);
void init_blocs();
void init_colors(SDL_Surface* screen);
void init_options();
void add_bloc(int blocMaxWidth, string blocShape, int redRate = 256, int greenRate = 256, int blueRate = 256);
void add_special_bloc(int blocMaxWidth, string blocShape, int redRate = 256, int greenRate = 256, int blueRate = 256);
bool save_options(string filename);
int update_game();
void quit_game();
void new_game();
void end_game(bool loose_game = false);
void show_grid();
void show_text (char* text,TTF_Font* font, SDL_Surface* dest, int posX = 0, int posY = 0, int redRate = 0, int greenRate = 0, int blueRate = 0, int alpha = 255);
SDL_Surface* generate_random_bmp_tuiles (bool saveBMP = false);
void init_window_style();
bool get_blocs_by_file(bool get_special_blocs = false);
//*/
########BLOC.H########
// ----------------------------------------------------
class Bloc
{
public:
Bloc ();
Bloc( int, int, const char*, int redRate = (rand() % 256), int greenRate = (rand() % 256), int blueRate = (rand() % 256), const char* tuile_image = NULL );
void display( SDL_Surface*, int, int ) const;
void rotationRight();
void rotationLeft();
int index() const { return index_; }
int size() const { return size_; }
SDL_Surface* get_tuile() const { return tuile; }
int get( int x, int y ) const { return data_[ x * size() + y ]; }
private:
int index_;
int redRate_;
int greenRate_;
int blueRate_;
SDL_Surface* tuile;
int size_; // nb de lignes/colonne de la matrice du bloc
std::vector<int> data_;
};
Bloc::Bloc() {
}
// ----------------------------------------------------
Bloc::Bloc( int c, int s, const char* tab, int redRate, int greenRate, int blueRate, const char* tuile_image ) : index_( c ), size_( s ), redRate_( redRate ), greenRate_( greenRate ), blueRate_( blueRate )
{
for ( ; *tab; ++tab )
data_.push_back( (*tab=='1')?1:0 );
if (tuile_image == NULL) {
SDL_Surface* blocDegrade;
tuile = SDL_CreateRGBSurface(SDL_HWSURFACE, tetris.case_unit + 2*tetris.grid_width, tetris.case_unit + 2*tetris.grid_width, 32, 0, 0, 0, 0); // La bordure du bloc
// Fait un dégradé de la couleur vers le noir
for (int i = 0; i < (tetris.case_unit / 2); i++) { // On parcourt la tuile de l'extérieur vers l'intérieur, pixel par pixel et plus on va vers l'intérieur, plus on va ver le noir
blocDegrade = SDL_CreateRGBSurface(SDL_HWSURFACE, tetris.case_unit - (2 * i), tetris.case_unit - (2 * i), 32, 0, 0, 0, 0); // La bordure du bloc
// Les coordonnées de la surface sur la surface de destination
SDL_Rect srcPosition; // définition de la variable
srcPosition.x = i + tetris.grid_width; // abscisse
srcPosition.y = i + tetris.grid_width; // ordonnée
//Uint32 color = SDL_MapRGB(tuile->format, redRate_ - (i * (redRate_ / ((tetris.case_unit / 2) - 1))), greenRate_ - (i * (greenRate_ / ((tetris.case_unit / 2) - 1))), blueRate_ - (i * (blueRate_ / ((tetris.case_unit / 2) - 1)))); // dégradé vers le noir
Uint32 color = SDL_MapRGB(tuile->format, redRate_ + (i * ((255 - redRate_) / ((tetris.case_unit / 2) - 1))), greenRate_ + (i * ((255 - greenRate_) / ((tetris.case_unit / 2) - 1))), blueRate_ + (i * ((255 - blueRate_) / ((tetris.case_unit / 2) - 1)))); // dégradé vers le blanc
SDL_FillRect(blocDegrade, NULL, color); // Remplissage de la surface avec la couleur (color) passée en paramètre
SDL_BlitSurface(blocDegrade, NULL, tuile, &srcPosition); // Collage de la surface sur la destination (dest)
}
} else {
tuile = SDL_LoadBMP( tuile_image ); // chargement d'une image pour la tuiles
}
}
// ----------------------------------------------------
void Bloc::rotationRight()
{
for ( int i = 0; i < size() / 2 ; ++i )
for ( int j = 0; j < ( size() + 1 )/ 2; ++j )
{
int iAux = size() - 1 - i;
int jAux = size() - 1 - j;
swap( data_[i * size() + j], data_[jAux * size() + i] );
swap( data_[i * size() + j], data_[iAux * size() + jAux] );
swap( data_[i * size() + j], data_[j * size() + iAux] );
}
}
// ----------------------------------------------------
void Bloc::rotationLeft()
{
for ( int i = 0; i < size() / 2 ; ++i )
for ( int j = 0; j < ( size() + 1 )/ 2; ++j )
{
int iAux = size() - 1 - i;
int jAux = size() - 1 - j;
swap( data_[i * size() + j], data_[j * size() + iAux] );
swap( data_[i * size() + j], data_[iAux * size() + jAux] );
swap( data_[i * size() + j], data_[jAux * size() + i] );
}
}
// ----------------------------------------------------
void Bloc::display( SDL_Surface* screen, int x, int y ) const
{
for ( int i = 0; i < size(); ++i )
for ( int j = 0; j < size(); ++j )
if ( get( i, j ) )
{
SDL_Rect rectDest;
rectDest.x = i * (tetris.case_unit + tetris.grid_width) + x * (tetris.case_unit + tetris.grid_width) + tetris.grid_width;
rectDest.y = j * (tetris.case_unit + tetris.grid_width) + (y+1) * (tetris.case_unit + tetris.grid_width) + tetris.grid_width;
rectDest.w = rectDest.h = 0;
SDL_Rect rectSrc;
rectSrc.x = tetris.grid_width;
rectSrc.y = tetris.grid_width;
rectSrc.w = rectSrc.h = tetris.case_unit;
SDL_BlitSurface( tuile, &rectSrc, screen, &rectDest );
}
}
########BOARD.H########
//--------------------------------------------
//*
class Board
{
public:
Board()
{ // Initialisation des bordures
}
void display( SDL_Surface* ) const;
bool isMouvementValid( int, int, const Bloc& ) const;
void addPiece( int, int, const Bloc& );
void init_board()
{
_board.resize(tetris.board_size_x); // redimensionne le tableau à sa taille réelle calculée dans l'initialisation des options
for ( int x = 0; x < tetris.board_size_x; ++x ) {
_board[x].resize(tetris.board_size_y);
for ( int y = 0; y < tetris.board_size_y; ++y ) {
_board[x][y] = ( x == 0 || x == tetris.board_size_x - 1 || y == tetris.board_size_y - 1 );
}
}
}
void reduceLine( int );
int reduce();
private:
vector < vector<int> > _board; // utilisation d'un tableau multidimensionnel redimensionnable vector
};
// ----------------------------------------------------
void Board::display( SDL_Surface* screen ) const
{
for ( int x = 1; x < tetris.board_size_x-1; ++x )
for ( int y = 0; y < tetris.board_size_y-1; ++y )
if ( _board[x][y] )
{
SDL_Rect rectDest;
rectDest.x = x * (tetris.case_unit + tetris.grid_width);
rectDest.y = (y+1)* (tetris.case_unit + tetris.grid_width);
rectDest.w = rectDest.h = 0;
SDL_Rect rectSrc;
rectSrc.x = 0;
rectSrc.y = 0;
rectSrc.w = rectSrc.h = tetris.case_unit + (2*tetris.grid_width);
SDL_BlitSurface( blocs[_board[x][y] - 1].get_tuile(), &rectSrc, screen, &rectDest );
}
}
// ----------------------------------------------------
bool Board::isMouvementValid( int posX, int posY, const Bloc& bloc ) const
{
for ( int x = posX; x < posX + bloc.size(); ++x )
for ( int y = posY; y < posY + bloc.size(); ++y )
if ( bloc.get( x - posX, y - posY ) && _board[x][y] )
return false;
return true;
}
// ----------------------------------------------------
void Board::addPiece( int posX, int posY, const Bloc& bloc )
{
for ( int x = posX; x < posX + bloc.size(); ++x )
for ( int y = posY; y < posY + bloc.size(); ++y )
if ( bloc.get( x - posX, y - posY ) )
_board[x][y] = bloc.index() + 1;
}
// ----------------------------------------------------
int Board::reduce()
{
int addedLine = 0;
for ( int y = 1; y < tetris.board_size_y - 1 ; ++y )
{
bool lineFull = true;
for ( int x = 1; ( x < tetris.board_size_x - 1 ) && lineFull; ++x )
if ( !_board[x][y] ) lineFull = false;
if ( lineFull )
{
++addedLine; // Une ligne suplémentaire
for ( int z = y; z > 1 ; --z )
for ( int x = 1; x < tetris.board_size_x - 1; ++x )
_board[x][z] = _board[x][z-1];
for ( int x = 1; x < tetris.board_size_x - 1; ++x )
_board[x][0] = 0;
}
}
tetris.lines += addedLine;
if (tetris.level < ( tetris.lines / tetris.line_number_to_level_up ) + 1) {
tetris.level++; // Un niveau supplémentaire
tetris.score += (tetris.level * 100) + (tetris.level * min( 4, addedLine ) + addedLine) * 150; // Un point pour le niveau
return 2;
}
if (addedLine > 0) {
tetris.score += (tetris.level * min( 4, addedLine ) + addedLine) * 150; // Un point pour le niveau
return 1;
}
return 0;
}
Conclusion :
Tout est dans le zip A CETTE ADRESSE parce que le package est trop lourd (2MO)
Version 1 (2MO) :
http://dev.thierry.poinot.fr/TetrisV1.0 10-08-2007 16h35.zip
Version 2 (5MO) :
http://dev.thierry.poinot.fr/TetrisV2.0 19-08-2007 15h45.zip
Il contient les DLL, les sources, le projet Dev-cpp et l'éxécutable.
Pour les dernières mise à jour :
http://blog.thierry.poinot.fr/dc/?post/2007/08/14/Tetris-V10
Bugs connus :
le jeu ne se ferme qu'en appuyant sur ECHAP
- l'action de fermer la fenêtre avec la croix de la fenêtre ne marche pas je ne sais pas pourquoi...
- lorsque le jeu est en pause, il est impossible de fermer
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.