我是剛入坑不久的,貪吃蛇算是我第一個用C寫出來的小游戲
這個程式里并沒有什么難懂的部分,大多都是剛開始學就接觸到的,so 加油吧!
源代碼在文章的末尾.
效果圖就不上了 (〃'▽'〃)
首先,來確定我們所需的頭檔案
#include <time.h> #include <conio.h> #include <stdio.h> #include <stdlib.h> #include <windows.h>
<time.h> 這是我們在之后生成隨機食物坐標時,用來以時間來生成亂數種子所需的頭檔案
<conio.h> 這個是gotoxy()函式所需的頭檔案
至于其他的應該都明白的.
接下來,定義我們需要的常量和全域變數
//常量
//蛇的行進狀態 U:上 D:下 L:左 R:右 #define U 1 #define D 2
#define L 3 #define R 4
//全域變數的設定 int state; //當前蛇的狀態 int wall_x=1,wall_y=1,wall_x1=97,wall_y1=25; //圍墻的坐標 int speed =200; //蛇每一次運行的時間間隔 int snake_x=6,snake_y=5; //蛇頭的坐標 int food_x,food_y; //食物的坐標 int path_list[30000][2]; //路徑串列 int path_find_line=0; //路徑記錄到第幾行 int point_food=0; //食物得到次數
上面的注釋應該挺清楚的了,我用的是食物得到的次數來確定蛇身的長度.
因為我比較喜歡吧main()函式放在源檔案中定義函式的前面,
所以我需要函式原型,來告訴編譯器將在源檔案中定義的函式的特征.(如圖)
void wall_draw(); //制造圍墻 int border(int,int); //邊界限制 int snake_move(); //蛇的移動 int snake_tail_delete(); //洗掉蛇尾 int path_log(); //蛇的位移路徑記錄 int food_generate(); //食物生成 int food_get(int,int); //獲得食物 int gotoxy(int,int); //移動游標 int rectangle(int,int,int,int); //建立矩形 int control(); //控制蛇的移動方向
然后,開始一個一個的分析定義的函式:
void wall_draw() { //確定視窗大小 system("mode con cols=100 lines=30"); //繪畫矩形 rectangel(wall_x,wall_y,wall_x1,wall_y1); //列印標題 gotoxy(43,0); printf("***Snake***"); //回到游標區 gotoxy(0,29); }
其中的:

在命令列中的意思是:吧視窗改變成 行容納100個字符 可以輸出30列
(ps:效果是這樣但是我描述的可能不太好,建議自己在命令提示符中嘗試)

接下來的 rectangel()函式,是我自己寫的,好像在哪個頭檔案里已經有了這個函式,但是我看不懂.
沒辦法只能自己打一個.
int rectangel(int x,int y,int x2,int y2) { gotoxy(x,y); printf("┌"); int i; for (i = 0; i < x2-x-1; i++) { printf("─"); } printf("┐"); for (i = 0; i < y2-y-1; i++) { gotoxy(x,y+i+1); printf("│"); gotoxy(x2,y+i+1); printf("│"); } gotoxy(x,y2); printf("└"); for (i = 0; i < x2-x-1; i++) { printf("─"); } printf("┘"); }
關于這個函式其實挺簡單的,他要求輸入的引數有 4個.也就是矩形的兩個對頂點
把兩個對頂點輸入進去,就可以求出整個矩形的四個頂點,然后用gotoxy()函式來移動游標進行列印矩形
path_log()函式:
//蛇的移動路徑記錄 int path_log() { path_list[path_find_line][0]=snake_x; path_list[path_find_line][1]=snake_y; ++path_find_line; }
當執行該函式時,會把當前蛇頭的坐標記錄到path_list陣列中.
snake_tail_delete()函式:
//洗掉蛇尾
int snake_tail_delete()
{
//查詢蛇尾位置
int x,y;
x=path_list[path_find_line-point_food-1][0];
y=path_list[path_find_line-point_food-1][1];
gotoxy(x,y);
printf(" ");
path_list[path_find_line-point_food-1][0]=0;
path_list[path_find_line-point_food-1][1]=0;
//回傳游標區
gotoxy(0,29);
return 0;
}
在這里我的想法是每次都洗掉蛇尾,只不過如果吃到食物的時候會去上一次的地方洗掉蛇尾.
解釋的可能不怎么好.(簡單來講:假設蛇移動了十次,且吃到了兩次食物,那么就可知道蛇尾是在已走路徑中的第 path_find_line - point_food這里,即10-2)
border()函式:
在貪吃蛇中,蛇不能撞墻,也不能撞到自己的身體所以需要 border()函式來判斷蛇是否撞墻,或者撞到自己的身體.
//是否生成在障礙物上 是:1 否:0 border(x,y)
int border(int x,int y)
{
//查詢物體是否撞到蛇身
int i;
for (i = 0; i < path_find_line+1; i++)
{
if (x==path_list[i][0] && y==path_list[i][1])
{
return 1;
}
}
//查詢物體是否撞到墻
if (wall_x>=x || wall_x1<=x || wall_y>=y || wall_y1<=y)
{
return 1;
}
return 0;
}
在這個函式中,是有回傳值的.
判斷蛇身就是在path_list陣列中查詢當前蛇頭坐標是否在里面,是:撞到 否:沒撞到
如果蛇撞墻,或者撞到了蛇身,回傳1, 否則回傳0.
food_generate()函式:
//食物的生成 成功:1 失敗:0 int food_generate() { //初始化隨機種子 srand((unsigned int)time(NULL)); int x,y; x=food_x; y=food_y; while (1) { //隨機食物坐標 food_x=rand()%wall_x1+wall_x; food_y=rand()%wall_y1+wall_y; //查詢食物是否生成位置錯誤 if (food_x%2 ==1) { continue; } if (food_x==x && food_y==y) { continue; } if (border(food_x,food_y)==1) { continue; } //列印食物 gotoxy(food_x,food_y); printf("\a⊕"); gotoxy(0,29); return 1; } return 0; }
唯一要講的差不多就是食物的隨機生成的問題了
用rand()函式取亂數.但是使用前需要初始化亂數種子
也就是這個:

food_get()函式:
//獲得食物 food_get(snake_x,snake_y) int food_get(int x,int y) { if (x==food_x && y==food_y) { food_generate(); ++point_food; gotoxy(1,0); printf("Point:%4d",point_food); gotoxy(0,29); } }
簡單講:就是判斷蛇頭坐標是否和食物坐標相等.
相等 -> 生成一次食物 food_generate()
不相等 -> 不執行
snake_move()函式:
//蛇的移動 int snake_move() { snake_tail_delete(); if (state == U) { --snake_y; gotoxy(snake_x,snake_y); printf("█"); gotoxy(10,29); printf("Speed:%4d",speed); } if (state == D) { ++snake_y; gotoxy(snake_x,snake_y); printf("█"); gotoxy(10,29); printf("Speed:%4d",speed); } if (state == L) { --snake_x; --snake_x; gotoxy(snake_x,snake_y); printf("█"); gotoxy(10,29); printf("Speed:%4d",speed); } if (state == R) { ++snake_x; ++snake_x; gotoxy(snake_x,snake_y); printf("█"); gotoxy(10,29); printf("Speed:%4d",speed); } food_get(snake_x,snake_y); if (border(snake_x,snake_y)==1) { return 1; } path_log(); Sleep(speed); }
在游戲里貪吃蛇每隔一定的時間就要移動一格.
所以我們需要Sleep()函式.
(ps:Sleep的S一定要大寫,C語言對大小寫十分敏感)
然后在蛇每移動一次,就執行path_log()來記錄移動的路徑
之后判斷是否吃到食物 food_get()
以及執行snake_tail_delete()來洗掉蛇尾
然后等待Sleep(speed);
最后就是控制蛇的移動啦 ε≡?(?>?<)?
control()函式:
//監聽鍵盤 成功:1 失敗:0 int control() { state = D; gotoxy(snake_x,snake_y); printf(" "); while(1) { if(GetAsyncKeyState(VK_UP) && state!=D) { state=U; } else if(GetAsyncKeyState(VK_DOWN) && state!=U) { state=D; } else if(GetAsyncKeyState(VK_LEFT)&& state!=R) { state=L; } else if(GetAsyncKeyState(VK_RIGHT)&& state!=L) { state=R; } else if(GetAsyncKeyState(VK_F1)) { if (speed<=20) { speed=10; } else { speed=speed-10; } } else if(GetAsyncKeyState(VK_F2)) { speed=speed+10; } if (snake_move()==1) { break; } } }
這個就是游戲的主回圈了
在這里的時候,出現了GetAsyncKeyState()函式
(解釋一下這個函式:執行他的時候會尋找是否在上次執行這個命令時是否按下鍵盤上的那個鍵,詳細的去百度吧!)
源代碼:
1 #include <time.h> 2 #include <conio.h> 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <windows.h> 6 7 //蛇的行進狀態 8 #define U 1 9 #define D 2 10 #define L 3 11 #define R 4 12 13 void wall_draw(); //制造圍墻 14 int border(int,int); //邊界限制 15 int snake_move(); //蛇的移動 16 int snake_tail_delete(); //洗掉蛇尾 17 int path_log(); //蛇的位移路徑記錄 18 int food_generate(); //食物生成 19 int food_get(int,int); //獲得食物 20 int gotoxy(int,int); //移動游標 21 int rectangle(int,int,int,int); //建立矩形 22 int control(); //控制移動方向 23 24 //全域變數的設定 25 26 int state; //當前蛇的狀態 27 int wall_x=1,wall_y=1,wall_x1=97,wall_y1=25; //圍墻的坐標 28 int speed =200; //蛇每一次運行的時間間隔 29 int snake_x=6,snake_y=5; //蛇頭的坐標 30 int food_x,food_y; //食物的坐標 31 int path_list[30000][2]; //路徑串列 32 int path_find_line=0; //路徑記錄到第幾行 33 int point_food=0; //食物得到次數 34 35 int main() 36 { 37 wall_draw(); //繪制邊界 38 39 gotoxy(snake_x,snake_y); 40 printf("█"); 41 42 food_generate(); //生成一次食物 43 44 //游戲行程 45 control(); //控制蛇的移動方向 46 47 //游戲結束 48 system("cls"); 49 wall_draw(); 50 } 51 52 53 54 int gotoxy(int x,int y) 55 { 56 COORD coord = {x,y}; 57 SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); 58 } 59 void wall_draw() 60 { 61 //確定視窗大小 62 system("mode con cols=100 lines=30"); 63 //繪畫矩形 64 rectangel(wall_x,wall_y,wall_x1,wall_y1); 65 //列印標題 66 gotoxy(43,0); 67 printf("***Snake***"); 68 //回到游標區 69 gotoxy(0,29); 70 } 71 int rectangel(int x,int y,int x2,int y2) 72 { 73 gotoxy(x,y); 74 printf("┌"); 75 int i; 76 for (i = 0; i < x2-x-1; i++) 77 { 78 printf("─"); 79 } 80 printf("┐"); 81 for (i = 0; i < y2-y-1; i++) 82 { 83 gotoxy(x,y+i+1); 84 printf("│"); 85 gotoxy(x2,y+i+1); 86 printf("│"); 87 } 88 gotoxy(x,y2); 89 printf("└"); 90 for (i = 0; i < x2-x-1; i++) 91 { 92 printf("─"); 93 } 94 printf("┘"); 95 } 96 97 //是否生成在障礙物上 是:1 否:0 border(x,y) 98 int border(int x,int y) 99 { 100 //查詢物體是否撞到蛇身 101 int i; 102 for (i = 0; i < path_find_line+1; i++) 103 { 104 if (x==path_list[i][0] && y==path_list[i][1]) 105 { 106 return 1; 107 } 108 109 } 110 111 //查詢物體是否撞到墻 112 if (wall_x>=x || wall_x1<=x || wall_y>=y || wall_y1<=y) 113 { 114 return 1; 115 } 116 117 return 0; 118 } 119 120 //蛇的移動路徑記錄 121 int path_log() 122 { 123 path_list[path_find_line][0]=snake_x; 124 path_list[path_find_line][1]=snake_y; 125 ++path_find_line; 126 } 127 128 //食物的生成 成功:1 失敗:0 129 int food_generate() 130 { 131 //初始化隨機種子 132 srand((unsigned int)time(NULL)); 133 int x,y; 134 x=food_x; 135 y=food_y; 136 while (1) 137 { 138 //隨機食物坐標 139 food_x=rand()%wall_x1+wall_x; 140 food_y=rand()%wall_y1+wall_y; 141 142 //查詢食物是否生成位置錯誤 143 if (food_x%2 ==1) 144 { 145 continue; 146 } 147 148 if (food_x==x && food_y==y) 149 { 150 continue; 151 } 152 if (border(food_x,food_y)==1) 153 { 154 continue; 155 } 156 157 //列印食物 158 gotoxy(food_x,food_y); 159 printf("\a⊕"); 160 gotoxy(0,29); 161 162 return 1; 163 } 164 return 0; 165 } 166 167 //獲得食物 food_get(snake_x,snake_y) 168 int food_get(int x,int y) 169 { 170 if (x==food_x && y==food_y) 171 { 172 food_generate(); 173 ++point_food; 174 gotoxy(1,0); 175 printf("Point:%4d",point_food); 176 gotoxy(0,29); 177 } 178 179 } 180 181 //洗掉蛇尾 182 int snake_tail_delete() 183 { 184 //查詢蛇尾位置 185 int x,y; 186 x=path_list[path_find_line-point_food-1][0]; 187 y=path_list[path_find_line-point_food-1][1]; 188 gotoxy(x,y); 189 printf(" "); 190 path_list[path_find_line-point_food-1][0]=0; 191 path_list[path_find_line-point_food-1][1]=0; 192 193 //回傳游標區 194 gotoxy(0,29); 195 196 return 0; 197 } 198 199 //監聽鍵盤 成功:1 失敗:0 200 int control() 201 { 202 state = D; 203 gotoxy(snake_x,snake_y); 204 printf(" "); 205 while(1) 206 { 207 if(GetAsyncKeyState(VK_UP) && state!=D) 208 { 209 state=U; 210 } 211 else if(GetAsyncKeyState(VK_DOWN) && state!=U) 212 { 213 state=D; 214 } 215 else if(GetAsyncKeyState(VK_LEFT)&& state!=R) 216 { 217 state=L; 218 } 219 else if(GetAsyncKeyState(VK_RIGHT)&& state!=L) 220 { 221 state=R; 222 } 223 else if(GetAsyncKeyState(VK_F1)) 224 { 225 if (speed<=20) 226 { 227 speed=10; 228 } 229 else 230 { 231 speed=speed-10; 232 } 233 234 235 } 236 else if(GetAsyncKeyState(VK_F2)) 237 { 238 speed=speed+10; 239 } 240 if (snake_move()==1) 241 { 242 break; 243 } 244 } 245 } 246 //蛇的移動 247 int snake_move() 248 { 249 snake_tail_delete(); 250 if (state == U) 251 { 252 --snake_y; 253 gotoxy(snake_x,snake_y); 254 printf("█"); 255 gotoxy(10,29); 256 printf("Speed:%4d",speed); 257 } 258 if (state == D) 259 { 260 ++snake_y; 261 gotoxy(snake_x,snake_y); 262 printf("█"); 263 gotoxy(10,29); 264 printf("Speed:%4d",speed); 265 } 266 if (state == L) 267 { 268 --snake_x; 269 --snake_x; 270 gotoxy(snake_x,snake_y); 271 printf("█"); 272 gotoxy(10,29); 273 printf("Speed:%4d",speed); 274 } 275 if (state == R) 276 { 277 ++snake_x; 278 ++snake_x; 279 gotoxy(snake_x,snake_y); 280 printf("█"); 281 gotoxy(10,29); 282 printf("Speed:%4d",speed); 283 } 284 food_get(snake_x,snake_y); 285 286 if (border(snake_x,snake_y)==1) 287 { 288 return 1; 289 } 290 291 292 path_log(); 293 294 Sleep(speed); 295 296 }
如果這個程式有什么問題,或者是有什么建議的話,可以聯系我交流.
歡迎討論,并互相進步!
(第 4次更改)
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/36286.html
標籤:C
上一篇:遇到的兩個編譯問題
下一篇:C指標 (??▽?)?
