Comment puis-je gérer l'entrée en C sans interrompre la boucle principale?

Dec 16 2020

Je veux que mon programme C mette à jour la console toutes les secondes, et cela fonctionnait bien jusqu'à ce que j'essaye de gérer les entrées. Maintenant, le programme s'arrête car il attend une entrée de l'utilisateur. Comment puis-je faire ceci?

while(true) {
    ShowConsole();  //Show
    Sleep(1000);        //Wait
    scanf("%s",&a)      //Handle Input  
    Update();
    ClearScreen();      //Clear
}

Réponses

1 Vaillancourt Dec 17 2020 at 08:32

J'ai pris la liberté d'essayer de résoudre ce problème moi-même.

Uniquement basé sur le texte de la question, le type de jeu que vous essayez de faire n'est pas très clair, j'ai donc adopté une sorte de jeu de serpent , où le serpent se déplacera, quoi que le joueur fasse (ou ne fasse pas) .

Je Sleepà arpenter les sondages d'entrée et le taux de rafraîchissement et _kbhit()de peut - être lu un caractère, et clock_t/ clock()mettre à jour le jeu une fois par seconde.

Maintenant, je ne suis pas cprogrammeur, donc je ne sais pas si ce ccode est "élégant" (ce n'est probablement pas le cas), mais il a fonctionné sur ma machine (Windows, Visual Studio).

#include <stdio.h>
#include <conio.h>
#include <time.h>
#include <ctype.h>
#include <windows.h>

typedef int BOOL;
#define FALSE ((int)0)
#define TRUE ((int)1)

void ClearScreen()
{
  // code here that clears the screen, see https://stackoverflow.com/a/42500322
}

int main( void )
{
  BOOL run = TRUE;

  clock_t lastTickClock = clock();
  int position = 0;

  char registeredCommand = 'd'; // Command that will be effective at the next game tick.
  while ( run )
  {
    char currentCharIfAny = 0; // The char that is read this loop.
    if ( _kbhit() )
      currentCharIfAny = _getch();

    if ( currentCharIfAny == 'a' || currentCharIfAny == 'd' )
      registeredCommand = currentCharIfAny; // We only respond to 'a' or 'd'.

    clock_t newClock = clock();
    if ( ( newClock - lastTickClock ) > CLOCKS_PER_SEC )
    {
      // This is the command handling/the game tick
      if ( registeredCommand == 'a' )
        position = max( --position, 0 );
      else if ( registeredCommand == 'd' )
        position = min( ++position, 24 );

      lastTickClock = newClock;
    }

    char buffer[1024];
    buffer[0] = 0;

    for ( int i = 0; i < position; ++i )
      strcat_s( buffer, 1024, " " );
    strcat_s( buffer, 1024, "_\n" ); // This underscore represents our "agent" or "game token" or "paddle".

    // The following is only for debugging purpose; it prints the character we're currently handling. 
    if ( currentCharIfAny >= 'a' && currentCharIfAny <= 'z' )
    {
      char lbuff[2]; lbuff[0] = 0;
      sprintf_s( lbuff, 2, "%c", currentCharIfAny );
      strcat_s( buffer, 1024, lbuff );
    }

    ClearScreen();
    printf( "%s\n", buffer );
    Sleep( 1000 / 60 );
    if ( currentCharIfAny == 'q' )
      run = FALSE;
  }

  printf( "\ndone. press a key to quit." );
  _getch();
  return 0;
}

Quelques points à noter:

  • il y a probablement d'autres (meilleures) façons d'y parvenir: pour l'instant, lorsque je rafraîchis (ClearScreen), l'écran «scintille» un peu.
  • sous Windows, le système d'exploitation "rythmera" le taux de répétition du caractère qu'il envoie aux applications, donc lorsque vous appuyez sur, dpar exemple, le programme montrera que vous appuyez d, puis il montrera que vous n'appuyez sur aucune touche, puis cela montrera que vous frappez à dnouveau, jusqu'à ce que vous relâchiez la touche.
  • comme votre propre implémentation, elle n'est pas portable en raison de la nature des fonctions utilisées.
AliTeo Dec 16 2020 at 05:28

Bien que je devais utiliser du code non portable, je l'ai fait fonctionner sans avoir besoin d'une bibliothèque tierce. En outre, il s'avère que la fonction _kbhit () retarde le tampon de sorte que vous n'avez pas besoin d'attendre 1 seconde pour entrer la chaîne complète. Cependant, la chaîne écrite était coupée si elle n'est pas écrite en une seconde. Donc je l'ai également montré dans la fonction ShowConsole ().

Remarque: il s'agit d'un code non standard et non portable. Fonctionne dans mon système d'exploitation (Windows).

char key;
    if(_kbhit()){
        key = _getch();
        if(key == 13){                  //If Enter key is pressed
            HandleInput(moveInput);     //handle the input string
            memset(moveInput, 0, 6);    //clear input string
            moveIndex=0;                //reset string index to 0
        }
        moveInput[moveIndex] = key;     //If any other key is pressed, add the hit character to string input
        moveIndex++;
    }

Dans la fonction ShowConsole ():

ShowConsole(){
    .
    .
    .
    printf("%s", moveInput); // At the end of showing the graphics, also show the input that is being written.
}