有很多學習C語言或者C++的朋友可能寫過貪吃蛇的作業,我也是其中之一。在最開始寫的時候自己水平很差,寫出的效果還不如許多同學從網上抄的。 這一系列博客都是使用C語言寫貪吃蛇,逐步提升難度,當然自己也好久不動手了,也算是自己複習一次C語言。 第一個貪吃蛇,因為許多剛學完C的同學並不瞭解太多東西,所以我 ...
有很多學習C語言或者C++的朋友可能寫過貪吃蛇的作業,我也是其中之一。在最開始寫的時候自己水平很差,寫出的效果還不如許多同學從網上抄的。
這一系列博客都是使用C語言寫貪吃蛇,逐步提升難度,當然自己也好久不動手了,也算是自己複習一次C語言。
第一個貪吃蛇,因為許多剛學完C的同學並不瞭解太多東西,所以我們只使用最基本的方法,完成最基本的功能。當然,我們得到的效果可能也就不是很好。
1 #include <stdio.h> 2 3 //隨機數生成 4 #include <stdlib.h> 5 #include <time.h> 6 7 //Windows API 8 #include <Windows.h> 9 10 //游戲常量設置 11 #define MAP_H 10 12 #define MAP_W 20 13 #define INIT_LEN 2 14 #define GAME_SPEED 200 15 16 #define CH_SNAKE 'O' 17 #define CH_FOOD '*' 18 #define CH_WALL 'H' 19 #define CH_SPACE ' ' 20 21 char map[MAP_H][MAP_W]; 22 struct _point{ 23 int y; 24 int x; 25 }snake[MAP_H*MAP_W]; 26 int snakeLength; 27 enum _direction{ 28 UP,LEFT,RIGHT,DOWN 29 }direction; 30 31 void initialize();//初始化 32 int update();//更新畫面 33 void generateFood();//生成食物 34 void changeDirection();//方向控制 35 void showMap();//顯示畫面 36 37 /************* 38 * 基本的游戲邏輯:顯示、控制、更新 39 */ 40 int main(){ 41 42 initialize(); 43 do{ 44 showMap(); 45 changeDirection(); 46 }while(update()); 47 48 return 0; 49 } 50 51 /******************* 52 * 初始化畫面數組、蛇身體的坐標數組、蛇的長度、最後在地圖上生成一個食物 53 */ 54 void initialize(){ 55 int i,j; 56 snakeLength=INIT_LEN; 57 direction=RIGHT; 58 59 for(i=0;i<MAP_H;i++){ 60 for(j=0;j<MAP_W;j++){ 61 map[i][j]=CH_SPACE; 62 } 63 } 64 65 for(i=0;i<INIT_LEN;i++){ 66 snake[i].x=INIT_LEN-i-1; 67 snake[i].y=0; 68 } 69 70 for(i=0;i<snakeLength;i++){ 71 map[snake[i].y][snake[i].x]=CH_SNAKE; 72 } 73 74 generateFood(); 75 } 76 77 /******************* 78 * Sleep控制游戲速度,system函數調用console指令cls清屏,最後迴圈輸出畫面 79 */ 80 void showMap(){ 81 system("cls"); 82 int i,j; 83 84 for(i=0;i<MAP_W+2;i++){ 85 putchar(CH_WALL); 86 } 87 putchar('\n'); 88 89 for(i=0;i<MAP_H;i++){ 90 putchar(CH_WALL); 91 for(j=0;j<MAP_W;j++){ 92 putchar(map[i][j]); 93 } 94 putchar(CH_WALL); 95 putchar('\n'); 96 } 97 98 for(i=0;i<MAP_W+2;i++){ 99 putchar(CH_WALL); 100 } 101 } 102 103 /******************* 104 * 使用隨機數產生食物的坐標 105 */ 106 void generateFood(){ 107 int x,y; 108 srand(time(0)); 109 while(1){ 110 x=rand()%MAP_W; 111 y=rand()%MAP_H; 112 if(map[y][x]==CH_SPACE) 113 break; 114 } 115 map[y][x]=CH_FOOD; 116 } 117 118 /******************* 119 * 更新畫面(游戲邏輯處理的部分) 120 * 通過direction計算下一個畫面蛇頭到達的位置,檢查該位置的物體,分別處理不同情形 121 */ 122 int update(){ 123 Sleep(GAME_SPEED); 124 int i,head_y,head_x; 125 126 switch(direction){ 127 case UP: 128 head_y=snake[0].y-1; 129 head_x=snake[0].x; 130 break; 131 case LEFT: 132 head_y=snake[0].y; 133 head_x=snake[0].x-1; 134 break; 135 case RIGHT: 136 head_y=snake[0].y; 137 head_x=snake[0].x+1; 138 break; 139 case DOWN: 140 head_y=snake[0].y+1; 141 head_x=snake[0].x; 142 break; 143 } 144 if(head_x<0||head_x>MAP_W||head_y<0||head_y>MAP_H){ 145 return 0;//撞牆 146 } 147 148 if(map[head_y][head_x]==CH_SNAKE){ 149 return 0;//撞自己 150 } 151 if(map[head_y][head_x]==CH_FOOD){ 152 for(i=snakeLength;i>0;i--){ 153 snake[i]=snake[i-1]; 154 } 155 snake[0].x=head_x; 156 snake[0].y=head_y; 157 map[head_y][head_x]=CH_SNAKE; 158 snakeLength+=1; 159 generateFood(); 160 return 1;//吃食物 161 } 162 if(map[head_y][head_x]==CH_SPACE){ 163 map[snake[snakeLength-1].y][snake[snakeLength-1].x]=CH_SPACE; 164 for(i=snakeLength-1;i>0;i--){ 165 snake[i]=snake[i-1]; 166 } 167 snake[0].x=head_x; 168 snake[0].y=head_y; 169 map[head_y][head_x]=CH_SNAKE; 170 return 1;//繼續前進 171 } 172 173 return 1; 174 } 175 176 /******************* 177 * 使用GetKeyState獲取鍵盤輸入,改變direction變數來控制行進方向 178 */ 179 void changeDirection(){ 180 if(GetKeyState(VK_UP)<0&&direction!=DOWN) 181 direction=UP; 182 else if(GetKeyState(VK_LEFT)<0&&direction!=RIGHT) 183 direction=LEFT; 184 else if(GetKeyState(VK_DOWN)<0&&direction!=UP) 185 direction=DOWN; 186 else if(GetKeyState(VK_RIGHT)<0&&direction!=LEFT) 187 direction=RIGHT; 188 }
這差不多就是我第一次寫的,相當的簡陋,使用體驗很差。但是除了Sleep,system,GetKeyState之外並沒有什麼C語言課本上沒教過的。
Sleep函數使控制台掛起(停下來),控制游戲速度。
system函數是用於輸入控制台命令的,cls是控制台用於清屏的命令
GetKeyState函數用於讀取鍵盤上某個特定按鍵的狀態,這裡用於讀取用戶輸入(控制方向)
當然,現在上面的代碼除了基本的游戲邏輯什麼都沒有。而且還會閃屏,最坑的是因為Sleep函數,按鍵有時候並不能被讀取,這是因為Sleep掛起了整個程式,而讀取輸入正是程式的一部分。