2015-11-26 76 views
1

我想在C中做一個簡單的俄羅斯方塊遊戲。我來到輸入部分,遇到了麻煩。我製作了一個循環,每秒鐘都會將新片移動。現在我希望這種情況發生,但我希望玩家能夠按下一個按鈕來移動棋子,當然這也是遊戲的目標。這兩件事不應該干涉。遊戲循環是繼續執行循環,同時有可能採取輸入

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

    sleep(1); 
    } 

這裏函數移動,移動下降的塊向下一個單元,並返回1,如果該塊撞到地面或另一片在這種情況下,新的塊經由產卵功能衍生。印刷板只是將板打印到終端。做這個的最好方式是什麼?

在此先感謝

爲了完整起見,這裏是完整的代碼到目前爲止

#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; 
} 

回答

1

通常的方式做到這一點是依靠民意調查()或select()調用。

這個想法是在select調用中設置一個超時(因爲你會是1秒),並在發生超時時執行標準刷新。

用戶輸入通過文件描述符(在這裏我猜它是stdin,因此是0),每次用戶按下按鈕時,select都退出,但這次fd被標記爲有輸入,因此你只需要閱讀輸入內容並對待你剛纔閱讀的內容。而在選擇()

僞代碼去等待再次會是什麼樣子(採取從選擇人):

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

在* nix,您可以將intput文件描述符設置爲非阻塞模式。 然後你可以在每次刷新間隔嘗試讀取,它會成功或失敗,EAGAIN(假設沒有錯誤):

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

如果你的輸入是終端,您還需要禁用終端行緩衝(例如,如果鏈接ncurses,則使用cbreak())。

select和家庭是有用的,如果你沒有什麼別的事情不等待輸入。在這種情況下循環會浪費其他進程可以使用的CPU時間。