Pourquoi getch () ne lit-il pas le dernier caractère saisi?

J’écris un jeu de serpent en C en utilisant la bibliothèque ncurses , où l’écran se met à jour toutes les secondes. Comme le savent ceux qui ont joué au jeu, si l’utilisateur entre plusieurs touches ou maintient une touche enfoncée longtemps, il ne doit y avoir aucune pression sur une touche ‘mise en mémoire tampon‘ qui soit enregistrée. En d’autres termes, si j’appuie sur w (la touche haut) et que stdin reçoit une séquence de 20 w s, puis que je saisis un d (la touche droite), j’attends du serpent qu’il se mette immédiatement à droite et ignore la mise en mémoire tampon. w s.

J’essaie d’y parvenir en utilisant la fonction ncurses getch() , mais pour une raison quelconque, getch() l’effet indésirable que je viens de décrire; à savoir que toutes les pressions longues sont stockées et traitées en premier, avant de considérer la dernière touche enfoncée, comme l’illustre ce MWE:

 #include  #include  #include  int main(){ char c = 'a'; initscr(); cbreak(); noecho(); for(;;){ fflush(stdin); timeout(500); c = getch(); sleep(1); printw("%c", c); } return 0; } 

Est-il possible de modifier ce code pour que getch() ignore tout texte mis en mémoire tampon? Le fflush() juste avant ne semble pas aider.

    Tout d’abord la réponse à votre question immédiate: même lorsque vous lisez stdin un caractère à la fois, vous ne voulez normalement pas en manquer un. Si getch() ne fait que renvoyer le caractère entré en dernier, les routines d’entrée utilisant getch() deviendraient très peu fiables.

    Même dans un jeu de serpent, vous voulez que tous les personnages soient entrés. Imaginez que le serpent se déplace vers la droite et que le joueur veuille faire un “demi-tour” en descendant puis tout de suite à gauche . Si votre jeu ne captait que le dernier personnage, le serpent irait directement à gauche et se tuerait ainsi. Une expérience de jeu assez frustrante;)

    La solution à votre problème est simple: faites interroger votre boucle de jeu beaucoup plus souvent que le déplacement du serpent et maintenez une queue des changements de direction demandés. Je l’ai fait dans mon jeu de serpent à base de malédictions .

    Voici le code correspondant à la boucle de jeu:

     typedef enum { NONE, LEFT, DOWN, RIGHT, UP } Dir; // [...] ticker_start(10); while (1) { screen_refresh(screen); ticker_wait(); key = getch(); if (key == 'q' || key == 'Q') { // quit game } switch (key) { case KEY_LEFT: snake_setDir(snake, LEFT); break; case KEY_DOWN: snake_setDir(snake, DOWN); break; case KEY_UP: snake_setDir(snake, UP); break; case KEY_RIGHT: snake_setDir(snake, RIGHT); break; case ' ': // pause game break; } if (!--nextStep) { step = snake_step(snake); // move the snake // code to check for food, killing, ... } if (!--nextFood) { // add a new food item } } ticker_stop(); 

    Et voici comment le serpent implémente et utilise la queue:

     struct snake { // queue of requested directions: Dir dir[4]; // more properties }; void snake_setDir(Snake *self, Dir dir) { int i; Dir p; p = self->dir[0]; for (i = 1; i < 4; ++i) { if (self->dir[i] == NONE) { if (dir != p) self->dir[i] = dir; break; } p = self->dir[i]; } } static void dequeueDir(Snake *self) { int i; if (self->dir[1] != NONE) { for (i=0; i<3; ++i) self->dir[i] = self->dir[i+1]; self->dir[3] = NONE; } } Step snake_step(Snake *self) { dequeueDir(self); // [...] switch (self->dir[0]) { case LEFT: --newHead->x; break; case DOWN: ++newHead->y; break; case RIGHT: ++newHead->x; break; case UP: --newHead->y; break; default: break; } // [...] } 

    Bonne chance avec votre jeu!

    J’ai fait d’autres recherches et découvert que:

    La routine flushinp() supprime toute tête de frappe tapée par l’utilisateur et non encore lue par le programme.

    Cela a résolu mon problème.

    Source: https://linux.die.net/man/3/flushinp

    le code proposé suivant montre comment ignorer tout sauf la dernière clé entrée.

     #include  #include  #include  int main( void ) { char c = ' '; char lastKey; initscr(); cbreak(); noecho(); for(;;) { timeout(500); while( (c = getch()) != EOF ) { lastKey = c; } sleep(1); if( EOF == c ) { printw("%c", lastKey); } } return 0; }