play snake on linux

在寫完超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 }
View Code

 

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 }

 

 

感謝參考資料

1.Linux struct itimerval用法

2.【Linux函數】Signal ()函數詳細介紹

3. linux下c語言寫的簡單的貪吃蛇

4.關於curses的簡單知識

5.在linux下面實現檢測按鍵(Linux中kbhit()函數的實現)

相關文章
相關標籤/搜索