我正在尝试在C中制作一个简单的俄罗斯方块游戏。我已经进入输入部分并遇到麻烦。我制作了一个循环,每秒都会将新作品向下移动。现在我希望这种情况发生,但我希望玩家能够按下按钮来移动棋子,当然这也是游戏的目标。这两件事不应该干涉。游戏循环是
for (i=1;i<100;i++)
{
printBoard(¤t);
if (move(¤t))
spawn(¤t);
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(¤t);
for (i=1;i<100;i++)
{
printBoard(¤t);
if (move(¤t))
spawn(¤t);
sleep(1);
}
return 0;
}
答案 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时间。