Como posso controlar a entrada em C sem interromper o loop principal?

Dec 16 2020

Quero que meu programa C atualize o console a cada segundo e estava funcionando bem até que tentei controlar a entrada. Agora o programa é interrompido, pois espera uma entrada do usuário. Como posso fazer isso?

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

Respostas

1 Vaillancourt Dec 17 2020 at 08:32

Tomei a liberdade de tentar resolver isso sozinho.

Com base exclusivamente no texto da pergunta, não está muito claro que tipo de jogo você está tentando fazer, então usei a abordagem de um tipo de jogo de cobra , onde a cobra se moverá, o que quer que o jogador esteja fazendo (ou não) .

Eu costumava Sleepa andar a votação de entrada ea taxa de redesenho, e _kbhit()para talvez ler um personagem, eo clock_t/ clock()a atualizar o jogo uma vez por segundo.

Agora não sou um cprogramador, então não sei se este ccódigo é "elegante" (provavelmente não é), mas funcionou na minha máquina (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;
}

Algumas coisas a serem observadas:

  • provavelmente existem outras (melhores) maneiras de fazer isso: por enquanto, quando eu atualizo (ClearScreen), a tela "pisca" um pouco.
  • no Windows, o sistema operacional "acompanhará" a taxa de repetição do caractere que envia para os aplicativos, então quando você apertar, dpor exemplo, o programa mostrará que você está apertando d, então mostrará que você não está apertando nenhuma tecla, então ele mostrará que você está batendo dnovamente, até que você solte a tecla.
  • como sua própria implementação, não é portátil devido à natureza das funções usadas.
AliTeo Dec 16 2020 at 05:28

Embora eu tenha que usar um código não portátil, consegui fazê-lo funcionar sem a necessidade de uma biblioteca de terceiros. Além disso, a função _kbhit () atrasa o buffer, então você não precisa esperar 1 segundo para inserir a string completa. No entanto, a string escrita estava sendo cortada se não fosse escrita em um segundo. Então, eu também mostrei na função ShowConsole ().

Nota: Este é um código não padronizado e não portátil. Funciona no meu SO (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++;
    }

Na função ShowConsole ():

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