【C语言】之实现俄罗斯方块游戏
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                【C语言】之实现俄罗斯方块游戏
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                實現思路:
關鍵點是使用鬧鐘信號,鬧鐘定時一段時間觸發信號函數,在信號函數里對方塊進行自動下落操作,而主線控制界面顯示以及處理用戶的輸入。
共有兩個文件 main.c 和 data.h,需要把兩個文件放到同一目錄下,直接在該目錄下執行命令:
gcc main.c -o main注意:如果編譯的時候提示沒有或者找不到 data.h 這個文件的話:
- 1、確保兩個文件是在同一路徑下并檢查 data.h 這個文件的命名是否正確(有時候你的data.h后面可能多了個空格或者其它空白字符)導致這個文件找不到;
- 2、實在是解決不了的話,直接把 data.h 里面的數據復制到 main.c 文件的 #include "data.h" 下面并去掉 #include "data.h" 這句代碼
提示:如果中途遇到問題,可以留言評論,我有時間上線看到之后會回復大家的疑惑(但我的空閑時間有限,并不是所有問題都會回復,代碼一定是完整、可以正常運行的,至于自己的電腦為什么起不來,就需要自己學會找一下問題了),同時也希望大家看完后認真學習一下代碼的思路(代碼里面的注釋已經非常詳細了),只有這樣大家才能有所進步!
代碼:
main.c (這是主程序,需要用到下面的 data.h 文件)
/** 文件名稱: main.c* 功能:實現俄羅斯方塊小游戲* 編寫人:王廷云 */ #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <sys/time.h> #include <time.h> #include <unistd.h> #include "data.h"#define ROW 21 // 游戲區域的行數 #define COL 18 // 游戲區域的列數/* 按鍵枚舉 */ enum key {DOWN, // 上LEFT, // 左RIGHT, // 右CHANGE, // 變化STOP, // 停止EXIT, // 退出UNKNOW, // 未知 };/***** 函數聲明區域 ******/ void initalGameArea(void); // 初始化游戲區域 void drawBlock(char bl[NR][NR]); // 畫方塊 void cleanBlock(char bl[NR][NR]); // 清除方塊 void turnBlock(char bl[NR][NR]); // 旋轉方塊 void gameEnd(void); // 結束游戲 void gameStop(void); // 暫停游戲 void showGame(void); // 顯示游戲 void gameSelf(int signo); // 游戲自動運行 void checkDeleteLine(void); // 檢查是否滿一行 void checkGameOver(char bl[NR][NR]); // 檢查是否游戲結束 int checkMove(char bl[NR][NR], int flag); // 檢查方塊是否可移動 int getInput(void); // 獲取輸入/* 全局變量區域 */ static char gameArea[ROW][COL] = {0}; // 游戲區域數據 static int startX = 7, startY = 6; // 方塊出現的起始位置 static int type = 0; // 方塊當前類型 static int nextType = 0; // 方塊的下一種類型 static int diret = 0; // 方塊的方向 char *state = "\033[32m游戲中...\033[0m"; // 游戲運行狀態 static unsigned int level = 0; // 游戲等級 static unsigned int score = 0; // 游戲分數 static unsigned int maxScore = 0; // 游戲最高記錄 static FILE *fp = NULL; // 用于把記錄保存到文件/** 主函數:控制全局流程 */ int main(void) {/** 設置鬧鐘:* 當前時間間隔為0.7秒,下一次時間間隔為0.7秒*/struct itimerval timer = {{0,700000},{0,700000}};setitimer(ITIMER_REAL, &timer,NULL);/* 初始化游戲區域 */initalGameArea();/* 設置游戲信號 */signal(SIGALRM, gameSelf);/* 初始化方塊類型 */srand(time(NULL));type = rand()%7;nextType = rand()%7;/* 讀取文件的最高記錄 */fp = fopen("./record","r+");if (NULL == fp){/** 文件不存在則創建并打開 * "w"方式打開會自動創建不存在的文*/fp = fopen("./record","w");}fscanf(fp,"%u",&maxScore);/* 用戶操作 */int key;while (1){key = getInput();switch (key){case RIGHT : checkMove(bl[type][diret],RIGHT);break;case LEFT : checkMove(bl[type][diret],LEFT);break;case DOWN : checkMove(bl[type][diret],DOWN);break;case CHANGE: turnBlock(bl[type][(diret+1)%4]);break;case STOP : gameStop();break;case EXIT : gameEnd();break;case UNKNOW: continue;}/* 畫方塊 */drawBlock(bl[type][diret]);/* 顯示游戲 */showGame();/* 清除方塊 */cleanBlock(bl[type][diret]);}return 0; }/** 函數名:initalGameArea* 函數功能:初始化游戲區域* 參數:無* 返回值:無 */ void initalGameArea(void) {int i;/* 屏幕設置 */printf("\033[2J"); // 清屏system("stty -icanon"); // 關緩沖system("stty -echo"); // 關回顯fprintf(stdout,"\033[?25l"); // 關閉鼠標顯示/* 初始化行 */for (i = 0; i < COL; i++){gameArea[0][i] = 8; // 第0行gameArea[5][i] = 8; // 第5行gameArea[ROW-1][i] = 8; // 最后一行}/* 初始化列 */for (i = 0; i < ROW; i++){gameArea[i][0] = 8; // 第0列gameArea[i][COL-1] = 8; // 最后一列}/* 中間一小列 */for (i = 1; i < 5; i++){gameArea[i][6] = 8;} }/** 函數名:gameSelf* 函數功能:作為信號函數,鬧鐘時間一到就自動下落* 參數:信號* 返回值:無 */ void gameSelf(int signo) {/* 畫方塊 */drawBlock(bl[type][diret]);/* 顯示游戲 */showGame();/* 清除方塊 */cleanBlock(bl[type][diret]);/* 如果方塊已經到底 */if (!checkMove(bl[type][diret],DOWN)){/* 檢查是否游戲結束 */checkGameOver(bl[type][diret]);/* 保留已經到底的方塊 */drawBlock(bl[type][diret]);/* 顯示游戲結果 */showGame();/* 到達邊界后檢查是否可消行 */checkDeleteLine();/* 重新開始下一個方塊 */startY = 6;startX = 7;type = nextType;nextType = rand()%7;diret = 0;} }/** 函數名:checkDeleteLine* 函數功能:檢查是否可消行* 參數:無* 返回值:無 */ void checkDeleteLine(void) {int i, j;int x, y;/* 檢查當前方塊的四行區域內 */for (i = 3; i >= 0; i--){for (j = 1; j < COL-1; j++){/* 檢測方塊是否滿一行 */if (gameArea[startY+i][j] == 0)break;/* 跳過邊框區域 */else if (gameArea[startY+i][j] == 8)break;}/* 如果滿了一行則刪除一行 */if (j == COL-1){/* 刪除滿了的一行 */for (j = 1; j < COL-1; j++){gameArea[startY+i][j] = 0;}/* 分數累加 */score += 100;/* 記錄最高分 */if (score > maxScore){maxScore = score;/* 保存最高分 */rewind(fp);fprintf(fp,"%u\n",maxScore);}/* 記錄級別 */if (score%200 == 0){/* 每200分加一級 */level++;}/* 刪除后往下移動一行 */for (x = 1; x < COL-1; x++){for (y = startY+i; y >= 7; y--){gameArea[y][x] = gameArea[y-1][x];}}/* 移動的一行需要檢測范圍加一行 */i++;}} }/** 函數名:checkGameOver* 函數功能:檢查游戲是否結束* 參數:待檢查方塊數據數據* 返回值:無 */ void checkGameOver(char block[NR][NR]) {int i;for (i = 0; i < NR; i++){/* 方塊碰到上方邊界則游戲結束 */if (block[0][i] != 0 && gameArea[startY-1][startX+i] == 8){gameEnd();}} }/** 函數名:turnBlock* 函數功能:旋轉方塊* 參數:需要旋轉的方塊數組數據* 返回值:無 */ void turnBlock(char bl[NR][NR]) {int x, y;/* 檢查是否越界 */for (y = 0; y < NR; y++){for (x = 0; x < NR; x++){/* 只能判斷到達了邊界 */if (bl[y][x] != 0 && gameArea[startY+y][startX+x] != 0){return;}}}/* 兩邊都沒有越界則旋轉方塊方向 */diret = (diret+1)%4; }/** 函數名:gameStop* 函數功能:暫停游戲,等待用戶再次啟動游戲* 參數:無* 返回值:無 */ void gameStop(void) {/* 創建一個暫停的是時鐘 */struct itimerval stop = {0}, older;/* 設置新鬧鐘并存儲舊鬧鐘 */setitimer(ITIMER_REAL,&stop,&older);/* 配置暫停后的界面 */state = "\033[31m暫停中...\033[0m";startY--; // 為了防止按下暫停鍵后方塊下滑一格drawBlock(bl[type][diret]);showGame();cleanBlock(bl[type][diret]);/* 等待用戶按開始鍵或退出鍵 */int key;while (1){key = fgetc(stdin);/* 空格開始 */if (key == ' ')break;/* q 退出 */else if (key == 'q')gameEnd();}/* 恢復鬧鐘和游戲 */setitimer(ITIMER_REAL,&older,NULL);state = "\033[32m游戲中...\033[0m"; }/** 函數名:checkMove* 函數功能:檢查方塊是否可移動,能移則移* 參數:1.方塊數組數據 2.方向標志位* 返回值:可移動返回1,不能移動返回0 */ int checkMove(char bl[NR][NR], int flag) {int m, n; // 用于標明可移動方向int x, y; // 用于循環switch (flag){case RIGHT : n = 0; m = 1; break;case LEFT : n = 0; m = -1; break;case DOWN : n = 1; m = 0; break;}/* 全局檢查 */for (y = 0; y < NR; y++){for (x = 0; x < NR; x++){/* 只能判斷到達了邊界 */if (bl[y][x] != 0 && gameArea[startY+y+n][startX+x+m] != 0){return 0;}}}/* 出來說明沒有到達邊界 */startY += n;startX += m;return 1; }/** 函數名:getInput* 函數功能:獲取用戶輸入* 參數:無* 返回值:無 */ int getInput(void) {char key;key = fgetc(stdin);if (key == '\033' && fgetc(stdin) == '[') // 方向鍵{switch (fgetc(stdin)){case 'A': return CHANGE; // ↑ 方向鍵變換方塊形狀case 'B': return DOWN; // ↓ 方向鍵加速下落case 'C': return RIGHT; // → 方向鍵右移case 'D': return LEFT; // ← 方向鍵左移}}else if (key == 'q') // 退出鍵{return EXIT;}else if (key == ' ') // 空格鍵-暫停游戲{return STOP;}else // 其它不相關的鍵return UNKNOW; }/** 函數名:drawBlock* 函數功能:填充方塊數據* 參數:方塊數組數據* 返回值:無 */ void drawBlock(char block[NR][NR]) {int x, y;/* 畫當前方塊 */for (y = 0; y < NR; y++){for (x = 0; x < NR; x++){if (block[y][x] != 0){gameArea[startY+y][startX+x] = block[y][x];}}}/* 畫提示的下一個方塊 */for (x = 0; x < 2; x++){for (y = 0; y < NR; y++){if (bl[nextType][0][x][y] != 0)gameArea[3+x][2+y] = bl[nextType][0][x][y];elsegameArea[3+x][2+y] = 0;}} }/** 函數名:cleanBlock* 函數功能:清除方塊數據* 參數:方塊數組數據* 返回值:無 */ void cleanBlock(char bl[NR][NR]) {int x, y;for (y = 0; y < NR; y++){for (x = 0; x < NR; x++){if (bl[y][x] != 0){gameArea[startY+y][startX+x] = 0;}}} }/** 函數名:showGame* 函數功能:顯示游戲* 參數:無* 返回值:無 */ void showGame(void) {int i, j;/* 定位到第一行第一列 */fprintf(stdout,"\033[1;1H");fflush(stdout);/* 打印所有數據 */for (i = 0; i < ROW; i++){for (j = 0; j < COL; j++){if (gameArea[i][j] == 0) // 空白區域{fprintf(stdout," ");}else if (gameArea[i][j] == 8) // 邊界區域{fprintf(stdout,"\033[46m \033[0m");}else // 方塊區域{fprintf(stdout,"\033[%dm[]\033[0m",gameArea[i][j]+40);}}fputc('\n',stdout);}/* 打印提示信息 */fprintf(stdout,"\033[2;3H\033[33m【下一個】\033[0m\n");fprintf(stdout,"\033[2;15H當前級別:\033[36m%u\033[0m\n",level);fprintf(stdout,"\033[3;15H當前分數:\033[32m%u\033[0m\n",score);fprintf(stdout,"\033[4;15H最高記錄:\033[35m%u\033[0m\n",maxScore);fprintf(stdout,"\033[5;15H當前狀態:%s\n",state); }/** 函數名:gameEnd* 函數功能:處理游戲結束的設置* 參數:無* 返回值:無 */ void gameEnd(void) {/* 配置游戲結束后的界面 */state = "\033[31m游戲結束!!\033[0m";drawBlock(bl[type][diret]);showGame();/* 恢復終端設置 */system("stty icanon"); // 恢復緩沖system("stty echo"); // 恢復回顯fprintf(stdout,"\033[?25h"); // 恢復鼠標顯示/* 尾部處理 */fprintf(stdout,"\033[200;1H"); // 定位光標到最后一行fclose(fp); // 關閉文件exit(0); // 退出程序 }data.h (這是存放數據文件,為 main.c 提供數據)
/** 文件名稱: Data.h* 功能描述:俄羅斯方塊游戲的方塊數據庫* 編寫人:王廷云 */ #ifndef _DATA_H_ #define _DATA_H_#define NR 4 // 方塊數據大小 #define TYPE 7 // 方塊類型數/* 方塊數據 */ char bl[TYPE][NR][NR][NR] = {/* 第一種方塊 */{{ /* 第一種方向 */{1,1,0,0},{1,1,0,0},{0,0,0,0},{0,0,0,0},},{ /* 第二種方向 */{1,1,0,0},{1,1,0,0},{0,0,0,0},{0,0,0,0},},{ /* 第三種方向 */{1,1,0,0},{1,1,0,0},{0,0,0,0},{0,0,0,0},},{ /* 第四種方向 */{1,1,0,0},{1,1,0,0},{0,0,0,0},{0,0,0,0},},},/* 第二種方塊 */{{ /* 第一種方向 */{2,2,2,2},{0,0,0,0},{0,0,0,0},{0,0,0,0},},{ /* 第二種方向 */{0,2,0,0},{0,2,0,0},{0,2,0,0},{0,2,0,0},},{ /* 第三種方向 */{2,2,2,2},{0,0,0,0},{0,0,0,0},{0,0,0,0},},{ /* 第四種方向 */{0,2,0,0},{0,2,0,0},{0,2,0,0},{0,2,0,0},},},/* 第三種方塊 */{{ /* 第一種方向 */{3,0,0,0},{3,3,3,0},{0,0,0,0},{0,0,0,0},},{ /* 第二種方向 */{0,3,3,0},{0,3,0,0},{0,3,0,0},{0,0,0,0},},{ /* 第三種方向 */{3,3,3,0},{0,0,3,0},{0,0,0,0},{0,0,0,0},},{ /* 第四種方向 */{0,0,3,0},{0,0,3,0},{0,3,3,0},{0,0,0,0},},},/* 第四種方塊 */{{ /* 第一種方向 */{0,0,4,0},{4,4,4,0},{0,0,0,0},{0,0,0,0},},{ /* 第二種方向 */{0,4,0,0},{0,4,0,0},{0,4,4,0},{0,0,0,0},},{ /* 第三種方向 */{0,4,4,4},{0,4,0,0},{0,0,0,0},{0,0,0,0},},{ /* 第四種方向 */{0,4,4,0},{0,0,4,0},{0,0,4,0},{0,0,0,0},},},/* 第五種方塊 */{{ /* 第一種方向 */{0,5,0,0},{5,5,5,0},{0,0,0,0},{0,0,0,0},},{ /* 第二種方向 */{0,5,0,0},{0,5,5,0},{0,5,0,0},{0,0,0,0},},{ /* 第三種方向 */{5,5,5,0},{0,5,0,0},{0,0,0,0},{0,0,0,0},},{ /* 第四種方向 */{0,5,0,0},{5,5,0,0},{0,5,0,0},{0,0,0,0},},},/* 第六種方塊 */{{ /* 第一種方向 */{6,6,0,0},{0,6,6,0},{0,0,0,0},{0,0,0,0},},{ /* 第二種方向 */{0,0,6,0},{0,6,6,0},{0,6,0,0},{0,0,0,0},},{ /* 第三種方向 */{6,6,0,0},{0,6,6,0},{0,0,0,0},{0,0,0,0},},{ /* 第四種方向 */{0,0,6,0},{0,6,6,0},{0,6,0,0},{0,0,0,0},},},/* 第七種方塊 */{{ /* 第一種方向 */{0,7,7,0},{7,7,0,0},{0,0,0,0},{0,0,0,0},},{ /* 第二種方向 */{0,7,0,0},{0,7,7,0},{0,0,7,0},{0,0,0,0},},{ /* 第三種方向 */{0,0,7,7},{0,7,7,0},{0,0,0,0},{0,0,0,0},},{ /* 第四種方向 */{0,7,0,0},{0,7,7,0},{0,0,7,0},{0,0,0,0},},}, };#endif //_DATA_H_總結
以上是生活随笔為你收集整理的【C语言】之实现俄罗斯方块游戏的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: nodejsmongoangularjs
- 下一篇: C语言面试高频问题:自己代码实现字符串相
