贪吃蛇游戏(printf输出C语言版本)

这一次我们应用printf输出实现一个经典的小游戏—贪吃蛇,主要难点是小蛇数据如何存储、如何实现转弯的效果、吃到食物后如何增加长度

1 构造小蛇

首先,在画面中显示一条静止的小蛇。二维数组canvas[High][Width]的对应元素,值为0输出空格,-1输出边框#,1输出蛇头@,大于1的正数输出蛇身*。startup()函数中初始化蛇头在画布中间位置(canvas[High/2][Width/2] = 1;),蛇头向左依次生成4个蛇身(for (i=1;i<=4;i++) canvas[High/2][Width/2-i] = i+1;),元素值分别为2、3、4、5。

 

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <conio.h>
 4 #include <windows.h>
 5           //C语言自学网
 6 #define High 20  // 游戏画面尺寸
 7 #define Width 30
 8 
 9 // 全局变量
10 int canvas[High][Width] = {0}; // 二维数组存储游戏画布中对应的元素
11 // 0为空格,-1为边框#,1为蛇头@,大于1的正数为蛇身*
12 
13 void gotoxy(int x,int y)  //光标移动到(x,y)位置
14 {
15     HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
16     COORD pos;
17     pos.X = x;
18     pos.Y = y;
19     SetConsoleCursorPosition(handle,pos);
20 }
21 
22 void startup() // 数据初始化
23 {
24     int i,j;
25     
26     // 初始化边框
27     for (i=0;i<High;i++)
28     {
29         canvas[i][0] = -1;
30         canvas[i][Width-1] = -1;
31     }
32     for (j=0;j<Width;j++)
33     {
34         canvas[0][j] = -1;
35         canvas[High-1][j] = -1;
36     }
37     
38     // 初始化蛇头位置
39     canvas[High/2][Width/2] = 1;
40     // 初始化蛇身,画布中元素值分别为2,3,4,5....
41     for (i=1;i<=4;i++)
42         canvas[High/2][Width/2-i] = i+1;
43 }
44 
45 void show()  // 显示画面
46 {
47     gotoxy(0,0);  // 光标移动到原点位置,以下重画清屏
48     int i,j;
49     for (i=0;i<High;i++)
50     {
51         for (j=0;j<Width;j++)
52         {
53             if (canvas[i][j]==0)
54                 printf(" ");   //   输出空格
55             else if (canvas[i][j]==-1)
56                 printf("#");   //   输出边框#
57             else if (canvas[i][j]==1)
58                 printf("@");   //   输出蛇头@
59             else if (canvas[i][j]>1)
60                 printf("*");   //   输出蛇身*
61         }
62         printf("\n");
63     }
64 }    
65 
66 void updateWithoutInput()  // 与用户输入无关的更新
67 {
68 }
69 
70 void updateWithInput()  // 与用户输入有关的更新
71 {
72 }
73 
74 int main()
75 {
76     startup();  // 数据初始化    
77     while (1) //  游戏循环执行
78     {
79         show();  // 显示画面
80         updateWithoutInput();  // 与用户输入无关的更新
81         updateWithInput();  // 与用户输入有关的更新
82     }
83     return 0;
84 }

2 小蛇自动移动

实现小蛇的移动是贪吃蛇游戏的难点,下图列出了小蛇分别向右、向上运动后,对应二维数组元素值的变化,从中我们可以得出实现思路。

 

假设小蛇元素为54321,其中1为蛇头、5432为蛇身、最大值5为蛇尾。首先将所有大于0的元素加1,得到65432;将最大值6变为0,即去除了原来的蛇尾;再根据对应的移动方向,将2对应方向的元素由0变成1;如此即实现了小蛇的移动。小蛇向上移动的对应流程如图所示。

 

定义变量int moveDirection表示小蛇的移动方向,值1、2、3、4分别表示小蛇向上、下、左、右方向移动,小蛇移动实现在moveSnakeByDirection()函数中。

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <conio.h>
  4 #include <windows.h>
  5 //C语言自学网
  6 #define High 20  // 游戏画面尺寸
  7 #define Width 30
  8 
  9 // 全局变量
 10 int moveDirection; // 小蛇移动方向,上下左右分别用1,2,3,4表示
 11 int canvas[High][Width] = {0}; // 二维数组存储游戏画布中对应的元素
 12             // 0为空格0,-1为边框#,1为蛇头@,大于1的正数为蛇身*
 13 
 14 void gotoxy(int x,int y)  //光标移动到(x,y)位置
 15 {
 16     HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
 17     COORD pos;
 18     pos.X = x;
 19     pos.Y = y;
 20     SetConsoleCursorPosition(handle,pos);
 21 }
 22 
 23 // 移动小蛇
 24 // 第一步扫描数组canvas所有元素,找到正数元素都+1
 25 // 找到最大元素(即蛇尾巴),把其变为0
 26 // 找到=2的元素(即蛇头),再根据输出的上下左右方向,把对应的另一个像素值设为1(新蛇头)
 27 void moveSnakeByDirection()
 28 {
 29     int i,j;
 30     for (i=1;i<High-1;i++)
 31         for (j=1;j<Width-1;j++)
 32             if (canvas[i][j]>0)
 33                 canvas[i][j]++;
 34 
 35     int oldTail_i,oldTail_j,oldHead_i,oldHead_j;
 36     int max = 0;
 37 
 38     for (i=1;i<High-1;i++)
 39         for (j=1;j<Width-1;j++)
 40             if (canvas[i][j]>0)
 41             {
 42                 if (max<canvas[i][j])
 43                 {
 44                     max = canvas[i][j];
 45                     oldTail_i = i;
 46                     oldTail_j = j;
 47                 }
 48                 if (canvas[i][j]==2)
 49                 {
 50                     oldHead_i = i;
 51                     oldHead_j = j;
 52                 }
 53             }
 54 
 55     canvas[oldTail_i][oldTail_j] = 0;
 56 
 57     if (moveDirection==1) // 向上移动
 58         canvas[oldHead_i-1][oldHead_j] = 1;
 59     if (moveDirection==2) // 向下移动
 60         canvas[oldHead_i+1][oldHead_j] = 1;
 61     if (moveDirection==3) // 向左移动
 62         canvas[oldHead_i][oldHead_j-1] = 1;
 63     if (moveDirection==4) // 向右移动
 64         canvas[oldHead_i][oldHead_j+1] = 1;
 65 }
 66 
 67 void startup() // 数据初始化
 68 {
 69     int i,j;
 70     
 71     // 初始化边框
 72     for (i=0;i<High;i++)
 73     {
 74         canvas[i][0] = -1;
 75         canvas[i][Width-1] = -1;
 76     }
 77     for (j=0;j<Width;j++)
 78     {
 79         canvas[0][j] = -1;
 80         canvas[High-1][j] = -1;
 81     }
 82     
 83     // 初始化蛇头位置
 84     canvas[High/2][Width/2] = 1;
 85     // 初始化蛇身,画布中元素值分别为2,3,4,5....
 86     for (i=1;i<=4;i++)
 87         canvas[High/2][Width/2-i] = i+1;
 88     
 89     // 初始小蛇向右移动
 90     moveDirection = 4;    
 91 }
 92 
 93 void show()  // 显示画面
 94 {
 95     gotoxy(0,0);  // 光标移动到原点位置,以下重画清屏
 96     int i,j;
 97     for (i=0;i<High;i++)
 98     {
 99         for (j=0;j<Width;j++)
100         {
101             if (canvas[i][j]==0)
102                 printf(" ");   //   输出空格
103             else if (canvas[i][j]==-1)
104                 printf("#");   //   输出边框#
105             else if (canvas[i][j]==1)
106                 printf("@");   //   输出蛇头@
107             else if (canvas[i][j]>1)
108                 printf("*");   //   输出蛇身*
109         }
110         printf("\n");
111     }
112     Sleep(100);
113 }    
114 
115 void updateWithoutInput()  // 与用户输入无关的更新
116 {
117     moveSnakeByDirection();
118 }
119 
120 void updateWithInput()  // 与用户输入有关的更新
121 {
122 }
123 
124 int main()
125 {
126     startup();  // 数据初始化    
127     while (1) //  游戏循环执行
128     {
129         show();  // 显示画面
130         updateWithoutInput();  // 与用户输入无关的更新
131         updateWithInput();  // 与用户输入有关的更新
132     }
133     return 0;
134 }

3 玩家控制小蛇移动

这一步的实现比较简单,在updateWithInput()函数中按asdw键改变moveDirection的值,然后调用moveSnakeByDirection()实现小蛇向不同方向的移动,如图所示。

 

 1 void updateWithInput()  // 与用户输入有关的更新
 2     //C语言自学网
 3 {
 4     char input;
 5     if(kbhit())  // 判断是否有输入
 6     {
 7         input = getch();  // 根据用户的不同输入来移动,不必输入回车
 8         if (input == 'a') 
 9         {
10             moveDirection = 3;   // 位置左移
11             moveSnakeByDirection();
12         }
13         else if (input == 'd')
14         {
15             moveDirection = 4;  // 位置右移
16             moveSnakeByDirection();
17         }
18         else if (input == 'w')
19         {
20             moveDirection = 1;  // 位置上移
21             moveSnakeByDirection();
22         }
23         else if (input == 's')
24         {
25             moveDirection = 2;   // 位置下移
26             moveSnakeByDirection();
27         }
28     }
29 }

4 判断游戏失败

当小蛇和边框或自身发生碰撞时,游戏失败,如图所示。

 1 void moveSnakeByDirection()
 2 //C语言自学网
 3 {
 4     int i,j;
 5     for (i=1;i<High-1;i++)
 6         for (j=1;j<Width-1;j++)
 7             if (canvas[i][j]>0)
 8                 canvas[i][j]++;
 9     int oldTail_i,oldTail_j,oldHead_i,oldHead_j;
10     int max = 0;
11     for (i=1;i<High-1;i++)
12         for (j=1;j<Width-1;j++)
13             if (canvas[i][j]>0)
14             {
15                 if (max<canvas[i][j])
16                 {
17                     max = canvas[i][j];
18                     oldTail_i = i;
19                     oldTail_j = j;
20                 }
21                 if (canvas[i][j]==2)
22                 {
23                     oldHead_i = i;
24                     oldHead_j = j;
25                 }
26             }
27     canvas[oldTail_i][oldTail_j] = 0;
28     int newHead_i,newHead_j;
29     if (moveDirection==1) // 向上移动
30     {
31         newHead_i = oldHead_i-1;
32         newHead_j = oldHead_j;
33     }
34     if (moveDirection==2) // 向下移动
35     {
36         newHead_i = oldHead_i+1;
37         newHead_j = oldHead_j;
38     }
39     if (moveDirection==3) // 向左移动
40     {
41         newHead_i = oldHead_i;
42         newHead_j = oldHead_j-1;
43     }
44     if (moveDirection==4) // 向右移动
45     {
46         newHead_i = oldHead_i;
47         newHead_j = oldHead_j+1;
48     }
49 
50     // 是否小蛇和自身撞,或者和边框撞,游戏失败
51     if (canvas[newHead_i][newHead_j]>0 || canvas[newHead_i][newHead_j]==-1)
52     {
53         printf("游戏失败!\n");
54         exit(0);
55     }
56     else
57         canvas[newHead_i][newHead_j] = 1;
58 }

5 吃食物增加长度

增加食物,二维数组canvas[High][Width]元素值为-2时,输出食物数值’F’,如图所示。当蛇头碰到食物时,长度加一。

 

实现思路和2中小蛇移动类似,只需保持原蛇尾,不将最大值变为0即可,下图为小蛇向上移动吃到食物的对应流程。

 

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <conio.h>
  4 #include <windows.h>
  5 //C语言自学网
  6 #define High 20  // 游戏画面尺寸
  7 #define Width 30
  8 
  9 // 全局变量
 10 int moveDirection; // 小蛇移动位置,上下左右分别用1,2,3,4表示
 11 int food_x,food_y; // 食物的位置
 12 int canvas[High][Width] = {0}; // 二维数组存储游戏画布中对应的元素
 13     // 0为空格0,-1为边框#,-2为食物F,1为蛇头@,大于1的正数为蛇身*
 14 
 15 void gotoxy(int x,int y)  //光标移动到(x,y)位置
 16 {
 17     HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
 18     COORD pos;
 19     pos.X = x;
 20     pos.Y = y;
 21     SetConsoleCursorPosition(handle,pos);
 22 }
 23 
 24 // 移动小蛇
 25 // 第一步扫描数组canvas所有元素,找到正数元素都+1
 26 // 找到最大元素(即蛇尾巴),把其变为0
 27 // 找到=2的元素(即蛇头),再根据输出的上下左右方向,把对应的另一个像素值设为1(新蛇头)
 28 void moveSnakeByDirection()
 29 {
 30     int i,j;
 31     for (i=1;i<High-1;i++)
 32         for (j=1;j<Width-1;j++)
 33             if (canvas[i][j]>0)
 34                 canvas[i][j]++;
 35 
 36     int oldTail_i,oldTail_j,oldHead_i,oldHead_j;
 37     int max = 0;
 38 
 39     for (i=1;i<High-1;i++)
 40         for (j=1;j<Width-1;j++)
 41             if (canvas[i][j]>0)
 42             {
 43                 if (max<canvas[i][j])
 44                 {
 45                     max = canvas[i][j];
 46                     oldTail_i = i;
 47                     oldTail_j = j;
 48                 }
 49                 if (canvas[i][j]==2)
 50                 {
 51                     oldHead_i = i;
 52                     oldHead_j = j;
 53                 }
 54             }
 55 
 56     int newHead_i,newHead_j;
 57 
 58     if (moveDirection==1) // 向上移动
 59     {
 60         newHead_i = oldHead_i-1;
 61         newHead_j = oldHead_j;
 62     }
 63     if (moveDirection==2) // 向下移动
 64     {
 65         newHead_i = oldHead_i+1;
 66         newHead_j = oldHead_j;
 67     }
 68     if (moveDirection==3) // 向左移动
 69     {
 70         newHead_i = oldHead_i;
 71         newHead_j = oldHead_j-1;
 72     }
 73     if (moveDirection==4) // 向右移动
 74     {
 75         newHead_i = oldHead_i;
 76         newHead_j = oldHead_j+1;
 77     }
 78 
 79     // 新蛇头如果吃到食物
 80     if (canvas[newHead_i][newHead_j]==-2)
 81     {
 82         canvas[food_x][food_y] = 0;
 83         // 产生一个新的食物
 84         food_x = rand()%(High-5) + 2;
 85         food_y = rand()%(Width-5) + 2;
 86         canvas[food_x][food_y] = -2;
 87 
 88         // 原来的旧蛇尾留着,长度自动+1
 89     }
 90     else // 否则,原来的旧蛇尾减掉,保持长度不变
 91         canvas[oldTail_i][oldTail_j] = 0;
 92 
 93     // 是否小蛇和自身撞,或者和边框撞,游戏失败
 94     if (canvas[newHead_i][newHead_j]>0 || canvas[newHead_i][newHead_j]==-1)
 95     {
 96         printf("游戏失败!\n");
 97         Sleep(2000);
 98         system("pause");
 99         exit(0);
100     }
101     else
102         canvas[newHead_i][newHead_j] = 1;
103 }
104 
105 void startup() // 数据初始化
106 {
107     int i,j;
108     
109     // 初始化边框
110     for (i=0;i<High;i++)
111     {
112         canvas[i][0] = -1;
113         canvas[i][Width-1] = -1;
114     }
115     for (j=0;j<Width;j++)
116     {
117         canvas[0][j] = -1;
118         canvas[High-1][j] = -1;
119     }
120     
121     // 初始化蛇头位置
122     canvas[High/2][Width/2] = 1;
123     // 初始化蛇身,画布中元素值分别为2,3,4,5....
124     for (i=1;i<=4;i++)
125         canvas[High/2][Width/2-i] = i+1;
126 
127     // 初始小蛇向右移动
128     moveDirection = 4;
129     
130     food_x = rand()%(High-5) + 2;
131     food_y = rand()%(Width-5) + 2;
132     canvas[food_x][food_y] = -2;
133 }
134 
135 void show()  // 显示画面
136 {
137     gotoxy(0,0);  // 光标移动到原点位置,以下重画清屏
138     int i,j;
139     for (i=0;i<High;i++)
140     {
141         for (j=0;j<Width;j++)
142         {
143             if (canvas[i][j]==0)
144                 printf(" ");   //   输出空格
145             else if (canvas[i][j]==-1)
146                 printf("#");   //   输出边框#
147             else if (canvas[i][j]==1)
148                 printf("@");   //   输出蛇头@
149             else if (canvas[i][j]>1)
150                 printf("*");   //   输出蛇身*
151             else if (canvas[i][j]==-2)
152                 printf("F");   //   输出食物F
153         }
154         printf("\n");
155     }
156     Sleep(100);
157 }    
158 
159 void updateWithoutInput()  // 与用户输入无关的更新
160 {
161     moveSnakeByDirection();
162 }
163 
164 void updateWithInput()  // 与用户输入有关的更新
165 {
166     char input;
167     if(kbhit())  // 判断是否有输入
168     {
169         input = getch();  // 根据用户的不同输入来移动,不必输入回车
170         if (input == 'a') 
171         {
172             moveDirection = 3;   // 位置左移
173             moveSnakeByDirection();
174         }
175         else if (input == 'd')
176         {
177             moveDirection = 4;  // 位置右移
178             moveSnakeByDirection();
179         }
180         else if (input == 'w')
181         {
182             moveDirection = 1;  // 位置上移
183             moveSnakeByDirection();
184         }
185         else if (input == 's')
186         {
187             moveDirection = 2;   // 位置下移
188             moveSnakeByDirection();
189         }
190     }
191 }
192 
193 int main()
194 {
195     startup();  // 数据初始化    
196     while (1) //  游戏循环执行
197     {
198         show();  // 显示画面
199         updateWithoutInput();  // 与用户输入无关的更新
200         updateWithInput();  // 与用户输入有关的更新
201     }
202     return 0;
203 }

6 思考题

1. 增加道具,吃完可以加命或减速;

2. 尝试实现双人版贪吃蛇


感谢你的阅读,请用心感悟!希望可以帮到爱学习的你!!分享也是一种快乐!!!请接力。。。

猜你喜欢

转载自www.cnblogs.com/kangyifan/p/13149831.html
今日推荐