在寫完超Low的windows上的貪吃蛇後html
被人吐槽了幾個方面:linux
1.界面真的Low,開始,結束,遊戲中,都太簡陋了...ios
2.每次都清屏在輸出字符矩陣的解決方案...太晃眼了windows
3.一個BUG,爲了解決貪吃蛇隔固定時間time移動一個單位的問題ide
咱們寫的是while(距上次移動時間 < time && 沒有鍵盤方向鍵的讀入);函數
因而咱們驚喜的發現,只要一直摁方向鍵,就沒必要等待固定時間time學習
而是會直接下一步移動...手動加快貪吃蛇移動速度...url
可是咱們暫時並不想改進這個程序...畢竟怎麼說仍是能玩一玩的es5
因而ytz決定在本身的deepin系統上寫一個能運行的貪吃蛇...spa
先想到的方法固然是直接把windows上的代碼拿來改一改啊...
但很快咱們就遇到了重重障礙!
1.咱們使用了conio.h中的_kbhit函數來判斷是否有鍵盤讀入
然而linux系統下是沒有conio.h這個庫的...
百度了一下linux下也沒有自帶庫函數有相同功能
因而咱們就百度了一個手動實現_kbhit函數加進去
(這個實現原理不是很懂我是照抄的...)
2.conio.h中的getch函數一樣須要替代品
這時候就有人指出明路,curses.h庫裏有啊
而後咱們須要先安裝這個庫,在終端輸入
sudo apt-get install libncurses5-dev
回車便可開始安裝
而後編譯時須要加入 -lncurses 命令
好比 g++ -o Snake -lncurses Snake.cpp
不然編譯沒法經過
3.啊,編譯經過了!
咱們愉快的運行一下吧!
運行出了一坨屎!
咱們百度一下curses.h 這個庫
發現是一個圖形庫,相似於大一學習C和C++的時候
老師提供的windows上的的第三方庫ege.h
只不過curses的評價彷佛比ege好一點2333
而後ege那個你懂的吧,開始運行進入圖形界面後
各類函數失效,printf,scanf...
以及輸出基本靠定位定點輸出,\n,\t 什麼的都會gg你懂的吧
4.因而咱們把pritf全都換成printw
拋棄 \n \t 改用move來移動光標位置
而後只在遊戲開始時使用一次清屏system("clear")
其它都使用 curses.h 裏的 refresh 函數便可
(咱們的 printw 是輸出在邏輯屏幕上的,
refresh 函數用來同步邏輯屏幕和物理屏幕
物理屏幕即咱們看到的屏幕
而後refresh函數表現的十分流暢的
最重要的是,它不晃眼!!!)
而後終於能正確打印出字符矩陣了!
5.漢字在終端顯示成亂碼
百度了好久沒有找到解決方案
咱們就退讓一步,把漢字都改爲了英文
而後調用noecho函數,讓咱們的按鍵不顯示在屏幕上
嘗試運行......發現咱們造出來了一條癱瘓蛇...
不貪吃了癱瘓了...咱們不摁下方向鍵它本身不動...
先把癱瘓蛇代碼放上來吧
1 #include <ctime> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <stdio.h> 5 #include <termios.h> 6 #include <unistd.h> 7 #include <fcntl.h> 8 #include <curses.h> 9 10 #define map(pos) map[pos.x][pos.y] 11 12 char map[30][30]; 13 14 struct point { 15 int x, y; 16 17 void _rand() { 18 x = rand() % 20 + 1; 19 y = rand() % 20 + 1; 20 } 21 22 bool operator == (const point &a) const { 23 return x == a.x && y == a.y; 24 } 25 26 }; 27 28 int head, tail; 29 point snake[500], food, next; 30 int dir, grade, length, uptime; 31 32 inline int _kbhit() { 33 termios oldt, newt; 34 int ch, oldf; 35 tcgetattr(STDIN_FILENO, &oldt); 36 newt = oldt; 37 newt.c_lflag &= -(ICANON | ECHO); 38 tcsetattr(STDIN_FILENO, TCSANOW, &newt); 39 oldf = fcntl(STDIN_FILENO, F_GETFL, 0); 40 fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); 41 ch = getchar(); 42 tcsetattr(STDIN_FILENO, TCSANOW, &oldt); 43 fcntl(STDIN_FILENO, F_SETFL, oldf); 44 if(ch != EOF) { 45 ungetc(ch, stdin); 46 return 1; 47 } 48 return 0; 49 } 50 51 inline void find_food() { 52 do { 53 food._rand(); 54 }while(map(food) != ' '); 55 map(food) = '*'; 56 } 57 58 inline void update() { 59 //system("clear"); 60 for(int i = 0;i < 22;i ++) { 61 for(int j = 0;j < 22;j ++) 62 move(i + 3, 3 + j * 2), printw("%c ", map[i][j]); 63 if(i == 0) move(i + 3, 60), printw("Level:%d", grade); 64 if(i == 2) move(i + 3, 60), printw("length:%d", length); 65 if(i == 6) move(i + 3, 60), printw("Time_interval:"); 66 if(i == 8) move(i + 3, 60), printw("%d ms", uptime); 67 } 68 refresh(); 69 } 70 71 inline bool GO() { 72 bool timeover = 1; 73 double start = (double) clock() / CLOCKS_PER_SEC; 74 while((timeover = (double) clock() / CLOCKS_PER_SEC <= start + uptime / 1000.0) && !(_kbhit())); 75 if(timeover) dir = getch(); 76 next = snake[head]; 77 switch (dir) { 78 case 'w':next.x -= 1;break; 79 case 's':next.x += 1;break; 80 case 'a':next.y -= 1;break; 81 case 'd':next.y += 1;break; 82 default: 83 move(30, 10); 84 printw("Game Over!"); 85 return 0; 86 } 87 if(!next.x || next.x == 21 || !next.y || next.y == 21) { 88 move(30, 10); 89 printw("Game Over!"); 90 return 0; 91 } 92 if(map(next) != ' ' && !(next == food)) { 93 move(30, 10); 94 printw("Game Over!"); 95 return 0; 96 } 97 if(length == 400) { 98 move(30, 10); 99 printw("Game Over!"); 100 return 0; 101 } 102 return 1; 103 } 104 105 int main() { 106 initscr(); 107 clear(); 108 curs_set(0); 109 srand(19980320); 110 for(int i = 1;i <= 20;i ++) 111 for(int j = 1;j <= 20;j ++) 112 map[i][j] = ' '; 113 for(int i = 0;i < 22;i ++) 114 map[i][0] = map[21][i] = map[0][i] = map[i][21] = '!'; 115 map[1][1] = map[1][2] = 'o', map[1][3] = '@'; 116 snake[0] = (point){1, 1}; 117 snake[1] = (point){1, 2}; 118 snake[2] = (point){1, 3}; 119 head = 2, tail = 0, grade = 1, length = 3, uptime = 500; 120 find_food(), dir = 'd'; 121 122 move(3, 10); 123 printw("Let's play snake!"); 124 refresh(); 125 double start; 126 for(int i = 3;i >= 0;i --) { 127 start = (double)clock() / CLOCKS_PER_SEC; 128 while((double)clock() / CLOCKS_PER_SEC <= start + 1); 129 if(i > 0) { 130 //system("clear"); 131 move(3, 10); 132 printw("Enter the countdown:%d", i); 133 refresh(); 134 } 135 else { 136 update(); 137 } 138 } 139 140 while(1) { 141 int tmp = GO(); 142 refresh(); 143 if(tmp) { 144 if(next == food) { 145 length ++; 146 if(length % 10 == 0) { 147 grade ++; 148 if(uptime >= 100) uptime -= 50; 149 } 150 map(next) = '@'; 151 map(snake[head]) = 'o'; 152 head = (head + 1) % 500; 153 snake[head] = next; 154 find_food(), update(); 155 } 156 else { 157 map(snake[tail]) = ' '; 158 tail = (tail + 1) % 500; 159 map(next) = '@'; 160 map(snake[head]) = 'o'; 161 head = (head + 1) % 500; 162 snake[head] = next; 163 update(); 164 } 165 } 166 else break; 167 } 168 getch(); 169 endwin(); 170 return 0; 171 }
6.咱們通過實驗發現
問題出在getch和kbhit函數的配合上面
因而咱們修改一下kbhit函數
在得到鍵盤讀入以後再也不把字符存入緩衝區
而是直接return回去就行了!
而後爲了解決開始提到的第三個問題
咱們在得到鍵盤讀入以後
依舊等待固定時間間隔結束再讓蛇移動便可!
而後爲了解決第一個問題...
我加了個最終分數提示...
從新開始遊戲我懶就沒加...
至此咱們的windows貪吃蛇魔改之linux版基本就完成了!
(我太懶了因此依然沒有加註釋
1 #include <ctime> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <stdio.h> 5 #include <termios.h> 6 #include <unistd.h> 7 #include <fcntl.h> 8 #include <curses.h> 9 10 #define map(pos) map[pos.x][pos.y] 11 12 char map[30][30]; 13 14 struct point { 15 int x, y; 16 17 void _rand() { 18 x = rand() % 20 + 1; 19 y = rand() % 20 + 1; 20 } 21 22 bool operator == (const point &a) const { 23 return x == a.x && y == a.y; 24 } 25 26 }; 27 28 int head, tail; 29 point snake[500], food, next; 30 int dir, grade, length, uptime; 31 32 inline int _kbhit() { 33 termios oldt, newt; 34 int ch, oldf; 35 tcgetattr(STDIN_FILENO, &oldt); 36 newt = oldt; 37 newt.c_lflag &= -(ICANON | ECHO); 38 tcsetattr(STDIN_FILENO, TCSANOW, &newt); 39 oldf = fcntl(STDIN_FILENO, F_GETFL, 0); 40 fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); 41 ch = getchar(); 42 tcsetattr(STDIN_FILENO, TCSANOW, &oldt); 43 fcntl(STDIN_FILENO, F_SETFL, oldf); 44 if(ch != EOF) return ch; 45 return 0; 46 } 47 48 inline void find_food() { 49 do { 50 food._rand(); 51 }while(map(food) != ' '); 52 map(food) = '*'; 53 } 54 55 inline void update() { 56 //system("clear"); 57 for(int i = 0;i < 22;i ++) { 58 for(int j = 0;j < 22;j ++) 59 move(i + 3, 3 + j * 2), printw("%c ", map[i][j]); 60 if(i == 0) move(i + 3, 60), printw("Level:%d", grade); 61 if(i == 2) move(i + 3, 60), printw("length:%d", length); 62 if(i == 6) move(i + 3, 60), printw("Time_interval:"); 63 if(i == 8) move(i + 3, 60), printw("%d ms", uptime); 64 } 65 refresh(); 66 } 67 68 inline bool GO() { 69 int ch; 70 bool timeover = 1; 71 double start = (double) clock() / CLOCKS_PER_SEC; 72 while((timeover = (double) clock() / CLOCKS_PER_SEC <= start + uptime / 1000.0) && !(ch = _kbhit())); 73 if(timeover) { 74 while(timeover = (double) clock() / CLOCKS_PER_SEC <= start + uptime / 1000.0); 75 dir = ch; 76 } 77 next = snake[head]; 78 switch (dir) { 79 case 'w':next.x -= 1;break; 80 case 's':next.x += 1;break; 81 case 'a':next.y -= 1;break; 82 case 'd':next.y += 1;break; 83 default:return 0; 84 } 85 if(!next.x || next.x == 21 || !next.y || next.y == 21) return 0; 86 if(map(next) != ' ' && !(next == food)) return 0; 87 if(length == 400) return 0; 88 return 1; 89 } 90 91 int main() { 92 initscr(); 93 noecho(); 94 clear(); 95 curs_set(0); 96 srand(19980320); 97 for(int i = 1;i <= 20;i ++) 98 for(int j = 1;j <= 20;j ++) 99 map[i][j] = ' '; 100 for(int i = 0;i < 22;i ++) 101 map[i][0] = map[21][i] = map[0][i] = map[i][21] = '!'; 102 map[1][1] = map[1][2] = 'o', map[1][3] = '@'; 103 snake[0] = (point){1, 1}; 104 snake[1] = (point){1, 2}; 105 snake[2] = (point){1, 3}; 106 head = 2, tail = 0, grade = 1, length = 3, uptime = 500; 107 find_food(), dir = 'd'; 108 109 move(3, 10); 110 printw("Let's play snake!"); 111 refresh(); 112 double start; 113 for(int i = 3;i >= 0;i --) { 114 start = (double)clock() / CLOCKS_PER_SEC; 115 while((double)clock() / CLOCKS_PER_SEC <= start + 1); 116 if(i > 0) { 117 //system("clear"); 118 move(3, 10); 119 printw("Enter the countdown:%d", i); 120 refresh(); 121 } 122 else { 123 update(); 124 } 125 } 126 127 while(1) { 128 int tmp = GO(); 129 refresh(); 130 if(tmp) { 131 if(next == food) { 132 length ++; 133 if(length % 10 == 0) { 134 grade ++; 135 if(uptime >= 100) uptime -= 50; 136 } 137 map(next) = '@'; 138 map(snake[head]) = 'o'; 139 head = (head + 1) % 500; 140 snake[head] = next; 141 find_food(), update(); 142 } 143 else { 144 map(snake[tail]) = ' '; 145 tail = (tail + 1) % 500; 146 map(next) = '@'; 147 map(snake[head]) = 'o'; 148 head = (head + 1) % 500; 149 snake[head] = next; 150 update(); 151 } 152 } 153 else { 154 move(30, 20); 155 printw("Game Over!"); 156 move(32, 14); 157 printw("Your Final Score : %d", length); 158 break; 159 } 160 } 161 getch(); 162 endwin(); 163 return 0; 164 }
感謝參考資料