Linux下C语言实现俄罗斯方块——详细版
一、思路
1、創建界面map數組邊界填充值 1。
 2、rand生成隨機數確定下移的圖形。
 3、界面顯示,通過移動光標輸出確定界面位置。
4、圖形顯示,通過光標移動輸出圖形,四個數據塊每一塊對應一個小方塊。
????? 下一個輸出next為 反L3:{(0,0), (1,0), (0,1), (0,2)}。
5、圖形下移,通過y變化改變位置下移。
 6、下移完成,判斷圖形到界面邊界,將圖形到達位置寫入map, map填充值2。
 7、判斷一行是否都填滿,填滿后忽略本行,將此行以上的拷貝下來,最上面一行不用拷貝(最上面一行如果有圖形游戲已經結束了)。
 8、判斷結束,判斷最上面那一行map中有 2 ,有則結束。 ?
 9、每次輸出完,清理輸出界面system("clear"),是一幀一幀輸出后形成流暢畫面。
 10、控制顏色輸出詳細內容:https://mrleef.blog.csdn.net/article/details/125542134?spm=1001.2014.3001.5506
?二、其他
????? 本次用的Linux版本為,ubuntu-18.04.6-desktop-amd64.ios,更新20的版本也不錯,個人感覺這個版本的更好用,CentoS不太好用,軟件安裝也不方便。
????? 編輯器是VSCode和vim,VSCode是開源的,沒有版權問題。
????? 運行是用終端運行的。編譯命令:gcc game.c?? -o game? 運行:./game
三、代碼
#include<stdio.h> #include<stdlib.h> #include<time.h> #include<unistd.h>#define TTY_PATH "/dev/tty" //系統指令 #define STTY_US "stty raw -echo -F " //系統指令 #define STTY_DEF "stty -raw echo -F " //系統指令#define WIDE 18 #define HEIGHT 20 #define INFO_AREA 6 #define SPEED 8 #define Y_NEXT 4 // x_next, y_next下一個圖形在方框的位置 #define X_NEXT WIDE - INFO_AREA / 2 - 1int score = 0; //分數 int map[HEIGHT][WIDE] = { 0 }; //界面int x, y; // x, y 正在下降圖形的位置 int moveDown_count = 0; int shapeIndex, shapeIndex_next; //shapeIndex:下移圖形 shapeIndex_next:下一個圖形struct Point { //中心點的偏移量,中心點以此延伸獲得各形狀點的坐標int shape_x;int shape_y; };struct Point shapes[19][4] = {{{0, 0},{-1, 0},{1, 0},{2, 0}}, //橫條 通過光標移動輸出圖形{{0, 0},{0, -1},{0, 1},{0, 2}}, //豎條 每一個圖形由四個方塊組成{{0,0},{-1,-1},{-1,0},{0,-1}}, //方塊 四組,每一組對應輸出一個方塊 {{0, 0},{0, -1},{0, -2},{1, 0}}, //正L1 0, 1...反映光標移動情況{{0,0},{0,1},{1,0},{2,0}}, //正L2 {{0,0},{-1,0},{0,1},{0,2}}, //正L3 {{0,0},{0,-1},{-1,0},{-2,0}}, //正L4 {{0,0},{-1,0},{0,-1},{0,-2}}, //反L1 {{0,0},{0,-1},{1,0},{2,0}}, //反L2 {{0,0},{1,0},{0,1},{0,2}}, //反L3 {{0,0},{-1,0},{-2,0},{0,1}}, //反L4 {{0,0},{-1,0},{1,0},{0,-1}}, //T1 {{0,0},{0,1},{0,-1},{1,0}}, //T 2 {{0,0},{-1,0},{1,0},{0,1}}, //T 3 {{0,0},{-1,0},{0,-1},{0,1}}, //T 4 {{0,0},{1,0},{0,-1},{-1,-1}}, //正 Z 1 {{0,0},{1,-1},{0,1},{1,0}}, //正Z2 {{0,0},{1,-1},{-1,0},{0,-1}}, //反z1 {{0,0},{-1,-1},{-1,0},{0,1}} //反Z2 };void setFrame(); //構建邊寬 void showMap(); //展示界面 void showPoint(int x, int y,int bright,int color); void showShape(); //輸出圖形 void creatNewShape();//創建新的圖形 int moveDown(); //圖形下降,判斷是否還可以移動 void addToMap(); //把確定位置的保存在map中 int overCheak(); //確定游戲是否結束 int get_char(); //獲取輸入 void control(char str); //控制移動 void chageShape(); //改變形狀 void moveLeft(); //左移 void moveRight(); //右移 void clearLines(); //清除已滿行int main() {system(STTY_US TTY_PATH); //輸入阻塞setFrame(); //初始化mapshowMap(); //展示界面srand(time(0));shapeIndex = rand() % 19;creatNewShape(); //創建下一個圖形while(1) {system("clear"); //清除界面顯示內容showShape(); //展示方塊showMap(); //展示界面if (moveDown()) { //判斷移動addToMap(); //不可移動后,寫入到mapif (overCheak()) { //檢查是否游戲結束break;}clearLines(); //判斷一行是否滿,并清理shapeIndex = shapeIndex_next;creatNewShape(); //創建下一個圖形}char str = get_char(); //得到輸入指令if (str == 3) { //是否為ctrl+Cbreak;}control(str); //控制移動usleep(1000*50); //阻礙運行速度}system(STTY_DEF TTY_PATH); //輸入阻塞結束printf("\033[21;0H"); }/*** @brief Set the Frame object */ void setFrame() {int i;for(i = 0; i < WIDE; i++) { //界面兩條橫線map[0][i] = 1;map[HEIGHT - 1][i] = 1;}for(i = 0; i < HEIGHT; i++) { //界面三條豎線map[i][0] = 1;map[i][WIDE - INFO_AREA - 1] = 1;map[i] [WIDE - 1] = 1;} }/*** @brief 展示界面 */ void showMap() {int i, j;for(i = 0; i < HEIGHT; i++) {for(j = 0;j < WIDE; j++) {if ( map[i][j] == 1 || map[i][j] == 2) {showPoint(j, i, 1, 32 + map[i][j]); //行標i,列表j與坐標系橫縱坐標的值是相反的}}} printf("\033[2;27H"); // \033[X;XH 光標移動格式printf("\033[31mNext:"); printf("\033[11;27H"); printf("\033[32mScore:"); printf("\033[12;26H"); printf(" \033[32m%3d", score); fflush(stdout); //清理緩存,使畫面動作流暢 }/*** @brief 輸出一個方塊* * @param x1 光標橫軸位置* @param y1 光標縱軸位置* @param bright 顏色亮度* @param color 顏色種類*/ void showPoint(int x1, int y1, int bright, int color) {printf("\033[%d;%dH", y1 + 1, x1 * 2 + 1); //光標位置printf("\033[%d;%dm■ \033[0m", bright, color); //顏色深淺,顏色種類 }/*** @brief 創建下一個圖形和重置光標位置*/ void creatNewShape() { y = 2;x = (WIDE - INFO_AREA) / 2;shapeIndex_next = rand() % 19; }/*** @brief 顯示正在下降的圖形和顯示下一個圖形*/ void showShape() {int i;for(i = 0; i < 4; i++) { //顯示正在下降的圖形showPoint(x + shapes[shapeIndex][i].shape_x, y + shapes[shapeIndex][i].shape_y, 1, 31);}for(i = 0; i < 4; i++) { //顯示下一個圖形showPoint(X_NEXT + shapes[shapeIndex_next][i].shape_x, Y_NEXT + shapes[shapeIndex_next][i].shape_y, 1, 31);} }/*** @brief 圖形下降和控制移速* * @return int 1為已經處地,0還可移動*/ int moveDown() {int i;if (moveDown_count < SPEED) { //控制移動速度moveDown_count++; //移動準確性return 0; //也就是兩次進入函數圖形下移一格}moveDown_count = 0;for (i = 0; i < 4; i++) {int dx = x + shapes[shapeIndex][i].shape_x;int dy = y + shapes[shapeIndex][i].shape_y + 1;//原來位置的map[x][y]已經是1if (map[dy][dx] == 1 || map[dy][dx] == 2) {return 1; //不可移動}}y++;return 0; }/*** @brief 把不能移動的方塊保存到map中*/ void addToMap() {int i;for(i = 0; i < 4; i++) {map[y + shapes[shapeIndex][i].shape_y][x + shapes[shapeIndex][i].shape_x] = 2;} }/*** @brief 檢測游戲是否結束* * @return int 0為結束,1還可繼續*/ int overCheak() {int i;for (i = 0; i < WIDE; i++) {if (map[1][i] == 2) {return 1;}}return 0; }/*** @brief Get the char object* * @return int 返回輸入的字符對應的ASCII值*/ int get_char() {fd_set rfds;struct timeval tv;int ch = 0;FD_ZERO(&rfds);FD_SET(0, &rfds);tv.tv_sec = 0;tv.tv_usec = 10; if (select(1, &rfds, NULL, NULL, &tv) > 0) {ch = getchar(); }return ch; }/*** @brief 判斷輸入,得出下一步移動* * @param str 輸入的字符*/ void control(char str) {switch (str) {case 'w': //變形chageShape();break;case 'a': //左移moveLeft();break;case 's': //下移moveDown_count = moveDown_count + SPEED;break;case 'd': //右移moveRight();break;} }/*** @brief 改變形狀* 原理:通過改變shapeIndex的值*/ void chageShape() {int ts = shapeIndex;switch(ts) {case 0:ts++;break;case 1: ts = 0;break;case 2:break;case 3:case 4:case 5:ts++;break;case 6:ts = 3;break;case 7:case 8:case 9:ts++;break;case 10:ts = 7;break;case 11:case 12:case 13:ts++;break;case 14:ts = 11;break;case 15:ts++;break;case 16:ts = 15;break;case 17:ts++;break;case 18:ts = 17;break;}//ts是假設變形后的圖形值int i; //判斷假設的圖形是否發生碰撞for(i = 0;i < 4;i++) {int cx = x+shapes[ts][i].shape_x;int cy = y+shapes[ts][i].shape_y;if (map[cy][cx]==1 || map [cy][cx]==2) {return;}}shapeIndex = ts; //完成變形 }/*** @brief 左移*/ void moveLeft() {int i;for (i = 0; i < 4; i++) {if(map[y + shapes[shapeIndex][i].shape_y][x + shapes[shapeIndex][i].shape_x - 1] == 1|| map[y + shapes[shapeIndex][i].shape_y][x + shapes[shapeIndex][i].shape_x - 1] == 2) {return;}}x--; }/*** @brief 右移*/ void moveRight() {int i;for(i = 0; i < 4; i++) {if (map[y + shapes[shapeIndex][i].shape_y][x + shapes[shapeIndex][i].shape_x + 1] == 1|| map[y + shapes[shapeIndex][i].shape_y][x + shapes[shapeIndex][i].shape_x + 1] == 2) {return;}}x++; }/*** @brief 判斷一行是否滿,并清理,拷貝上面內容*/ void clearLines() {int i, j, a;for (i = HEIGHT - 2; i > 0; i--) {a = 1;for(j = 1; j < WIDE - INFO_AREA - 1; j++) { //確定是否一行排滿if (map[i][j] != 2) {a = 0;break;} }if (a == 1) {score++;int n;for(n = i; n > 1 ; n--) { //把上面的拷貝下來for(j = 0; j < WIDE - INFO_AREA - 1; j++) {map[n][j] = map[n- 1][j];}}i++; //防止有多行一起排滿}}fflush(stdout); //清理緩存,使畫面動作流暢 }有什么問題歡迎留言私信,必回!!!
去克制自己糾正別人的欲望,收起你改造他人的執著!人教人是教不會的。
?
總結
以上是生活随笔為你收集整理的Linux下C语言实现俄罗斯方块——详细版的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 在php里让字体划过变色,鼠标划过字体时
- 下一篇: [禅悟人生]心平气和, 慢慢修行
