메인 루프를 중단하지 않고 C의 입력을 어떻게 처리 할 수 ​​있습니까?

Dec 16 2020

내 C 프로그램이 매초마다 콘솔을 업데이트하기를 원하며 입력을 처리하려고 할 때까지 제대로 작동했습니다. 이제 프로그램은 사용자의 입력을 기다리기 때문에 중지됩니다. 어떻게 할 수 있습니까?

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

답변

1 Vaillancourt Dec 17 2020 at 08:32

나는이 문제를 스스로 해결할 자유를 얻었다.

질문 텍스트만으로는 어떤 종류의 게임을하려고하는지 명확하지 않기 때문에 플레이어가 무엇을하든하지 않든, 뱀이 어디로 이동할 것인가 하는 일종의 스네이크 게임에 접근했습니다. .

내가 사용하는 Sleep입력 폴링 및 다시 그리기 속도를 속도를 조절하고, _kbhit()어쩌면 문자를 읽고, 그리고 clock_t/ clock()초당 한 번 게임을 업데이트 할 수 있습니다.

이제 저는 c프로그래머가 아니기 때문에이 c코드가 "우아한"지 (아마도 그렇지 않은지) 모르겠지만 내 컴퓨터 (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;
}

몇 가지 유의할 사항 :

  • 이 작업을 수행하는 다른 (더 나은) 방법이있을 수 있습니다. 현재로서는 (ClearScreen)을 새로 고치면 화면이 약간 "깜빡입니다".
  • Windows에서 OS는 앱에 보내는 문자의 반복 속도를 "빠르게"하므로 d예를 들어를 누르면 프로그램이를 치고 d있음을 표시 한 다음 키를 누르지 않음을 표시합니다. 그러면 d키를 놓을 때까지 다시 치는 것을 보여줍니다 .
  • 자신의 구현과 마찬가지로 사용되는 기능의 특성으로 인해 이식 할 수 없습니다.
AliTeo Dec 16 2020 at 05:28

이식 불가능한 코드를 사용해야했지만 타사 라이브러리 없이도 작동하도록했습니다. 또한 _kbhit () 함수가 버퍼를 지연 시키므로 전체 문자열을 입력하기 위해 1 초 동안 기다릴 필요가 없습니다. 그러나 1 초 안에 쓰여지지 않으면 쓰여진 문자열이 잘리고있었습니다. 그래서 ShowConsole () 함수에서도 보여주었습니다.

참고 : 이것은 비표준적이고 이식 불가능한 코드입니다. 내 OS (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++;
    }

ShowConsole () 함수에서 :

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