在可能接受输入时继续执行循环

时间:2015-11-26 18:45:25

标签: c

我正在尝试在C中制作一个简单的俄罗斯方块游戏。我已经进入输入部分并遇到麻烦。我制作了一个循环,每秒都会将新作品向下移动。现在我希望这种情况发生,但我希望玩家能够按下按钮来移动棋子,当然这也是游戏的目标。这两件事不应该干涉。游戏循环是

  for (i=1;i<100;i++)
  {
    printBoard(&current);
    if (move(&current))
      spawn(&current);

    sleep(1);
  }

这里函数移动,将下降块向下移动一个单位,如果块击中地面或另一个块则返回1,在这种情况下,通过spawn函数生成新块。 printboard只是将电路板打印到终端。这样做的最佳方式是什么?

提前致谢

为完整起见,这是目前为止的完整代码

#include <stdio.h>
#include <math.h>

#define height 20
#define width 15

typedef struct board{
  int x[height][width];
  int score;
} board;

void printBoard(board * current){
  int i,j;
  for (i=0;i<40;i++)
    printf("\n");

  printf("Score : %d\n", current->score);

  for (i=0;i<height-1;i++)
  {
    printf("|");
    for (j=0;j<width;j++)
    { 
      if (current->x[i][j] == 0)
        printf(" ");
      else
        printf("x");
    }
    printf("|\n");
  }
  for (i=0;i<width+2;i++)
    printf("T");

  printf("\n");
}

void spawn(board * current){
  current->x[0][4] = 2;
  current->x[1][4] = 2;
  current->x[1][5] = 2;
  current->x[1][6] = 2;
  current->x[1][7] = 2;
}

int move(board * current){ // returns 1 if block hits ground
  int i,j;
  for (i=(height-1);i>0;i--)
    for (j=0;j<width;j++)
      if (current->x[i-1][j] == 2){
        if (i==(height-1) || current->x[i][j] == 1){
          goto DONE;
        }
        current->x[i][j] = 2;
        current->x[i-1][j] = 0;
      }


  return 0;

  DONE: 
  for (i=0;i<height;i++)
    for (j=0;j<width;j++)
      if (current->x[i][j] == 2)
        current->x[i][j] = 1;
      return 1;
}


int main(){
  board current;
  current.score = 0;
  int i,j;
  for (i=0;i<height;i++)
    for (j=0;j<width;j++)
      current.x[i][j] = 0;


  spawn(&current);
  for (i=1;i<100;i++)
  {
    printBoard(&current);
    if (move(&current))
      spawn(&current);

    sleep(1);
  }
  return 0;
}

2 个答案:

答案 0 :(得分:1)

通常的做法是依靠poll()或select()调用。

这个想法是在select调用上设置超时(因为你将是1秒)并在超时发生时执行标准刷新。

通过文件描述符检索用户输入(这里我猜它会是stdin,因此为0),每次用户按下一个按钮时,select退出但是这次,fd被标记为有输入,因此你只需阅读输入并处理您刚读过的内容。然后再次在select()

中等待

伪代码看起来像(从选择人那里获取):

   int main(void)
   {
       fd_set rfds;
       struct timeval tv;
       int retval;

       /* look stdin (fd 0) for inputs */
       FD_ZERO(&rfds);
       FD_SET(0, &rfds);

       /* wait 1 second. */
       tv.tv_sec = 1;
       tv.tv_usec = 0;

       retval = select(1, &rfds, NULL, NULL, &tv);
       /* Carefull tv was updated (on linux) */

       if (retval == -1)
           perror(" an error occured");
       else if (retval == 1) {
           printf("Data is available on stdin \n");
           /* FD_ISSET(0, &rfds) should be true */
           handle_input();
       } else {
           printf("Timeout.\n");
          update_status();
       }
       exit(EXIT_SUCCESS);
   }

答案 1 :(得分:1)

在* nix上,您可以将intput filedescriptor设置为非阻塞模式。 然后,您可以在每个刷新间隔尝试读取,并且EAGAIN成功或失败(假设没有错误):

#include <unistd.h>        
#include <fcntl.h>
//...
fcntl(0 /*==stdin*/, F_SETFL, O_NONBLOCK); 

如果您的输入是终端,则还需要禁用终端线路缓冲(例如,如果您链​​接cbreak(),则使用ncurses。)

select和家人如果除了等待输入之外别无其他事可做其他事情。在这种情况下循环会浪费其他进程可以使用的CPU时间。