链接: 贪吃蛇源码及程序 提取码: jfsg
话不多说,先上一张贪吃蛇的流程图。给你三分钟时间,好好看看这张图,从这个图里先简单理解下整个游戏的执行过程。
那么从上面的图里,我们大概就能够知道贪吃蛇整个程序功能大致可以拆分成以下几个基本部分。
- 游戏开始界面
- 游戏地图界面(包括墙、活动区域以及🐍)
- 获取蛇移动方向(捕获键盘输入)
- 蛇移动方向控制
- 判断蛇是否吃到食物
- 生成新的食物
- 判断蛇是否撞到自身或墙壁
- 游戏结束界面
在正式讲解程序之前我们先普及点关键知识点:
1> 更改控制台输出的文本颜色
很多人都以为控制台只能显示黑白色,其实在window下是支持彩色输出的,为了不让我们的游戏显得枯燥无聊,可以通过修改这一设定来实现我们想要的颜色效果。
在windows系统下,我们可以调用Windows.h
头文件下的SetConsoleTextAttribute
函数改变文字和背景颜色。
调用形式为:SetConsoleTextAttribute( HANDLE hConsoleOutput, WORD wAttributes );
HANDLE
是long整型的别名,hConsoleOutput
是一个整数标识符,每一个整数与程序窗口一一对应,这里我们可以通过GetStdHandle(STD_OUTPUT_HANDLE)
来获得控制台窗口对应的整数标识符;
WORD
是unsigned short
整型的别名,wAttributes
表示文字颜色和背景颜色。使用低4位表示文字(前景)颜色,高4位表示文字背景颜色,所以它的取值为0x00~0xFF
。
0~F 分别代表的颜色如下:
0 = 黑色 | 1 = 淡蓝 | 2 = 淡绿 | 3 = 湖蓝 |
4 = 淡红 | 5 = 紫色 | 6 = 黄色 | 7 = 白色 |
8 = 灰色 | 9 = 蓝色 | A = 绿色 | B = 浅绿 |
C = 红色 | D = 淡紫 | E = 淡黄 | F = 亮白 |
例如:将背景设置为亮白色,文字设置为黄色。
#include <stdio.h>
#include <windows.h>
int main(){
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);//获取控制台标识符
SetConsoleTextAttribute(hConsole, 0xF6);//将控制台背景设置为亮白色,文字设置为黄色
puts("这是一个更改的文本颜色");
return 0;
}
2> 在任意位置输出文本
在一般情况下,我们都是按照顺序依次输出想要的数据到控制台上,而不去设定每次数据输出的位置。在运行贪吃蛇游戏的过程中,大部分位置的字符并不发生变化。为了提高程序效率,只需要对特定位置的字符进行更新即可。同样的,windows本身就为我们提供了这样的函数接口,即SetConsoleCursorPosition
函数。其包含在头文件windows.h中,它的调用方式为:
SetConsoleCursorPosition(HANDLE hConsoleOutput, COORD dwCursorPosition);
hConsoleOutput
的含义我们已经在前面解释过了,这里不再赘述;dwCursorPosition
是光标位置,也就是第几行第几列,它是 COORD
类型的结构体,包含两个整型变量x和y,其中x表示列,y表示行。
例如:在第5行,第10列输出“■”
;在第3行,第6列输出“★”
;在第1行,第1列输出“◆”
;最后,将坐标重新定位到第7行,第0列的位置。
#include <stdio.h>
#include <windows.h>
//自定义的光标定位函数
void setCursorPosition(int x, int y){
COORD coord;
coord.X = x;
coord.Y = y;
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hConsole, coord);
}
int main(){
setCursorPosition(10, 5);
puts("■");
setCursorPosition(6, 3);
puts("★");
setCursorPosition(1, 1);
puts("◆");
setCursorPosition(0, 7);
return 0;
}
3> 键盘输入检测
为了实现对贪吃蛇的移动方向进行控制,我们必须能够检测电脑按键的输入并判断按下的具体按键。
在Windows系统下,conio.h
头文件中的kbhit()
函数就可以用来实现键盘输入检测。
用户每按下一个键,都会将对应的字符放到输入缓冲区中,kbhit()
函数会检测缓冲区中是否有数据,如果有的话就返回非 0 值,没有的话就返回 0 值。但是kbhit()
不会读取数据,数据仍然留在缓冲区,所以一般情况下我们还要结合输入函数将缓冲区中的数据读出。请看下面的例子:
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
int main(){
char ch;
int i = 0;
//循环监听,直到按Esc键退出
while(1){
if(kbhit()){
//检测缓冲区中是否有数据
ch = toupper(getch()); //将缓冲区中的数据以字符的形式读出
printf("第%d次按下的按键是%c;\n", ++i,ch);
}
}
return 0;
}
4> 获取随机数
在实际编程中,我们经常需要生成随机数,例如,贪吃蛇游戏中在随机的位置出现食物,扑克牌游戏中随机发牌。在C语言中,我们一般使用 <stdlib.h> 头文件中的 rand() 函数来生成随机数,它的函数原型为:int rand (void)
;
rand()
会随机生成一个位于0 ~ RAND_MAX
之间的整数。
RAND_MAX 是 <stdlib.h> 头文件中的一个宏,它用来指明 rand() 所能返回的随机数的最大值。C语言标准并没有规定 RAND_MAX 的具体数值,只是规定它的值至少为 32767。在实际编程中,我们也不需要知道 RAND_MAX 的具体值,把它当做一个很大的数来对待即可。
请看示例代码:
#include <stdio.h>
#include <stdlib.h>
int main(){
for(int i=0;i<5;i++){
int R= rand()%100;
printf("新生成的随机数是%d\n",R);
}
return 0;
}
可以看到我们成功得到了随机数,但是当你关掉控制台并且重复执行这段代码时,你会依旧得到这样的结果。
这是为什么?
实际上,rand()
函数产生的随机数是伪随机数,是根据一个数值按照某个公式推算出来的,这个数值我们称之为“种子”。种子和随机数之间的关系是一种正态分布,如下图所示:
种子在每次启动计算机时是随机的,但是一旦计算机启动以后它就不再变化了;也就是说,每次启动计算机以后,种子就是定值了,所以根据公式推算出来的结果(也就是生成的随机数)就是固定的。
那么如何解决这个问题呢?
为了程序能够重复获得不同的随机数,我们经常要使用srand()
函数来重新“播种”,这样种子就会发生改变。srand()
的函数原型为:void srand (unsigned int seed)
;
它需要一个 unsigned int
类型的参数。在实际开发中,我们可以用时间作为参数,只要每次播种的时间不同,那么生成的种子就不同,最终的随机数也就不同。
在windows系统下,我们通常使用 <time.h>
头文件中的time()
函数即可得到当前的时间,就像下面这样:srand((unsigned)time(NULL))
;其中NULL
表示以当前时间作为参数对种子进行更新。
下面是一个随机数生成的实例:
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int main(){
for(int i=0;i<5;i++){
srand((unsigned)time(NULL));//以当前时间作为参数更新种子
int R= rand()%100;//生成100以内的随机数
printf("新生成的随机数是%d\n",R);
Sleep(1000);//暂停1秒,等待时间改变,否则太快时间一样得到的种子就不会变化,自然结果也不会变化
}
return 0;
}