Programmer un Plus4 en SDL

Programmer un Plus4 en SDL - C - Programmation

Marsh Posté le 25-05-2009 à 21:30:42    

Bonjour à tous !
 
Je viens vous j'ai quelques petits souci :s
 
En effet, dans le cadre de mes études, j'ai un mini-projet à faire, et j'ai choisi de le faire avec SDL (nous n'avons vu qu'Allegro, et cette dernière ne m'inspirait guère).
 
Mon sujet est donc le Plus4 :
-> Comme pour le célèbre Puissance 4, il faut aligner 4 boules de sa couleur... Mais ici, les boules ne tombent pas directement au fond de la grille 4x4, elles ne descendent que d’un cran à la fois. Quand elles ont été poussées 4 fois, elles tombent de la grille et le joueur peut les récupérer et les remettre en jeu. Les possibilités sont donc infinies, aucune partie ne se essemble !
La partie dure ainsi jusqu'à ce qu'un joueur réalise un alignement de 4 pions de sa couleur orthogonalement ou en diagonale et gagne la partie.
 
Le problème que je rencontre, c'est que j'ai établi un plateau de jeu (taille 600*600) avec 16 emplacement possible (4*4) dans une fenetre (800*600), et je ne sais comment faire pour faire en sorte que lorsque je clique dans une colonne, mon pion aille directement dans la case concerné.
Je pensais faire un tableau (dans le genre de celui utilisé dans le tutoriel, pour le mario sokoban), mais comment définir le fait qu'il ne fasse pas toute la fenetre mais seulement le plateau ? Et comment indiqué au pion qu'il doit aller dans telle case ?
 
Désolé pour tout ce bla-bla, mais j'ai vraiment du mal a poursuivre mon projet, j'espère que quelqu'un pourra m'éclairer sur le sujet !
 
Bonne soirée à tous  :)


---------------
[Mon Feed-Back]  
Reply

Marsh Posté le 25-05-2009 à 21:30:42   

Reply

Marsh Posté le 26-05-2009 à 14:53:50    

Tu pourrais utiliser le décalage de bit, pour peu que ton plateau de jeu ait des dimensions en puissance de 2.
 
Je programme en C sur ma Nintendo DS, et j'utilise souvent ça pour déterminer facilement où je presse le stylet.
 
Par exemple, tu as 4x4 emplacements, sur un plateau de 64x64. En récupérant les coordonnées de là où tu as cliqué, tu n'as qu'à décaler tes bits vers la droite (opérateur ">>" ) de 4 unités (car il faut diviser 64 par 2 quatre fois de suite pour obtenir 4) et ça te donnera directement les coordonnées de l'emplacement. Si tu as cliqué sur le point x=23 et y=42, x>>4 va te donner 1 et y>>4 va te donner 2, soit la case 1;2, deuxième colonne, troisième ligne (car les coordonnées commencent à 0;0 de cette manière).
 
C'est ultra simple et efficace.
 
Si je n'ai pas été clair (ce qui à ma relecture me parait plausible  :ange: ), n'hésite pas à me reposer des questions là-dessus.
 


---------------
If you think it could look good, then I guess it should
Reply

Marsh Posté le 26-05-2009 à 15:08:46    

avant de te soucier de faire des décalages ou autres optims inutiles (c'(est un projet scolaire sur PC, pas un jeu sur DS), considère que ton tableau est dans un repère différent de ton écran, ton problème revient simplement à un changement de repère.


---------------
last.fm
Reply

Marsh Posté le 26-05-2009 à 15:27:06    

theshockwave a écrit :

avant de te soucier de faire des décalages ou autres optims inutiles (c'(est un projet scolaire sur PC, pas un jeu sur DS), considère que ton tableau est dans un repère différent de ton écran, ton problème revient simplement à un changement de repère.


 
Oui, effectivement, c'est la première chose à faire, le décalage de bit n'intervient qu'après. Mais c'est un bon moyen d'éviter le  

Code :
  1. if (x<16) {
  2.    colonne=0;
  3. } else if (x>=16 and x<32) {
  4.    colonne=1;
  5. } else if (x>=32 and x<48) {
  6. //etc, et même balayage pour y...


 
Que ça soit un jeu DS ou un programme scolaire, ça reste la meilleure solution à mes yeux pour effectuer cette tâche  :o (et encore, il n'y a que 4x4 cases, imagine que son tableau en fasse beaucoup plus, cette méthode n'a plus rien d'une optimisation inutile).
 
On récapitule :

LaGuiche a écrit :

comment définir le fait qu'il ne fasse pas toute la fenetre mais seulement le plateau ?

Suis le conseil de theshockwave

LaGuiche a écrit :

Et comment indiqué au pion qu'il doit aller dans telle case ?

Suis mon conseil  ;)  


---------------
If you think it could look good, then I guess it should
Reply

Marsh Posté le 26-05-2009 à 15:43:20    

Turkleton a écrit :


Oui, effectivement, c'est la première chose à faire, le décalage de bit n'intervient qu'après. Mais c'est un bon moyen d'éviter le  

Code :
  1. if (x<16) {
  2.    colonne=0;
  3. } else if (x>=16 and x<32) {
  4.    colonne=1;
  5. } else if (x>=32 and x<48) {
  6. //etc, et même balayage pour y...


 
Que ça soit un jeu DS ou un programme scolaire, ça reste la meilleure solution à mes yeux pour effectuer cette tâche  :o (et encore, il n'y a que 4x4 cases, imagine que son tableau en fasse beaucoup plus, cette méthode n'a plus rien d'une optimisation inutile).


 
Utiliser un décalage manuellement n'a rien à voir avec le fait d'éviter de faire une série de if. Si tu fais ton changement de repère correctement (addition, multiplication ou division) n'importe quel compilateur de moins de 20 ans d'âge te remplacera ta division ou ta multiplication par un décalage si nécessaire. SE soucier de ca, ca ne te sert à rien, quelle que soit la taille du tableau (vu que, quelle que soit la taille de ton tableau, tu change un point de repère, le nombre d'opérations est fixe)
 
Edit : typo


Message édité par theshockwave le 26-05-2009 à 15:43:42

---------------
last.fm
Reply

Marsh Posté le 26-05-2009 à 19:24:55    

Turkleton a écrit :


 
Oui, effectivement, c'est la première chose à faire, le décalage de bit n'intervient qu'après. Mais c'est un bon moyen d'éviter le  

Code :
  1. if (x<16) {
  2.    colonne=0;
  3. } else if (x>=16 and x<32) {
  4.    colonne=1;
  5. } else if (x>=32 and x<48) {
  6. //etc, et même balayage pour y...




 
Et / % c'est pr les manchots ...

Reply

Marsh Posté le 26-05-2009 à 19:59:23    

Joel F a écrit :


 
Et / % c'est pr les manchots ...


 
Non, c'est pour ceux qui veulent effectivement pas s'emmerder avec des trucs compliqués comme le décalage de bit. Sur la DS, ça marche bien car les dimensions sont adaptées, pour tout le reste, un bon "/" marche aussi bien  :jap:


---------------
If you think it could look good, then I guess it should
Reply

Marsh Posté le 26-05-2009 à 20:14:57    

Turkleton a écrit :


 
Non, c'est pour ceux qui veulent effectivement pas s'emmerder avec des trucs compliqués comme le décalage de bit. Sur la DS, ça marche bien car les dimensions sont adaptées, pour tout le reste, un bon "/" marche aussi bien  :jap:


 
[:prozac] ok le roxxor je te laisse là j'ai des trucs sérieux à faire :o

Reply

Marsh Posté le 26-05-2009 à 20:26:49    

Désolé, j'ai toujours cru que le résultat d'une division stocké dans un "int" plantait, d'où mon recours au décalage de bit pour ne pas avoir un résultat avec virgule dans un float.
Suite à ton post et à celui de theshockwave, j'ai recherché un peu et je me suis rendu compte que ce n'était pas le cas, et que le résultat était directement arrondi à l'entier inférieur, comme pour un décalage de bit, ce qui fait bien l'affaire dans ce cas de figure.
 
On en apprend tous les jours, je n'ai pas la science infuse, j'essayais juste d'aider avec le peu de connaissances que je possède, merci de tes messages très encourageants, vas-y tu peux y aller, va faire tes trucs sérieux  :pfff:


---------------
If you think it could look good, then I guess it should
Reply

Marsh Posté le 26-05-2009 à 20:29:56    

note : mettre un lien ver le post expliquant :o ;€

Reply

Marsh Posté le 26-05-2009 à 20:29:56   

Reply

Marsh Posté le 26-05-2009 à 20:34:50    

restons calmes, restons calmes :D
 
Bon pour l'histoire de décalage de bit, je sais pas si j'ai tout compris, mais je vais essayer de voir ce que je peux faire avec ça :)
 
Au début j'était parti sur  

Code :
  1. int carte[BLOCS_LARGEUR][BLOCS_HAUTEUR] = {0};


 
comme ça je pouvais facilement avoir mes cases avec

Code :
  1. carte[1][1]
  2. carte[2][4]


 
mais en fait j'ai du mal a comprendre le fonctionnement :s (j'avais pris ça, car je l'avais trouver sur le site du zéro)
 
 
Ensuite j'ai essayer :

Code :
  1. for(i=0;i<BLOCS_LARGEUR;i++)
  2.     {
  3.         for(j=0;j<BLOCS_HAUTEUR;j++)
  4.         {
  5.             positionVide.x=120+150*i; //position du 1er pions + espacement entre chaque
  6.             positionVide.y=38+105*j;
  7.             SDL_BlitSurface(Vide,NULL,ecran,&positionVide);
  8.         }


 
Cela avait pour but de mettre une image vide a chaque emplacement possible d'un pion, puis par la suite, on aurait cliqué dessus, et l'image v aurit été remplacé par un pion.
Mais idem, j'ai pas réussi a mettre en place, et je ne vois pas comment faire mes vérifications de victoire avec :s
 
Je sais pas si une de mes solutions aurait été exploitable mais bon :??:
 
Merci encore pour vos avis, je vais voir si j'arrive à avancer dans mon problème :)


---------------
[Mon Feed-Back]  
Reply

Marsh Posté le 31-05-2009 à 10:18:55    

Au fait, est ce qu'il y aurai une commande qui pourrait faire en sorte que lorsqu'on clique sur une image, cette dernière soit remplacée par une autre ?  
J'ai essayer avec le décalage de bit mais j'arrive a rien :(


---------------
[Mon Feed-Back]  
Reply

Marsh Posté le 01-06-2009 à 01:46:30    

oublie le site du zéro.
oublie cette histoire de décalage de bits.
 
le code que tu as écrit :

Code :
  1. positionVide.x=120+150*i;
  2. positionVide.y=38+105*j;


correspond au changement de repère dont je parlais plus haut. Avec ca, tu définis que ta grille est composée de cases de 150 pixels par 105 pixels et est décalée du coin haut gauche de l'écran de 120 pixels vers la droite et de 38 vers le bas, donc ...
 
Maintenant que tu as cette petite équation, tu dois facilement pouvoir localiser le clic de l'utilisateur
 
pour remplacer une zone affichée par une autre image, tu peux y aller à coup de BlitSurface aussi. Attention cependant à bien raffraichir l'ensemble des modifications qui ont lieu sur ta grille (les pièces qui sont poussées sont des cases sur lesquelles tu n'as pas cliqué, si j'ai bien saisi)
 
Plus simplement :
Il faut donc que tu aies à disposition une surface (image, donc) de case avec une pièce de chaque joueur et une image d'une case vide. Ensuite, pour composer ta grille, il te suffit de copier (à coups de BlitSurface, toujours) les bonnes images sur chaque case.
Le fait de ne raffraichir qu'une partie de la grille relève de l'optimisation. Commence par le plus simple : tu redessines toute la grille à chaque coup joué.


---------------
last.fm
Reply

Marsh Posté le 02-06-2009 à 19:20:58    


Comme tu me l'a dit, j'ai une surface défini pour le pion rouge, le bleu, et pour un espace vide.
 
mon code est le suivant :  
 

Code :
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <SDL.h>
  4. #include <SDL_image.h>
  5. #include "constantes.h"
  6. #include "jeu.h"
  7. void jeu(SDL_Surface* ecran)
  8. {
  9.     //Création des différentes surfaces de leur position
  10.     SDL_Surface *Rouge = NULL, *Bleu = NULL, *Plateau = NULL, *Vide = NULL;
  11.     SDL_Rect positionBleu, positionPlateau, positionRouge, positionVide;
  12.     SDL_Event event;
  13.     int continuer = 1;
  14.     int i,j,z;
  15.     int colonne, ligne;
  16.     //Chargement des images
  17.     Plateau = IMG_Load("plateau.png" );
  18.     Bleu = IMG_Load("pion_bleu.png" );
  19.     Rouge = IMG_Load("pion_rouge.png" );
  20.     Vide = IMG_Load("vide.png" );
  21.     //Position du plateau de jeu
  22.     positionPlateau.x = 0;
  23.     positionPlateau.y = 0;
  24.    
  25.    
  26.     SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 0, 0, 0)); //Coloration du fond
  27.     SDL_BlitSurface(Plateau, NULL, ecran, &positionPlateau); //Insertion de l'image du plateau de jeu
  28.     SDL_Flip(ecran);
  29.     //Insertion des images "vide" pour créer les différentes cases du plateau
  30.     for(i=0;i<BLOCS_LARGEUR;i++)
  31.     {
  32.         for(j=0;j<BLOCS_HAUTEUR;j++)
  33.         {
  34.             positionVide.x=120+150*i; //position du 1er pions + espacement entre chaque
  35.             positionVide.y=38+105*j;
  36.             SDL_BlitSurface(Vide,NULL,ecran,&positionVide);
  37.         }
  38.     }
  39.     while (continuer)
  40.     {
  41.         SDL_WaitEvent(&event);
  42.         switch (event.type)
  43.         {
  44.         case SDL_QUIT:
  45.             continuer = 0;
  46.             break;
  47.         case SDL_KEYDOWN:
  48.             switch (event.key.keysym.sym)
  49.             {
  50.             case SDLK_ESCAPE: //Touche Echap pour quitter
  51.                 continuer = 0;
  52.                 break;
  53.             }
  54.         case SDL_MOUSEBUTTONUP:
  55.             if (event.button.button == SDL_BUTTON_LEFT) //Pour un clique gauche
  56.             {
  57.                 positionBleu.x = event.button.x;
  58.                 positionBleu.y = event.button.y;
  59.                 SDL_BlitSurface(Bleu, NULL, ecran, &positionVide);
  60.             }
  61.             if (event.button.button == SDL_BUTTON_RIGHT) //Pour un clique droit
  62.             {
  63.                 positionRouge.x = event.button.x;
  64.                 positionRouge.y = event.button.y;
  65.                 SDL_BlitSurface(Rouge, NULL, ecran, &positionVide);
  66.             }
  67.             break;
  68.         }
  69.         SDL_BlitSurface(Plateau, NULL, ecran, &positionPlateau);
  70.         SDL_Flip(ecran);
  71.     }
  72. }


 
A ce stade, lorsque je clique, mes pions s'affiche seulement dans la case 4,4 ; la dernier positionVide écrite et ce quelque soit l'endroit ou je clique.
Comment je doit faire pour que le pion s'insère sur l'espace ou j'ai cliqué ? :??:
 
 
 
J'avais trouvé que la méthode de Turkleton, bien qu'elle soit a évité, aurait pu être envisageable, mais je ne comprend pas comment m'en servir par la suite :??:
 

Code :
  1. if (x<16) {
  2.    colonne=0;
  3. } else if (x>=16 and x<32) {
  4.    colonne=1;
  5. } else if (x>=32 and x<48) {
  6. //etc, et même balayage pour y...


 
Désolé pour toutes ces questions, mais la je suis vraiment perdu, et le délai se rétrécie  :sweat:


---------------
[Mon Feed-Back]  
Reply

Marsh Posté le 02-06-2009 à 21:08:01    

LaGuiche a écrit :


J'avais trouvé que la méthode de Turkleton, bien qu'elle soit a évité, aurait pu être envisageable, mais je ne comprend pas comment m'en servir par la suite :??:
 

Code :
  1. if (x<16) {
  2.    colonne=0;
  3. } else if (x>=16 and x<32) {
  4.    colonne=1;
  5. } else if (x>=32 and x<48) {
  6. //etc, et même balayage pour y...




 
Houla, non, c'est vraiment à éviter !  :non:  
 
Je ne connais pas bien SDL, mais j'ai cru voir un truc :  
dans ton instruction "SDL_BlitSurface(Bleu, NULL, ecran, &positionVide);", j'ai l'impression que tu utilises positionVide pour placer ton pion au lieu de positionBleu, qui a l'air d'être calculé en fonction de là où tu as cliqué (ou alors, j'ai rien compris à ton code), même chose pour le pion rouge. Et comme tu initialises positionVide plus haut dans le code en lui faisant prendre toutes les valeurs, et en finissant par la dernière, c'est pour ça que tu cliques n'importe où et c'est toujours la dernière case qui change.
 
Fais l'essai avec "SDL_BlitSurface(Bleu, NULL, ecran, &positionBleu);" et pareil pour rouge.
 
EDIT : Reste à savoir si tes "x" de positionBleu.x et event.button.x sont bien à la même échelle, et coordonnés. Pour ça, suis les indications de theshockwave.


Message édité par Turkleton le 02-06-2009 à 21:11:33

---------------
If you think it could look good, then I guess it should
Reply

Marsh Posté le 02-06-2009 à 21:21:00    

A oui, je me suis trompé en recopiant, ça c'était un essai que j'avais fait, mais sinon il était défini comme tu l'a dit :
 

Code :
  1. case SDL_MOUSEBUTTONUP:
  2.             if (event.button.button == SDL_BUTTON_LEFT) //Pour un clique gauche
  3.             {
  4.                 positionBleu.x = event.button.x;
  5.                 positionBleu.y = event.button.y;
  6.                 SDL_BlitSurface(Bleu, NULL, ecran, &positionBleu);
  7.             }
  8.             if (event.button.button == SDL_BUTTON_RIGHT) //Pour un clique droit
  9.             {
  10.                 positionRouge.x = event.button.x;
  11.                 positionRouge.y = event.button.y;
  12.                 SDL_BlitSurface(Rouge, NULL, ecran, &positionRouge);


 
Mais dans ce cas, je peux placer les pions n'importe ou sur ma grille :??:
Je n'arrive pas a vers en sorte qu'ils rentrent dans une des 16 cases ou il doivent allée, c'est ça qui me bloque :/
 


---------------
[Mon Feed-Back]  
Reply

Marsh Posté le 03-06-2009 à 07:39:10    

LaGuiche a écrit :


Mais dans ce cas, je peux placer les pions n'importe ou sur ma grille :??:
Je n'arrive pas a vers en sorte qu'ils rentrent dans une des 16 cases ou il doivent allée, c'est ça qui me bloque :/


 
A y est, je pense que je commence à comprendre un peu quel est ton problème : tes x et y sont des pixels et non des cases, et tu veux faire la conversion de l'un à l'autre, c'est ça ?
 
Exactement comme theshockwave te l'a dit, il faut inverser ton équation. Si ton équation de base pour remplir le plateau est :

Code :
  1. positionVide.x=120+150*i; //position du 1er pions + espacement entre chaque
  2. positionVide.y=38+105*j;


 
alors, les coordonnées de tes cases sont :
colonne sélectionnée = (event.button.x - 120) / 150
ligne sélectionnée = (event.button.y - 38) / 105
 
Ce que je ne savais pas (et que j'ai appris sur ce topic du coup), c'est que cette division va te donner un chiffre rond, à la condition que tu récupères ces deux résultats dans une variable de type "int". Ainsi, si tu cliques aux coordonnées (326;405), tu sélectionneras la case (1;3) (Attention, ça commence à 0, pas à 1).
 
Le mieux dans ton cas serait d'écrire les fonctions de conversion (dans un sens et dans l'autre) car tu vas osciller entre les coordonnées de tes cases (pour tous les calculs du jeu lui-même) et leur emplacement sur l'écran (en pixel cette fois, pour tous tes SDL_BlitSurface par exemple).
 
Ça aide ?


---------------
If you think it could look good, then I guess it should
Reply

Marsh Posté le 03-06-2009 à 18:50:06    

Oui ça m'aide pas mal, j'ai compris le principe, mais  je crois que j'ai du mal avec le fonctionnement.
 
Comme tu l'a dit je définit ligne et colonne ainsi :

Code :
  1. int colonne, ligne
  2. ...
  3.     colonne = ((event.button.x - 120) / 150);
  4.     ligne = ((event.button.y - 38) / 105);


 
Puis par la suite :  

Code :
  1. case SDL_MOUSEBUTTONUP:
  2.             if (event.button.button == SDL_BUTTON_LEFT) //Pour un clique gauche
  3.             {
  4.                 positionBleu.x=120+150*colonne;
  5.                 positionBleu.y=38+105*ligne;
  6.                 SDL_BlitSurface(Bleu, NULL, ecran, &positionBleu);


 
Mais ça me colle toujours mon pion dans la case 1,1  :heink:  
 
Je peux pas faire un  

Code :
  1. if(colonne=1)
  2.                 {
  3.                     positionBleu.x=120;
  4.                     positionBleu.y=38;
  5.                     SDL_BlitSurface(Bleu, NULL, ecran, &positionBleu);


Ca serait hyper compliqué non ? :??:
 
 
Je crois que je me suis lancé dans plus gros que mes compétences  :pt1cable:  
 


Message édité par LaGuiche le 03-06-2009 à 19:08:26

---------------
[Mon Feed-Back]  
Reply

Marsh Posté le 03-06-2009 à 20:10:58    

vu que tu n'as qu'un seul rectangle pour stocker la position DU pion bleu, tu ne peux pas retenir plusieurs positions, tu remarqueras.
 
Il faut que tu prennes l'habitude de séparer les données de l'affichage.
 
Avant de te lancer dans les problèmes avec SDL, fais-le éventuellement en mode texte.
 
Note que pour faire ce jeu, pouvoir tester d'éventuelles questions de victoire ou autre, il faudrait que tu connaisses l'état du jeu à chaque coup.


---------------
last.fm
Reply

Marsh Posté le 03-06-2009 à 20:19:08    

A oui ptain jsuis con, j'ai pas pensé au fait qu'il y ai qu'un pion :/
 
Bon je fait essayer de resoudre ça, j'espère que je vais m'en sortir :s


---------------
[Mon Feed-Back]  
Reply

Marsh Posté le 04-06-2009 à 16:33:24    

Bon bah j'ai résolu un de mes nombreux problèmes, je peux placer mon pion dans la colonne que je veux, c'était juste l'expression de colonne et de ligne qui n'était pas placé au bon endroit :/
 
du coup, maintenant ça donne :  

Code :
  1. ...
  2.         SDL_WaitEvent(&event);
  3.         switch (event.type)
  4.         {
  5.         case SDL_QUIT:
  6.             continuer = 0;
  7.             break;
  8.         case SDL_KEYDOWN:
  9.             switch (event.key.keysym.sym)
  10.             {
  11.             case SDLK_ESCAPE: //Touche Echap pour quitter
  12.                 continuer = 0;
  13.                 break;
  14.             }
  15.         case SDL_MOUSEBUTTONUP:
  16.             colonne = ((event.button.x - 120) / 150);
  17.             ligne = ((event.button.y - 38) / 105);
  18.             if (event.button.button == SDL_BUTTON_LEFT) //Pour un clique gauche
  19.             {
  20.                 positionBleu.x = 120+150*colonne;
  21.                 positionBleu.y = 38;
  22.                 SDL_BlitSurface(Bleu, NULL, ecran, &positionBleu);
  23.             }
  24.            
  25.             if (event.button.button == SDL_BUTTON_RIGHT) //Pour un clique droit
  26.             {
  27.                 positionRouge.x = 120+150*colonne;
  28.                 positionRouge.y = 38;
  29.                 SDL_BlitSurface(Rouge, NULL, ecran, &positionRouge);
  30.             }
  31.             break;
  32.         }
  33. ...


 
Bon donc maintenant je vais m'attaquer a faire en sorte que lorsque je clique dans une colonne, les pion déja mis dans cette dernière se décalent ... y a du boulot :D


Message édité par LaGuiche le 04-06-2009 à 16:33:52

---------------
[Mon Feed-Back]  
Reply

Marsh Posté le 04-06-2009 à 23:18:42    

Salut
 
J'avoue que je n'ai pas tout lu minutieusement, c'est sans doute ma première erreur. Quand je te vois parler de décalage des pions et que je regarde ton code au dessus, je me dis qu'en effet tu as peut-être bien du boulot.
Mon avis est qu'il faut séparer le moteur du jeu et la représentation graphique.
Au lieu d'afficher quelque chose quand tu cliques et d'essayer de voir ton jeu "visuellement", je pense que tu devrais le voir de façon "abstraite". Je m'explique. Je vois ton jeu comme un tableau à deux dimensions dont les cases peuvent contenir trois valeurs différentes: vide, rouge ou bleu. Les actions de l'utilisateur modifient le tableau. Ici c'est le clic souris mais cela pourrait bien être n'importe quoi, il faut s'affranchir de la technique utilisée par l'utilisateur (selon moi). Par exemple un excellent joueur d'echec peut jouer sans voir le plateau (équivalent au tableau 2D en mémoire) et sans "ses mains" juste en indiquant quelle pièce bouge de tel endroit à tel autre (équivalent à un scanf en gros). Cela ne change pas le jeu, juste sa représentation.
Pour en revenir à ton problème, le changement de repère que tu as obtenu précédemment te donne les coordonnées dans le tableau. Tu peux ensuite gérer les décalages toujours dans ce tableau.
 

Code :
  1. ajouterPion (ligne, colonne, couleur)
  2. {
  3.     si ligne == nblignes  /* le tableau va de 0 à nblignes-1 si ligne== nblignes c'est que le pion est "tombé"  */
  4.              return
  5.     si tab[ligne][colonne] != vide
  6.              ajouterPion (ligne+1, colonne, tab[ligne][colonne]) /* le pion de la ligne est décalé d'un cran */
  7.    
  8.     tab[ligne][colonne]=couleur /* le nouveau pion est placé dans le tableau */
  9. }


 
Voilà c'est un peu à l'arrache et écrit vite fait mais ça ne soit pas être trop loin du but.
Ensuite tu affiches le tableau avec une bete boucle for

Code :
  1. for i de 0 à nbcolonnes-1
  2. j de 0 à nblignes -1
  3.      changement de repere pour passer aux coordonnées de l'ecran
  4.      blitSurface ( obtenirSDLSurfaceAPartirDeCouleur(tab[i][j]))


     
 
Du coup dans ton programme, l'affichage et le jeu sont séparés:
 

Code :
  1. while ( personneNeGagne() )
  2. {
  3.     intercepterActionsUtilisateur()  /* encore une fois ici on pourrait avoir autre chose que des clics de souris */
  4.     modifierTableauSiBesoin ()
  5.     afficher() /* et ici on pourrait avoir une représentation sans SDL: simple printf, ncurses, ... */
  6. }


 
Voilà j'espère que je suis clair, que je n'ai pas écrit trop de merde et que cela t'aide.
Bonne nuit


---------------
deluser --remove-home ptitchep
Reply

Marsh Posté le 05-06-2009 à 09:34:18    

Oui j'ai pu faire quelque chose d'équivalent a ce que tu m'a dis, car au début je n'avais pas pensé au tableau en mémoire, alors que c'est ce qu'il y avait de plus pratique et simple, je pense, a mettre en place ^^
 
Bon donc la je dois dire que j'ai pu pas mal avancé, un ami ma également éclairer sur 2/3 trucs.
 
Donc pour le moment ça marche, je n'ai plus qu'a faire la condition pour que un joueur de puisse pas jouer 2 fois de suite, ainsi que la condition de victoire. Si je fini ça, je serais bien tranquille, le reste relevera de l'optimisation :)
 
 
Je vous met mon code si cela vous interresse, j'avoue que c'est peux être pas très bien codé, mais pour le moment ça marche est c'est le principal ^^  
 

Code :
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <SDL.h>
  4. #include <SDL_image.h>
  5. #include "constantes.h"
  6. void jeu(SDL_Surface* ecran)
  7. {
  8.     //Création des différentes surfaces de leur position
  9.     SDL_Surface *Rouge = NULL, *Bleu = NULL, *Plateau = NULL, *Vide = NULL;
  10.     SDL_Rect positionBleu, positionPlateau, positionRouge, positionVide, position;
  11.     SDL_Event event;
  12.     //Création du tableau en mémoire
  13.     char table[BLOCS_HAUTEUR][BLOCS_LARGEUR] = {0};
  14.     int continuer = 1;
  15.     int i,j;
  16.     int colonne, ligne;
  17.     //Chargement des images
  18.     Plateau = IMG_Load("plateau.png" );
  19.     Bleu = IMG_Load("pion_bleu.png" );
  20.     Rouge = IMG_Load("pion_rouge.png" );
  21.     Vide = IMG_Load("vide.png" );
  22.     //Position du plateau de jeu
  23.     positionPlateau.x = 0;
  24.     positionPlateau.y = 0;
  25.     SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 0, 0, 0)); //Coloration du fond
  26.     SDL_BlitSurface(Plateau, NULL, ecran, &positionPlateau); //Insertion de l'image du plateau de jeu
  27.     SDL_Flip(ecran);
  28.     //Insertion des images "vide" pour créer les différentes cases du plateau
  29.     for (i=0 ; i<BLOCS_LARGEUR ; i++)
  30.     {
  31.         for (j=0 ; j<BLOCS_HAUTEUR ; j++)
  32.         {
  33.             positionVide.x=120+150*i; //position du 1er pions + espacement entre chaque
  34.             positionVide.y=38+105*j;
  35.             SDL_BlitSurface(Vide,NULL, ecran,&positionVide);
  36.         }
  37.     }
  38.     //Initialisation du tableau en mémoire
  39.     for (i=0 ; i<BLOCS_LARGEUR ; i++)
  40.     {
  41.         for (j=0 ; j<BLOCS_HAUTEUR; j++)
  42.         {
  43.             table[i][j] = 'v';
  44.         }
  45.     }
  46.     while (continuer)
  47.     {
  48.         SDL_WaitEvent(&event);
  49.         switch (event.type)
  50.         {
  51.         case SDL_QUIT:
  52.             continuer = 0;
  53.             break;
  54.         case SDL_KEYDOWN:
  55.             switch (event.key.keysym.sym)
  56.             {
  57.             case SDLK_ESCAPE: //Touche Echap pour quitter
  58.                 continuer = 0;
  59.                 break;
  60.             }
  61.         case SDL_MOUSEBUTTONUP:
  62.             colonne = ((event.button.x - 75) / 150) + 1;
  63.             ligne = ((event.button.y - 38) / 105);
  64.             if (event.button.button == SDL_BUTTON_LEFT) //Pour un clique gauche
  65.             {
  66.                 //Décalage vers le bas des valeurs de la colonne sélectionnée
  67.                 for (i=3 ; i > 0 ; i--)
  68.                 {
  69.                     table[colonne-1][i]=table[colonne-1][i-1];
  70.                 }
  71.                 //Case de la colonne choisi et de la ligne 1 = BLEU
  72.                 table[colonne-1][0]='b';
  73.             }
  74.             if (event.button.button == SDL_BUTTON_RIGHT) //Pour un clique droit
  75.             {
  76.                 //Décalage vers le bas des valeurs de la colonne sélectionnée
  77.                 for (i=3 ; i > 0 ; i--)
  78.                 {
  79.                     table[colonne-1][i]=table[colonne-1][i-1];
  80.                 }
  81.                 //Case de la colonne choisi et de la ligne 1 = ROUGE
  82.                 table[colonne-1][0] = 'r';
  83.             }
  84.             //Balayage du tableau en mémoire pour remplir les cases
  85.             for (i=0 ; i<BLOCS_LARGEUR ; i++)
  86.             {
  87.                 for (j=0 ; j<BLOCS_HAUTEUR; j++)
  88.                 {
  89.                     position.x= 120+150*i;
  90.                     position.y= 38+105*j;
  91.                     switch (table[i][j])
  92.                     {
  93.                     case 'v':
  94.                         SDL_BlitSurface(Vide, NULL, ecran, &position);
  95.                         break;
  96.                     case 'b':
  97.                         SDL_BlitSurface(Bleu, NULL, ecran, &position);
  98.                         break;
  99.                     case 'r':
  100.                         SDL_BlitSurface(Rouge, NULL, ecran, &position);
  101.                         break;
  102.                     }
  103.                 }
  104.             }
  105.             break;
  106.         }
  107.         SDL_BlitSurface(Plateau, NULL, ecran, &positionPlateau);
  108.         SDL_Flip(ecran);
  109.     }
  110. }


 
Merci encore a tous pour vos avis !! :)


---------------
[Mon Feed-Back]  
Reply

Marsh Posté le 06-06-2009 à 16:00:32    

LaGuiche a écrit :


Code :
  1. 40:    SDL_Flip(ecran);




 
Pourquoi tu le fais là ?

Reply

Marsh Posté le 06-06-2009 à 16:13:19    

Euh bah ça devait être un essai que j'avais fait, et j'ai oublier de l'enlever, mais maintenant c'est corrigé :)
 
Bon en ce moment je suis sur les conditions de victoire, ça va pas trop mal:s
 
voici mon code :

Code :
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <SDL.h>
  4. #include <SDL_image.h>
  5. #include <time.h>
  6. #include "constantes.h"
  7. void jeu(SDL_Surface* ecran)
  8. {
  9.     //Création des différentes surfaces de leur position
  10.     SDL_Surface *Rouge = NULL, *Bleu = NULL, *Plateau = NULL, *Vide = NULL;
  11.     SDL_Surface *Tour_rouge = NULL, *Tour_bleu = NULL;
  12.     SDL_Surface *Victoire_rouge = NULL, *Victoire_bleu = NULL;
  13.     SDL_Rect positionBleu, positionPlateau, positionRouge, positionVide, position;
  14.     SDL_Rect positionTour_bleu, positionTour_rouge;
  15.     SDL_Rect positionVictoire_bleu, positionVictoire_rouge;
  16.     SDL_Event event;
  17.     //Création du tableau en mémoire
  18.     char table[BLOCS_HAUTEUR][BLOCS_LARGEUR] = {0};
  19.     int continuer = 1;
  20.     int i,j;
  21.     int colonne, ligne;
  22.     int tourjoueur=nb_aleatoire(1,2);
  23.     int victoire = 0;
  24.     char p;
  25.     //Chargement des images
  26.     Plateau = IMG_Load("plateau.png" );
  27.     Bleu = IMG_Load("pion_bleu.png" );
  28.     Rouge = IMG_Load("pion_rouge.png" );
  29.     Vide = IMG_Load("vide.png" );
  30.     Tour_bleu = IMG_Load("tour_bleu.png" );
  31.     Tour_rouge = IMG_Load("tour_rouge.png" );
  32.     Victoire_bleu = IMG_Load("victoire_bleu.png" );
  33.     Victoire_rouge = IMG_Load("victoire_rouge.png" );
  34.     //Position du plateau de jeu
  35.     positionPlateau.x = 0;
  36.     positionPlateau.y = 0;
  37.     SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 0, 0, 0)); //Coloration du fond
  38.     SDL_BlitSurface(Plateau, NULL, ecran, &positionPlateau); //Insertion de l'image du plateau de jeu
  39.    //Chargement des images selon a qui est le tour de joué
  40.     if(tourjoueur == 1)
  41.     {
  42.         positionTour_bleu.x = (L_ECRAN/2)-(314/2);
  43.         positionTour_bleu.y = ((H_ECRAN-100)/2)-(135/2);
  44.         SDL_BlitSurface(Tour_bleu, NULL, ecran, &positionTour_bleu);
  45.         SDL_Flip(ecran);
  46.     }
  47.     else if(tourjoueur == 2)
  48.     {
  49.         positionTour_rouge.x = (L_ECRAN/2)-(314/2);
  50.         positionTour_rouge.y = ((H_ECRAN-100)/2)-(135/2);
  51.         SDL_BlitSurface(Tour_rouge, NULL, ecran, &positionTour_rouge);
  52.         SDL_Flip(ecran);
  53.     }
  54.     SDL_Delay(1500); //On attend 1,5s avant l'effacement de l'affichage de tour de joué
  55.     SDL_FreeSurface(Tour_bleu);
  56.     SDL_FreeSurface(Tour_rouge);
  57.     SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 0, 0, 0));
  58.     //Initialisation du tableau en mémoire
  59.     for (i=0 ; i<BLOCS_LARGEUR ; i++)
  60.     {
  61.         for (j=0 ; j<BLOCS_HAUTEUR; j++)
  62.         {
  63.             table[i][j] = 'v';
  64.         }
  65.     }
  66.     while (continuer)
  67.     {
  68.         SDL_WaitEvent(&event);
  69.         switch (event.type)
  70.         {
  71.         case SDL_QUIT:
  72.             continuer = 0;
  73.             break;
  74.         case SDL_KEYDOWN:
  75.             switch (event.key.keysym.sym)
  76.             {
  77.             case SDLK_ESCAPE: //Touche Echap pour quitter
  78.                 continuer = 0;
  79.                 break;
  80.             }
  81.         case SDL_MOUSEBUTTONUP:
  82.             colonne = ((event.button.x - 75) / 150) + 1;
  83.             ligne = ((event.button.y - 38) / 105);
  84.             if (event.button.button == SDL_BUTTON_LEFT && tourjoueur == 1) //Pour un clique gauche
  85.             {
  86.                 //Décalage vers le bas des valeurs de la colonne sélectionnée
  87.                 for (j=3 ; j > 0 ; j--)
  88.                 {
  89.                     table[colonne-1][j]=table[colonne-1][j-1];
  90.                 }
  91.                 //Case de la colonne choisi et de la ligne 1 = BLEU
  92.                 table[colonne-1][0]='b';
  93.                 tourjoueur = 2;
  94.             }
  95.             if (event.button.button == SDL_BUTTON_RIGHT && tourjoueur == 2) //Pour un clique droit
  96.             {
  97.                 //Décalage vers le bas des valeurs de la colonne sélectionnée
  98.                 for (j=3 ; j > 0 ; j--)
  99.                 {
  100.                     table[colonne-1][j]=table[colonne-1][j-1];
  101.                 }
  102.                 //Case de la colonne choisi et de la ligne 1 = ROUGE
  103.                 table[colonne-1][0] = 'r';
  104.                 tourjoueur = 1;
  105.             }
  106.             //Balayage du tableau en mémoire pour remplir les cases
  107.             for (i=0 ; i<BLOCS_LARGEUR ; i++)
  108.             {
  109.                 for (j=0 ; j<BLOCS_HAUTEUR; j++)
  110.                 {
  111.                     position.x= 120+150*i;
  112.                     position.y= 38+105*j;
  113.                     switch (table[i][j])
  114.                     {
  115.                     case 'v':
  116.                         SDL_BlitSurface(Vide, NULL, ecran, &position);
  117.                         break;
  118.                     case 'b':
  119.                         SDL_BlitSurface(Bleu, NULL, ecran, &position);
  120.                         break;
  121.                     case 'r':
  122.                         SDL_BlitSurface(Rouge, NULL, ecran, &position);
  123.                         break;
  124.                     }
  125.                 }
  126.             }
  127.             //vérification de victoire pour les colonnes
  128.             for(i=0 ; i<4 ; i++)
  129.             {
  130.                 j=0;
  131.                     if(table[i][j] == 'b' && table[i][j+1] == 'b' && table[i][j+2] == 'b' && table[i][j+3] == 'b')
  132.                     {
  133.                         victoire = 1;
  134.                     }
  135.                     else if(table[i][j] == 'r' && table[i][j+1] == 'r' && table[i][j+2] == 'r' && table[i][j+3] == 'r')
  136.                     {
  137.                         victoire = 2;
  138.                     }
  139.             }
  140.             //Condition de fin, 1 = victoire des bleu, 2 victoire des rouges
  141.             if (victoire == 1)
  142.             {
  143.                 positionVictoire_bleu.x = (L_ECRAN/2)-(400/2);
  144.                 positionVictoire_bleu.y = ((H_ECRAN-100)/2)-(200/2);
  145.                 SDL_BlitSurface(Victoire_bleu, NULL, ecran, &positionVictoire_bleu);
  146.             }
  147.             else if (victoire == 2)
  148.             {
  149.                 positionVictoire_rouge.x = (L_ECRAN/2)-(400/2);
  150.                 positionVictoire_rouge.y = ((H_ECRAN-100)/2)-(200/2);
  151.                 SDL_BlitSurface(Victoire_rouge, NULL, ecran, &positionVictoire_rouge);
  152.             }
  153.          break;
  154.         }
  155.         SDL_BlitSurface(Plateau, NULL, ecran, &positionPlateau);
  156.         SDL_Flip(ecran);
  157.     }
  158. }
  159. int nb_aleatoire (int num_min, int num_max)
  160. {
  161.     return (int) (rand() / (double)RAND_MAX * (num_max - num_min + 1) + num_min);
  162. }


 
 
Y a juste l'image de victoire qui s'affiche sous le plateau je sais pas pourquoi :/
 
Puis faudrait que quand il y a victoire, ça reste afficher genre pendant 2 secondes puis qu'on revienne au menu
 
Enfin la fin minimal approche, je suis soulager :)


Message édité par LaGuiche le 06-06-2009 à 16:30:25

---------------
[Mon Feed-Back]  
Reply

Marsh Posté le 06-06-2009 à 17:06:22    

Salut
 
Découpe ton code en fonction, sinon tu vas vite être dépassé.
 
Ton affichage est à moitié à l'intérieur de ta gestion des événements et à moitié en dehors.
 
A mon avis ton image s'affiche dessous simplement parce que tu l'affiches avant le plateau
tu devrais faire une fonction d'affichage qui
-efface l'écran
-affiche le plateau et autres décorations
-affiche les pions
-affiche la victoire d'un joueur si besoin (avec le numéro du joueur en argument par exemple 0=pas de victoire; 1=joueur1; 2=joueur2)
et l'appeler à chaque fin de boucle.
 
Ta condition de victoire ne vérifie que les alignements verticaux. De plus comme c'est le même code pour les deux joueurs à l'exception de la valeur à vérifier, tu peux en faire une fonction avec la valeur en argument et l'appeler pour chaque joueur => évolution plus simple vers un nombre de joueurs différent. Elle te retourne vrai ou faux selon si le joueur passé en argument a gagné ou pas.
Je pense que pour éviter de trop mouliner tu ne devrais vérifier que les pions qui ont changé de place. Pour chaque pion de la colonne modifiée, tu regardes en haut en bas sur les cotés et en diagonale s'il ne fait pas partie d'un groupe de 4. Attention aux débordements et bon courage pour ne pas oublier de possibilités.
 
Pour ce qui est de revenir au menu après une victoire, je ferais simple genre rajouter une condition
if (!victoire)
pour la gestion de la souris (les joueurs ne pourront plus cliquer si quelqu'un a gagné;).
Si dans ta fonction d'affichage tu gères la victoire comme je viens de le dire alors le message restera affiché jusqu'à ce que l'utilisateur appuie sur echap ==> sortie de la boucle.
(ptite precision: la position de l'image de la victoire est toujours la même quel que soit le joueur, tu n'as besoin que d'une variable)
 
Bon courage,
si tu découpes correctement ton code: gestion des événements, actions, vérification de victoire, affichage, le tout dans des fonctions claires, tu devrais avoir une bonne note. Enfin si et seulement si ton prof regarde le code des devoirs qu'il corrige (très rare). Dans le cas contraire, tu auras au moins pris de bonnes habitudes. Par pitié évite les phrases genre:
 

LaGuiche a écrit :

Je vous met mon code si cela vous interresse, j'avoue que c'est peux être pas très bien codé, mais pour le moment ça marche est c'est le principal ^^  


C'est vrai, pour un devoir à rendre, c'est le principal vu que la plupart des profs ne regardent pas ce que tu as fait mais seulement le résultat. Par contre plus tard, tu risques d'avoir à coder des choses qui seront à maintenir, à améliorer et pas forcément par toi. Si tu ponds une bouse "qui marche", au premier problème ton code sera bon pour la poubelle et il faudra tout recommencer.


---------------
deluser --remove-home ptitchep
Reply

Marsh Posté le 06-06-2009 à 17:35:13    

D'acc merci pour ton avis :)
 
 
Le if(!victoire) est une super idée, c'est tout simple, mais jy avais pas pensé :s
 
Pour découpé en fonction je vais essayé de faire ça aussi, je ne m'y était pas attelé, car j'était en stress de pas avoir un programme qui marche, et je m'était concentré dessus.
 
Sinon pour les vérification, j'ai fait le meme principe que pour les colonne, remodelé un petit peu :)
 
Par contre mon problème reste pour l'affichage de l'image de victoire.
 
Tel quel dans le code ci dessus, ça s'affiche sous le plateau, puis quelque ligne après, je blitte le plateau.
 
J'ai donc essayé ça :  

Code :
  1. //Condition de fin
  2.             if (victoire == 1)
  3.             {
  4.                 positionVictoire_bleu.x = (L_ECRAN/2)-(400/2);
  5.                 positionVictoire_bleu.y = ((H_ECRAN-100)/2)-(200/2);
  6.                 SDL_BlitSurface(Victoire_bleu, NULL, ecran, &positionVictoire_bleu);
  7.                 SDL_Delay(3000);
  8.                 continuer = 0;


 
Normalement, je blitte la surface, j'attend 3sec et je quitte, le problème c'est que une vois que 4 pions sont aligné, le jeu se bloque le temps du delai, l'image s'affiche et le jeu quitte tout de suite après, comme si j'avais mis le delai avant le blitsurface :heink:
 
Du coup je sais pas trop comment je peux faire :s


---------------
[Mon Feed-Back]  
Reply

Marsh Posté le 06-06-2009 à 17:42:05    

Normal, l'affichage ne se fait réellement que lorsque tu "flip" les buffers. C'est pour cela que je te conseille de faire une fonction d'affichage qui fait tout d'un coup ET SURTOUT DANS LE BON ORDRE.
 
Fill (ecran, toutNoir)
blit (plateau)
blit (pions)
if (victoire)
    blit (victoire)
FLIP (ecran)
 
après cette fonction tu peux toujours ajouter  
if (victoire)
{
     sleep (3)
     continuer=0
}
 
mais je reste persuadé que chuinter la souris et attendre l'appui sur echap est une meilleure solution. Sinon pendant l'attente, ton programme est hors contrôle, si tu cliques sur la croix pour le fermer par exemple, je ne pense pas que cela fonctionne.


Message édité par ptitchep le 06-06-2009 à 17:43:55

---------------
deluser --remove-home ptitchep
Reply

Marsh Posté le 08-06-2009 à 08:07:52    

Bon bah mon Plus4 est terminer, normalemet tout fonctionne :)
 
Par contre j ai pas fait plein de fonctions, juste une qui me permet de faire toute les verifs, vu que contre le pc je les fais apres le joueur et apres le pc.  
Si vous voulez voir ce ke ca donne : www.rkfg.fr/autre/Plus_4.rar si je me trompe pas :)
 
Merci encore en vous tous pour vos avis :)


---------------
[Mon Feed-Back]  
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed