Aller au contenu

[RESOLU] [C] Tetris, problème de déplacement


tata2

Messages recommandés

Bonjour à tous !

Alors voilà, je suis actuellement en DUT INFO première année et en semaine spéciale de progra' on doit faire un tetris et depuis hier 16h, je cherche donc à déplacer un bloc avec les touches.

J4ai un petit soucis, si je ne met pas de sleep on ne voit pas le bloc qui descend, il est direct en bas (stupide processeur qui calcule trop vite ! x)' )

Et si je met un Sleep mes touches sont prises en compte après le Sleep donc si le bloc est bloqué par le Sleep, les touches (donc le déplacement à droite ou à gauche) seront pris en compte au prochain déplacement vers le bas

Donc j'aimerai savoir s'il y aurait un moyen de pouvoir déplacer le bloc même quand il est bloqué ... ?

Je vous laisse le code que j'ai fais actuellement et qui est celui qui fonctionne le mieux pour le déplacement sans bug :

for(i=0;i<2;i=1)   {       while(kbhit()==0)       {           if(grilleTetris[*x][*y+1]!=0 && *y<19)           {               *y+=1;               *top=*top+30;               *bottom=*bottom+30;               cleardevice();               rectangle(*left,*top,*right,*bottom);               grilleTetris[*x][*y]={0};               grilleTetris[*x][*y+1]={1};               printf("\n%i %i", *x, *y);           }           else           {               i=3;           }           Sleep(500);       }       touche=getch();       if(touche==KEY_LEFT)       {           *left-=30;           *right-=30;           cleardevice();           rectangle(*left,*top,*right,*bottom);           grilleTetris[*x][*y]={0};           grilleTetris[*x-1][*y]={1};       }       else if(touche==KEY_RIGHT)       {           *left+=30;           *right+=30;           cleardevice();           rectangle(*left,*top,*right,*bottom);           grilleTetris[*x][*y]={0};           grilleTetris[*x+1][*y]={1};       }   }

L'affichage du tetris est fait avec winbgi

left top right bottom correspondent au coordonnées dont j'ai besoin pour afficher mon bloc

x et y correspondent au position du bloc dans mon tableau (qui représente le tétris)

Si y'a besoin de plus de chose, je peux passer mais j'aimerai bien comprendre comment faire :(

Merci d'avance !

Lien vers le commentaire
Partager sur d’autres sites

Je ne maitrise pas trop la programmation de jeu et mon C est assez rouillé. Je ne me base ici donc que sur ta description, pas ton code.

Si j'ai bien compris, tu contrôles si un appui sur une touche a été effectué ainsi que la position et l'affichage à chaque itération, en faisant à chaque fois chuter le bloc en cours d'un cran ? Si tel est bien le cas, ce que je propose, c'est que tu contrôles l'appui sur les touches plus fréquemment, permettant au final au bloc de se déplacer plus rapidement horizontalement que sa vitesse de chute.

La programmation d'un Tetris semble être un exercice extrêmement intéressant. Surtout la gestion des pièces une fois qu'elles sont en contact avec le "sol".

Lien vers le commentaire
Partager sur d’autres sites

Je n'ai pas trop le temps de répondre, mais en gros c'est le problème du noob level 0 sur la gestion des animations.

Ton jeu a une boucle Main Loop comme cela (sûrement un timer tous les X millisecondes ou un Sleep comme ci-dessous):

while( !finished ) { handle_events(); update(); render(); sleep(20);}

Notice the sleep function here. It puts the code to sleep for some small period each loop so that it does not form a solid loop that would constantly suck up all of the time on the CPU.

Frame-based versus time-based logic

Frame-based logic updates game objects based on changes to individual frames. Timebased logic, which is more complex but more closely associated to the actual state of the game, updates game objects based on the time that has transpired. Programmers who are new to game development often make the mistake of combining frame- and time-based logic. The difference is subtle in definition, but it can cause very noticeable bugs if not handled appropriately. For example, let’s take the case of player movement. Novice programmers might write something such as this:

 void onPlayerInput( Input inputEvent ) {   if(inputEvt.type == IE_KEY && inputEvt.value == KEY_UP) {     //apply movement based on the user input     playerAvatar.y += movementSpeed;   } }

Every time the player presses a key, the avatar moves forward a set amount. This is frame-based logic because the change in movement can potentially happen with every new frame. Actually, in the current example, it will happen once per input event, which might be more or less than an iteration of the main loop. The visual impact of the move will be noticed only on the next iteration of the main loop, so any intermediate avatar movements will be wasted calculations. Let’s make the following improvement:

 void onPlayerInput( Input inputEvent ) {   if(inputEvt.type == IE_KEY && inputEvt.value == KEY_UP) {     //save the input state, but don't apply it     playerAvatar.joystick = KEY_UP;   }   if(inputEvt.type == IE_KEY_RELEASE) {     playerAvatar.joystick = 0;   } } void Update() {   //update the player avatar   if( playerAvatar.joystick == KEY_UP ) {     playerAvatar.y += movementSpeed;   } }

Now we know that the movement speed will be applied exactly once per game loop while the key is being held down. However, this is still frame-based logic. The problem with frame-based logic is that frames do not always happen at the same time interval. If, during a game loop, the rendering or game logic takes longer to complete than normal, it could push back the next loop. So, sometimes you will have 60 frames per second (fps), and other times, you might have only 30 fps. Because the movement is being applied per frame, sometimes you will move only half as fast as other times.

You can represent movement properly by using time-based logic instead. By keeping track of the time since the last update frame, you can apply a portion of the movement speed. In this way, you can specify a movement speed based on units per second, and no matter what the current frame rate is, the avatar’s movement will always be the same:

 void Update( long currTime ) {   long updateDT = currTime - lastUpdateTime;   //update the player avatar   if( playerAvatar.joystick == KEY_UP ) {      //since currTime is in milliseconds, we have to divide by 1000     // to get the correct speed in seconds.     playerAvatar.y += (movementSpeed * updateDT)/1000;   }   lastUpdateTime = currTime; }

In this example, the same amount of movement speed would be applied whether we had 2 fps or 60 fps. Time-based logic takes a little extra code to set up, but it allows you to be accurate regardless of temporary lag. It is certainly possible to develop a game using frame-based logic. The important thing is to avoid mixing the two. For instance, if your graphics code uses time-based logic to animate the player avatar’s sprite moving forward, but the game logic code uses frame-based logic to move the avatar forward in the game world, the walking animation is not going to sync up with the distance the player has traveled.

For some applications, time-based logic is a requirement. Networked multiplayer games, for instance, require synchronization between two clients. So, it’s absolutely necessary to use time-based logic to ensure that both clients render the same movement rate for all objects. Developers working on 3D games will notice that most physics APIs also use time-based logic for their simulations.

If you can get away with frame-based logic, do so. But thinking in terms of time-based logic will help you in the long run.

PS: À ré-écrire en français

Lien vers le commentaire
Partager sur d’autres sites

En gros, faut pas faire de sleep pour empêcher le bloc de descendre mais le soumettre à un timer.

Ton if tout en haut est trop bizarre. Je sais pas si t'as des effets de bord qui le modifient dans tes fonctions appelées dans le if, mais je ferais comme ça :

int keep_going=1;while (keep_going){// code// i=3 remplacé parkeep_going = 0;//code}
Lien vers le commentaire
Partager sur d’autres sites

En gros, faut pas faire de sleep pour empêcher le bloc de descendre mais le soumettre à un timer.

Ton if tout en haut est trop bizarre. Je sais pas si t'as des effets de bord qui le modifient dans tes fonctions appelées dans le if, mais je ferais comme ça

Non, il faut refaire la gestion des animations en gérant le temps (ce qui est le mieux). Et c'est pour cela que le code proposé est bizarre et qu'il ne faut surtout pas essayé de bricoler un truc à l'arrache :dd:

:smack:

Lien vers le commentaire
Partager sur d’autres sites

Je ne maitrise pas trop la programmation de jeu et mon C est assez rouillé. Je ne me base ici donc que sur ta description, pas ton code.

Si j'ai bien compris, tu contrôles si un appui sur une touche a été effectué ainsi que la position et l'affichage à chaque itération, en faisant à chaque fois chuter le bloc en cours d'un cran ? Si tel est bien le cas, ce que je propose, c'est que tu contrôles l'appui sur les touches plus fréquemment, permettant au final au bloc de se déplacer plus rapidement horizontalement que sa vitesse de chute.

La programmation d'un Tetris semble être un exercice extrêmement intéressant. Surtout la gestion des pièces une fois qu'elles sont en contact avec le "sol".

Si je contrôle trop fréquemment je vais rajouter des lignes de code pour ... pas grand chose ^^

Mais l'idée de Foetus d'utiliser l'heure du pc à l'air d'être très bonne (:

Je n'ai pas trop le temps de répondre, mais en gros c'est le problème du noob level 0 sur la gestion des animations.

Ton jeu a une boucle Main Loop comme cela (sûrement un timer tous les X millisecondes ou un Sleep comme ci-dessous):

while( !finished ) { handle_events(); update(); render(); sleep(20);}

Notice the sleep function here. It puts the code to sleep for some small period each loop so that it does not form a solid loop that would constantly suck up all of the time on the CPU.

Frame-based versus time-based logic

Frame-based logic updates game objects based on changes to individual frames. Timebased logic, which is more complex but more closely associated to the actual state of the game, updates game objects based on the time that has transpired. Programmers who are new to game development often make the mistake of combining frame- and time-based logic. The difference is subtle in definition, but it can cause very noticeable bugs if not handled appropriately. For example, let’s take the case of player movement. Novice programmers might write something such as this:

 void onPlayerInput( Input inputEvent ) {   if(inputEvt.type == IE_KEY && inputEvt.value == KEY_UP) {     //apply movement based on the user input     playerAvatar.y += movementSpeed;   } }

Every time the player presses a key, the avatar moves forward a set amount. This is frame-based logic because the change in movement can potentially happen with every new frame. Actually, in the current example, it will happen once per input event, which might be more or less than an iteration of the main loop. The visual impact of the move will be noticed only on the next iteration of the main loop, so any intermediate avatar movements will be wasted calculations. Let’s make the following improvement:

 void onPlayerInput( Input inputEvent ) {   if(inputEvt.type == IE_KEY && inputEvt.value == KEY_UP) {     //save the input state, but don't apply it     playerAvatar.joystick = KEY_UP;   }   if(inputEvt.type == IE_KEY_RELEASE) {     playerAvatar.joystick = 0;   } } void Update() {   //update the player avatar   if( playerAvatar.joystick == KEY_UP ) {     playerAvatar.y += movementSpeed;   } }

Now we know that the movement speed will be applied exactly once per game loop while the key is being held down. However, this is still frame-based logic. The problem with frame-based logic is that frames do not always happen at the same time interval. If, during a game loop, the rendering or game logic takes longer to complete than normal, it could push back the next loop. So, sometimes you will have 60 frames per second (fps), and other times, you might have only 30 fps. Because the movement is being applied per frame, sometimes you will move only half as fast as other times.

You can represent movement properly by using time-based logic instead. By keeping track of the time since the last update frame, you can apply a portion of the movement speed. In this way, you can specify a movement speed based on units per second, and no matter what the current frame rate is, the avatar’s movement will always be the same:

 void Update( long currTime ) {   long updateDT = currTime - lastUpdateTime;   //update the player avatar   if( playerAvatar.joystick == KEY_UP ) {      //since currTime is in milliseconds, we have to divide by 1000     // to get the correct speed in seconds.     playerAvatar.y += (movementSpeed * updateDT)/1000;   }   lastUpdateTime = currTime; }

In this example, the same amount of movement speed would be applied whether we had 2 fps or 60 fps. Time-based logic takes a little extra code to set up, but it allows you to be accurate regardless of temporary lag. It is certainly possible to develop a game using frame-based logic. The important thing is to avoid mixing the two. For instance, if your graphics code uses time-based logic to animate the player avatar’s sprite moving forward, but the game logic code uses frame-based logic to move the avatar forward in the game world, the walking animation is not going to sync up with the distance the player has traveled.

For some applications, time-based logic is a requirement. Networked multiplayer games, for instance, require synchronization between two clients. So, it’s absolutely necessary to use time-based logic to ensure that both clients render the same movement rate for all objects. Developers working on 3D games will notice that most physics APIs also use time-based logic for their simulations.

If you can get away with frame-based logic, do so. But thinking in terms of time-based logic will help you in the long run.

PS: À ré-écrire en français

Merci je vais essayer :D

J'ai mis 10 minutes à comprendre le truc mais perso', j'aurais jamais trouvé tout seul !

En gros, faut pas faire de sleep pour empêcher le bloc de descendre mais le soumettre à un timer.

Ton if tout en haut est trop bizarre. Je sais pas si t'as des effets de bord qui le modifient dans tes fonctions appelées dans le if, mais je ferais comme ça :

int keep_going=1;while (keep_going){// code// i=3 remplacé parkeep_going = 0;//code}

En gros j'ai un tableau qui représente les diffèrentes positions possible des blocs des formes donc je compare si les valeurs dans le tableau pour savoir si la forme peut continuer de descendre

En gros, faut pas faire de sleep pour empêcher le bloc de descendre mais le soumettre à un timer.

Ton if tout en haut est trop bizarre. Je sais pas si t'as des effets de bord qui le modifient dans tes fonctions appelées dans le if, mais je ferais comme ça

Non, il faut refaire la gestion des animations en gérant le temps (ce qui est le mieux). Et c'est pour cela que le code proposé est bizarre et qu'il ne faut surtout pas essayé de bricoler un truc à l'arrache :dd:

:smack:

Haha !

J'assume mon noob level 0 x)'

C'est la première fois que je code ce genre de chose car j'avais déjà coder un truc mais en faites, je ne déplaçais pas de 30 px par 30 px donc la vitesse de calcul du processeur suffisait largement ! (enfin à ce que m'avait dit le prof après ... hum hum)

Lien vers le commentaire
Partager sur d’autres sites

Juste une petite question, si on veut faire les animations par exemple toutes les 0.75 secondes, on fait comment ... ?

Car si je compare les secondes à 0.75 bah c'est fail ... x)'

En tout les cas, ça fonctionne nickel !

Juste à règler les touches ...

Merci !

Lien vers le commentaire
Partager sur d’autres sites

En fait, cela dépend fortement du comment c'est fait.

Pour une application iPhone ou Android ( :transpi: ), on va créer un timer qui va se déclencher toutes les X millisecondes pour exécuter ceci:

 handle_events(); update(); render();

Sinon, un Sleep va être dépendant du nombre de frames :siffle:

Lien vers le commentaire
Partager sur d’autres sites

Et il n'y aurait pas un moyen de pouvoir obtenir les millisecondes sur PC ? (Windows)

Et juste aussi, la fonction de time.h pour obtenir les secondes, elle s'utilise aussi sur Linux ?

Car actuellement je récupère les secondes mais c'est pas interressant car au niveau 1, je met déjà un timer de 1 seconde

Donc si je passe au niveau 2, je le met comment a 0.75 ? ou alors je le met à 0 ... x)'

Lien vers le commentaire
Partager sur d’autres sites

Là, il faut plus d'informations. Formulaire à répondre:

1) Langage utilisé: C

2) Compilateur/ ide utilisé: Code blocks

3) OS (plusieurs choix): Windows 7/XP/Vista

4) Librairie de temps utilisée: time.h

5) Bout de code pour créer le timer:

   time_t currTime;   time_t lastTime,diff;currTime=time (NULL);lastTime=time(NULL);diff=lastTime-currTime;//Je sais que j'utilise une variable en trop !

:windu:

(=

Lien vers le commentaire
Partager sur d’autres sites

Trouvé sur stackoverflow, du beau code Windows :mad2::mad2::mad2::mad2:

#include <windows.h>double PCFreq = 0.0;__int64 CounterStart = 0;void StartCounter(){   LARGE_INTEGER li;   if(!QueryPerformanceFrequency(&li))       cout << "QueryPerformanceFrequency failed!\n";   PCFreq = double(li.QuadPart)/1000.0;   QueryPerformanceCounter(&li);   CounterStart = li.QuadPart;}double GetCounter(){   LARGE_INTEGER li;   QueryPerformanceCounter(&li);   return double(li.QuadPart-CounterStart)/PCFreq;}int main(){   StartCounter();   Sleep(1000);   cout << GetCounter() <<"\n";   return 0;}

Et documentation (mais Windows/ Microsoft) sur les Timers avec des bouts de code

Lien vers le commentaire
Partager sur d’autres sites

Merci beaucoup !

Du coup en cherchant comment utiliser les diffèrentes fonctions (je crois la gettickcount exactement) je suis tombé sur la fonction clock() qui fonctionne nickel et simplement

Pour ceux qui voudrait savoir comment l'utiliser, la voici pour avoir le temps d'éxecution d'une instruction en millisecondes :

clock_t debut,fin;int tempsDExecution; //Je ne suis pas sur que ce soit un integer qu'il faut là !debut=clock();//instructionsfin=clock();tempsDExecution=fin-debut;

Plus qu'à le finir avant demain !

Désolé du message précédent mais je ne l'ai pas vu oO Abuser o_O

Mais du coup comme ça, la fonction clock(); fonctionne sur Linux aussi (:

Lien vers le commentaire
Partager sur d’autres sites

Archivé

Ce sujet est désormais archivé et ne peut plus recevoir de nouvelles réponses.

×
×
  • Créer...