本文详细说明了用C语言实现Snake的方法,并通过实例代码进行了详细介绍。对大家的学习或工作都有一定的参考价值。让我们和边肖一起为有需要的朋友学习吧。
目录
一、游戏说明1.1游戏按钮说明1.2评分系统二。游戏运行2.1游戏效果显示2.2纠错2.3游戏代码三, 游戏框架构建3.1游戏界面的大小3.2蛇头和蛇身3.2.1蛇头3.2.2蛇身3.3标记游戏区域3.3.1游戏区域存储的位置有哪些3.3.2使用宏使某些数字具有特殊含义3.4菜单栏的设置4.1隐藏光标的设置4.1光标信息的结构成员4.2隐藏光标的实现4.3GetStdHandle函数4.4 SetCo NsoleCursorInfo函数五、光标跳转的设置5.1光标的结构类型初始化界面6.1代码6.2系统函数6.3 SetConsoleTextAttribute函数VII。初始化蛇八号。打印蛇和盖蛇九、生成随机食物9.1效果显示9.2 srand和rand函数10、移动蛇11、游戏主逻辑函数11.1主逻辑函数11.2执行关键函数11.3判断比分并结束11.4从文件中读取历史数据11.5更新数据到文件11.6主函数11.7游戏背景音乐
一、游戏说明
1.1游戏按键说明
按上下左右箭头键改变蛇的移动方向。
短时间按下上、下、左、右其中一个箭头键,实现蛇向这个方向的短时加速运动。
按空格键暂停,然后按任意键继续游戏。
按Esc直接退出游戏。按R键重新开始游戏。
1.2计分系统
保存玩家的最高历史记录。
二、游戏运行
2.1游戏效果展示
2.2一个报错的纠正
如果出现这种情况,请相信这是编译器的问题。
(为了避免本文篇幅过长,部分不影响游戏逻辑的知识点以链接的形式展示)
解决办法
2.3游戏代码
描述:代码测试环境为visual studio 2017。
音乐文件(提取代码6666)
#包含stdio.h
#包含Windows.h
#包含stdlib.h
#包含时间. h
#包含conio.h
#includemmsystem.h
#pragma注释(lib,' Winmm.lib ')
//首先定义游戏界面的大小和游戏区域的行数和列数。
#定义第22行//游戏区域中的行数
#define COL 42 //游戏区域中的列数
#define KONG 0 //标签为空(nothing)
#定义1//在墙上做标记
#定义食物2 //标记食物
#定义头部3 //标记蛇头
#定义身体4 //标记蛇的身体
#定义向上72 //箭头键:向上
#定义向下80 //箭头键:向下
#定义左75 //箭头键:左
#定义右77 //箭头键:右
#定义空间32 //暂停
#定义ESC 27 //退出
//蛇头
结构蛇
{
int len//记录蛇的身体长度
int x;//蛇头横坐标
int y;//蛇头纵坐标
}蛇;
//蛇身
结构体
{
int x;//蛇身横坐标
int y;//蛇身纵坐标
} body[ROW * COL];//打开一个足以存储蛇体的结构数组
int face[ROW][COL];游戏区域的位置是什么,比如墙还是空,蛇身还是蛇头,都可以通过存储不同的数字来实现。
//菜单栏
void menu();
//隐藏光标
void hide cursor();
//光标跳转
void CursorJump(int x,int y);
//初始化接口
void init interface();
//颜色设置
空颜色(int c);
//从文件中读取最高分
void read grade();
//将最高分更新到文件中
void write grade();
//初始化蛇
void init snake();
//随机生成食物
void RandFood();
//判断比分和结局
void JudgeFunc(int x,int y);
//打印蛇和覆盖蛇
void DrawSnake(int标志);
//移动蛇
void MoveSnake(int x,int y);
//执行键
void run(int x,int y);
//游戏主体的逻辑功能
void游戏();
int max,grade//全局变量
int main()
{
//#pragma warning(disable: n)将报警设置为无效。
#pragma warning (disable:4996) //可以使用标准C语言提供的库函数。
menu();
max=0,grade=0;//初始化变量
srand((size _ t)time(NULL));//根据当前时间生成随机种子
系统(‘题蛇’);//设置cmd窗口的名称
系统('模式控制列=84行=23行');//设置cmd窗口的大小
hide cursor();//隐藏光标
read grade();//从文件中读取最高分到max变量
init interface();//初始化接口
init snake();//初始化蛇
RandFood();//随机生成食物
draw snake(1);//打印蛇
PlaySound(TEXT('bgmusic.wav '),NULL,SND _ FILENAME | SND _ ASYNC | SND _ LOOP);
game();//开始游戏
返回0;
}
void菜单(){
系统(‘题蛇’);
系统('模式控制列=84行=23行');//设置cmd窗口的大小
颜色(14);//将文本设置为浅黄色
printf(' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \ n ');
printf(' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *!* * * * * * * * * * * * * * * * * * * \ n’);
printf(' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \ n ');
printf(' * * * * * * * * * *上下左右按箭头键,可以改变蛇的移动方向* * * * * * * * * \ n ');
printf(' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \ n ');
printf(' * * * * * * * * * *按空格键暂停,再按任意键继续游戏* * * * * * * * * * * \ n ');
printf(' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \ n ');
printf(' * * * * * * * * * * * * * * * * * *按Esc键直接退出游戏* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \ n ');
printf(' * * * * * * * * * * * * * * * * * * * *按R键重新开始游戏* * * * * * * * * * * * * * * * * * * * * * * * * * * * \ n ');
printf(' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \ n ');
系统(“暂停”);
}
//用C语言开发游戏程序时,可以通过隐藏光标函数来解决光标闪烁的问题。
void HideCursor()
{
CONSOLE _ CURSOR _ INFO curInfo//定义光标信息的结构变量,头文件是windows.h
curinfo . dwsize=1;//如果没有赋值,光标隐藏无效。
//curinfo . b visible=TRUE;//将光标设置为可见
curinfo . b visible=FALSE;//将光标设置为不可见
HANDLE HANDLE=GetStdHandle(STD _ OUTPUT _ HANDLE);//获取控制台句柄
SetConsoleCursorInfo(handle,curInfo);//设置光标信息
}
//光标跳转
void CursorJump(int x,int y)
{
坐标位置;//定义光标位置的结构变量
位置。X=x//横坐标
位置。Y=y//纵坐标
HANDLE HANDLE=GetStdHandle(STD _ OUTPUT _ HANDLE);//获取控制台句柄
SetConsoleCursorPosition(handle,pos);//设置光标位置
}
//初始化接口
void初始接口()
{
颜色(3);//颜色设置为湖蓝色
for(int I=0;我划船;我)
{
for(int j=0;j COLj)
{
if (j==0 || j==COL - 1)
{
face[I][j]=WALL;//将此位置标记为墙
CursorJump(2 * j,I);
printf('');
}
else if (i==0 || i==ROW - 1)
{
face[I][j]=WALL;//将此位置标记为墙
printf('');
}
其他
{
face[i][j]=孔;//将此位置标记为空
}
}
}
颜色(4);//颜色设置为红色
CursorJump(0,ROW);
Printf('当前分数:%d ',等级);
CursorJump(COL,ROW);
Printf('历史最高分:%d ',max);
}
//颜色设置
空心颜色(中间)
{
SetConsoleTextAttribute(GetStdHandle(STD _ OUTPUT _ HANDLE),c);//颜色设置
//注意:SetConsoleTextAttribute是一个API(应用程序编程接口)
}
//从文件中读取最高分
void ReadGrade()
{
FILE* pf=fopen('贪吃蛇最高分记录。txt ',' r ');//以只读方式打开文件
If (pf==NULL) //无法打开文件
{
pf=fopen(‘贪吃蛇最高分记录。txt ',' w ');//以只写方式打开文件。
fwrite(max,sizeof(int),1,pf);//将max写入一个文件(此时max为0),即将最高分初始化为0。
}
fseek(pf,0,SEEK _ SET);//使文件指针pf指向文件的开头
fread(max,sizeof(int),1,pf);//将文件中的最高分读给max
fclose(pf);//关闭文件
pf=NULL//文件指针及时设置为空。
}
//将最高分更新到文件中
void WriteGrade()
{
FILE* pf=fopen('贪吃蛇最高分记录。txt ',' w ');//以只写方式打开文件。
If (pf==NULL) //无法打开文件
{
Printf('未能保存最高分记录\ n ');
退出(0);
}
fwrite(grade,sizeof(int),1,pf);//将此局的游戏分数写入文件。
fclose(pf);//关闭文件
pf=NULL//文件指针及时设置为空。
}
//初始化蛇
void InitSnake()
{
snake . len=2;//蛇的体长初始化为2
snake . x=COL/2;//蛇头位置的横坐标
snake . y=ROW/2;//蛇头位置的纵坐标
//初始化蛇体坐标
正文[0]。x=COL/2-1;
正文[0]。y=行/2;
正文[1]。x=COL/2-2;
正文[1]。y=行/2;
//标出蛇头和蛇身的位置。
face[snake . y][snake . x]=HEAD;
脸[体[0]。y][body[0]。x]=BODY;
脸[体[1]。y][body[1]。x]=BODY;
}
//随机生成食物
int my _ time=1;
void RandFood()
{
int i,j;
做
{
//随机生成食物的横坐标和纵坐标
I=rand()% ROW;
j=rand()% COL;
} while (face[i][j]!=孔);//确保生成食物的位置是空的,如果不是,重新生成。
face[I][j]=FOOD;//标记食物位置
颜色(12);//颜色设置为红色
CursorJump(2 * j,I);//光标跳转到生成的随机位置
printf('');//打印食物
}
//判断比分和结局
void JudgeFunc(int x,int y)
{
//如果蛇头即将到达的位置是食物,得分。
if(face[snake . y y][snake . x x]==FOOD)
{
snake.len//蛇身变长
等级=10;//更新当前分数
颜色(7);//颜色设置为白色
CursorJump(0,ROW);
Printf('当前分数:%d ',等级);//重新打印当前分数
RandFood();//重新随机生成食物
}
//如果蛇头即将到达的位置是墙壁或者蛇身,游戏结束。
else if(face[snake . y y][snake . x x]==WALL | | face[snake . y y][snake . x x]==BODY)
{
睡眠(1000);//留给玩家反应时间
系统(“cls”);//清除屏幕
颜色(7);//颜色设置为白色
CursorJump(2 * (COL/3),ROW/2-3);
if(最大等级)
{
Printf('恭喜打破最高纪录,最高纪录更新为%d ',成绩);
write grade();
}
else if (grade==max)
{
Printf('即使最高纪录:%d,加油,取得更好的成绩',成绩);
}
其他
{
Printf('请继续加油,目前与最高纪录相差%d ',max-grade);
}
CursorJump(2 * (COL/3),ROW/2);
printf('游戏结束');
While (1) //询问玩家是否想要另一个游戏。
{
char ch
CursorJump(2 * (COL/3),ROW/2 3);
printf(‘再来一局?(是/否):');
scanf('%c ',ch);
if (ch=='y' || ch=='Y ')
{
系统(“cls”);
main();
}
else if (ch=='n' || ch=='N ')
{
CursorJump(2 * (COL/3),ROW/2 5);
退出(0);
}
其他
{
CursorJump(2 * (COL/3),ROW/2 5);
Printf('选择错误,请重新选择');
}
}
}
}
//打印蛇和覆盖蛇
void DrawSnake(int标志)
{
If (flag==1) //打印蛇
{
颜色(10);//颜色设置为绿色
CursorJump(2 * snake.x,snake . y);
printf('');//打印蛇头
for(int I=0;i snake.len我)
{
CursorJump(2 * body[i]。x,体[i]。y);
printf('');//打印蛇体
}
}
Else //覆盖蛇
{
if (body[snake.len - 1]。x!=0) //防止len(也就是蛇变长)在(0,0)位置覆盖墙壁。
{
//用空格盖住蛇尾。
CursorJump(2 * body[snake.len - 1]。x,body[snake.len - 1]。y);
printf(“”);
}
}
}
//移动蛇
void MoveSnake(int x,int y)
{
draw snake(0);//先覆盖当前显示的蛇。
face[body[snake.len - 1]。y][body[snake.len - 1]。x]=孔;//蛇移动后,蛇的尾巴被重新标记为空
face[snake . y][snake . x]=BODY;//蛇移动后,蛇头的位置就变成了蛇身。
//蛇移动后需要更新每条蛇体的位置坐标。
for(int I=snake . len-1;I 0;我-)
{
正文[我]。x=body[i - 1]。x;
正文[我]。y=body[i - 1]。y;
}
//蛇移动后,蛇头的位置信息成为第一个蛇身的位置信息。
正文[0]。x=snake.x
正文[0]。y=snake.y
//蛇头的位置改变
snake . x=snake . x x;
snake . y=snake . y y;
draw snake(1);//在蛇移动后打印蛇
}
//执行键
空行程(整数x,整数y)
{
int t=0;
while (1)
{
如果(t==0)
t=3000//这里T越小,蛇移动越快(可以根据次数设置游戏难度)
而(-t)//如果控制移动速度,循环3000次需要一点时间。
{
if (kbhit()!=0) //如果敲击键盘,则退出循环。
打破;
}
If (t==0) //键盘没有被敲击。
{
JudgeFunc(x,y);//到达这个位置后判断游戏是否结束。
MoveSnake(x,y);//移动蛇
}
否则//敲击键盘。
{
打破;//返回游戏函数读取的键值
}
}
}
//游戏主体的逻辑功能
无效游戏()
{
int n=RIGHT//当你开始游戏时,你默认向后移动
int tmp=0;//记录蛇的移动方向
先去;//第一次进入循环,往默认方向走。
while (1)
{
n=getch();//读取键值
//在执行之前,需要调整读取的键。
开关(n)
{
案例向上:
case://如果你点击“上”或“下”
如果(tmp!=左tmp!=右)//而最后一条蛇的移动方向不是“左”也不是“右”
{
n=tmp//然后将下一条蛇的移动方向设置为上一条蛇的移动方向。
}
打破;
案例左侧:
case://如果你按“左”或“右”
如果(tmp!=UP tmp!=向下)//而最后一条蛇的移动方向不是“向上”也不是“向下”
{
n=tmp//然后将下一条蛇的移动方向设置为上一条蛇的移动方向。
}
案例空间:
案例ESC:
案例“r”:
案例“R”:
打破;//这四个不需要调整
默认值:
n=tmp//其他键无效,默认为最后一条蛇移动的方向。
打破;
}
第一次://第一次进入循环,往默认方向走。
开关(n)
{
向上://箭头键:向上
run(0,-1);//上移(横坐标偏移量为0,纵坐标偏移量为-1)
tmp=UP//记录当前蛇的移动方向
打破;
向下://箭头键:向下
run(0,1);//下移(横坐标偏移量为0,纵坐标偏移量为1)
tmp=DOWN//记录当前蛇的移动方向
打破;
Left://箭头键:left
运行(-1,0);//向左移动(横坐标偏移量为-1,纵坐标偏移量为0)
tmp=左;//记录当前蛇的移动方向
打破;
右://箭头键:右
run(1,0);//向右移动(横坐标偏移量为1,纵坐标偏移量为0)
tmp=右;//记录当前蛇的移动方向
打破;
案例空间://暂停
system(' pausenul ');//暂停后按任意键继续
打破;
案例退出://退出
系统(“cls”);//清除屏幕
颜色(7);//颜色设置为白色
CursorJump(第8列,第2行);
Printf('游戏结束');
CursorJump(COL - 8,ROW/2 2);
退出(0);
案例“r”:
案例“R”://重新开始
系统(“cls”);//清除屏幕
main();//重新执行主函数
}
}
}
三、游戏框架构建
3.1游戏界面的大小
首先定义游戏界面的大小,定义游戏区域的行数和列数。
#定义第22行//游戏区域中的行数
#define COL 42 //游戏区域中的列数
这里,蛇移动的区域称为游戏区,提示得分的区域称为提示区(提示区占一行)。
3.2蛇头和蛇身
此外,我们需要两个结构来表示蛇头和蛇身。蛇头结构存储当前蛇身的长度和蛇头的位置坐标。
3.2.1蛇头
结构蛇
{
int len//记录蛇的身体长度
int x;//蛇头横坐标
int y;//蛇头纵坐标
}蛇;
3.2.2蛇身
蛇身的位置坐标存储在蛇身结构中。
结构体
{
int x;//蛇身横坐标
int y;//蛇身纵坐标
} body[ROW * COL];//打开一个足以存储蛇体的结构数组
3.3标记游戏区
3.3.1存储游戏区的各个位置是什么
同时我们需要一个二维数组来存储游戏区域中每个位置是什么(位置是空的,墙,食物,蛇头,蛇身)。
int face[ROW][COL];//存储游戏区域的每个位置是什么,存储不同的数字就可以达到目的。
3.3.2 用宏来使某些数字具有特殊意义
为了提高代码的可读性,最好使用宏来定义空、墙、食物、蛇头和蛇身。
#define KONG 0 //标签为空(nothing)
#定义1//在墙上做标记
#定义食物2 //标记食物
#定义头部3 //标记蛇头
#定义身体4 //标记蛇的身体
当然,为了代码的可读性,我们最好也定义宏使用的键的键值。
#定义向上72 //箭头键:向上
#定义向下80 //箭头键:向下
#定义左75 //箭头键:左
#定义右77 //箭头键:右
#定义空间32 //暂停
#定义ESC 27 //退出
3.4菜单栏的设置
void菜单(){
系统(‘题蛇’);//设置窗口标题
系统('模式控制列=84行=23行');//设置cmd窗口的大小
颜色(14);//将文本设置为浅黄色
printf(' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \ n ');
printf(' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *!* * * * * * * * * * * * * * * * * * * \ n’);
printf(' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \ n ');
printf(' * * * * * * * * * *上下左右按箭头键,可以改变蛇的移动方向* * * * * * * * * \ n ');
printf(' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \ n ');
printf(' * * * * * * * * * *按空格键暂停,再按任意键继续游戏* * * * * * * * * * * \ n ');
printf(' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \ n ');
printf(' * * * * * * * * * * * * * * * * * *按Esc直接退出游戏* * * * * * * * * * * * * * * * * * * * * * * * * * * * \ n ');
printf(' * * * * * * * * * * * * * * * * * * * *按R键重新开始游戏* * * * * * * * * * * * * * * * * * * * * * * * * * * * \ n ');
printf(' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \ n ');
系统(“暂停”);//暂停程序,按任意键继续
}
下面会对这里出现的函数进行解释,以保证大家不会混淆!
四.隐藏光标的设置
隐藏光标很简单。定义一个光标信息的结构变量(结构类型系统已经定义好了),然后给光标信息赋值,最后用光标信息的结构变量设置光标信息。
4.1光标信息的结构体成员
成员的详细说明
4.2隐藏光标的实现
void HideCursor(){
CONSOLE _ CURSOR _ INFO curInfo//定义光标信息的结构变量,头文件是windows.h
curinfo . dwsize=1;//如果没有赋值,就是随机值,光标无效。
curinfo . b visible=FALSE;//将光标设置为不可见
HANDLE HANDLE=GetStdHandle(STD _ OUTPUT _ HANDLE);//获取控制台句柄
SetConsoleCursorInfo(handle,curInfo);//设置光标信息
}
4.3GetStdHandle函数
使用介绍
4.4 SetConsoleCursorInfo函数
使用介绍
五.光标跳转的设置
光标跳转,即让光标跳转到指定位置输出。类似隐藏光标的操作步骤,先定义一个光标位置的结构变量,然后设置光标的横坐标和纵坐标,最后用这个光标位置的结构变量设置光标位置。
5.1 光标位置的结构体类型
typedef struct _COORD {
短X;
短Y;
} COORD,* PCOORD
Typedef short SHORT
5.2 SetConsoleCursorPosition函数
使用介绍
5.3 光标跳转的实现
void CursorJump(int x,int y){
坐标位置;//定义光标位置的结构变量
位置。X=x//横坐标
位置。Y=y//纵坐标
HANDLE HANDLE=GetStdHandle(STD _ OUTPUT _ HANDLE);//获取控制台句柄
SetConsoleCursorPosition(handle,pos);//设置光标位置
}
六.初始化界面
初始化界面打印游戏区和提示区的“墙”。
6.1代码
int main()
{
//#pragma warning(disable: n)将报警设置为无效。
#pragma warning (disable:4996) //可以使用标准C语言提供的库函数。
系统(‘题蛇’);//设置cmd窗口的名称
系统('模式控制列=84行=23行');//设置cmd窗口的大小
hide cursor();//隐藏光标
init interface();//初始化接口
睡眠(10000);//暂停10000ms,头文件是Windows.h
返回0;
}
//初始化接口
void初始接口()
{
颜色(6);//颜色设置为卡其色
for(int I=0;我划船;我)
{
for(int j=0;j COLj)
{
if (j==0 || j==COL - 1)
{
face[I][j]=WALL;//将此位置标记为墙
CursorJump(2 * j,I);
printf('');
}
else if (i==0 || i==ROW - 1)
{
face[I][j]=WALL;//将此位置标记为墙
printf('');
}
其他
{
face[i][j]=孔;//将此位置标记为空
}
}
}
颜色(4);//颜色设置为红色
CursorJump(0,ROW);
Printf('当前分数:%d ',等级);
CursorJump(COL,ROW);
Printf('历史最高分:%d ',max);
}
//颜色设置
空心颜色(中间)
{
SetConsoleTextAttribute(GetStdHandle(STD _ OUTPUT _ HANDLE),c);//颜色设置
//注意:SetConsoleTextAttribute是一个API(应用程序编程接口)
}
6.2 system函数
使用介绍
注意:它总是程序中工作的最后一个系统(“颜色xx”)。
所以在这个游戏中没有使用system ("colorxx ")来控制游戏界面的颜色,而是使用了SetConsoleTextAttribute函数。
6.3 SetConsoleTextAttribute函数
使用介绍
七.初始化蛇
初始化一条蛇时,蛇身的长度初始化为2,蛇头的起始位置在游戏区域的中央,蛇头是第0条蛇身和左边第1条蛇身。
//初始化蛇
void InitSnake(){
snake . len=2;//蛇的体长初始化为2
snake . x=COL/2;//蛇头位置的横坐标
snake . y=ROW/2;//蛇头位置的纵坐标
//初始化蛇体坐标
正文[0]。x=COL/2-1;
正文[0]。y=行/2;
正文[1]。x=COL/2-2;
正文[1]。y=行/2;
//标出蛇头和蛇身的位置。
face[snake . y][snake . x]=HEAD;
脸[体[0]。y][body[0]。x]=BODY;
脸[体[1]。y][body[1]。x]=BODY;
}
八.打印蛇与覆盖蛇
Print snake和cover snake在这里是通过一个函数直接实现的。如果传入参数标志为1,则打印snake如果传入的参数为0,则蛇被一个空格覆盖。
印花蛇:
首先根据结构变量snake得到蛇头的坐标,在相应的位置打印蛇头。然后根据结构数组体依次得到蛇体的坐标,在相应的位置打印出来。
覆盖蛇(移动蛇后请回到这一部分):
用空格盖住最后一个蛇身就行了。
但在覆盖之前要注意判断被覆盖的位置是否为(0,0),因为当评分后蛇长增加,但新的蛇尾还没有赋值(编译器一般默认初始化为0)时,就不需要覆盖当前新的蛇尾(只需赋值新的蛇尾并打印蛇即可),我们根据最后一个蛇身得到的坐标为(0,0)。如果覆盖,将使用空格。
去掉这个判断,观察蛇吃掉食物后(0,0)位置的壁的变化,然后分析。
//打印蛇和覆盖蛇
void DrawSnake(int标志)
{
If (flag==1) //打印蛇
{
颜色(10);//颜色设置为绿色
CursorJump(2 * snake.x,snake . y);
printf('');//打印蛇头
for(int I=0;i snake.len我)
{
CursorJump(2 * body[i]。x,体[i]。y);
printf('');//打印蛇体
}
}
Else //覆盖蛇
{
if (body[snake.len - 1]。x!=0) //防止len(也就是蛇变长)在(0,0)位置覆盖墙壁。
{
//用空格盖住蛇尾。
CursorJump(2 * body[snake.len - 1]。x,body[snake.len - 1]。y);
printf(“”);
}
}
}
九、随机生成食物
//随机生成食物
void RandFood()
{
int i,j;
做
{
//随机生成食物的横坐标和纵坐标
I=rand()% ROW;
j=rand()% COL;
} while (face[i][j]!=孔);//确保生成食物的位置是空的,如果不是,重新生成。
face[I][j]=FOOD;//标记食物位置
颜色(12);//颜色设置为红色
CursorJump(2 * j,I);//光标跳转到生成的随机位置
printf('');//打印食物
}
9.1效果展示
int main(){
//#pragma warning(disable: n)将报警设置为无效。
#pragma warning (disable:4996) //可以使用标准C语言提供的库函数。
srand((size _ t)time(NULL));//根据当前时间生成一个随机种子
系统(‘题蛇’);//设置cmd窗口的名称
系统('模式控制列=84行=23行');//设置cmd窗口的大小
hide cursor();//隐藏光标
init interface();//初始化接口
init snake();//初始化蛇
draw snake(1);//打印蛇
RandFood();//随机生成食物
睡眠(10000);
返回0;
}
9.2 srand与rand函数
说明
十、移动蛇
移动蛇的作用是先覆盖当前显示的蛇,然后打印移动的蛇。
参数描述:
x:蛇相对于当前蛇移动后横坐标的变化。
y:相对于当前蛇的纵坐标移动后,蛇的纵坐标的变化。
蛇动了之后,各种信息都需要改变:
最后一条蛇的身体需要在游戏区重新标记为空。蛇头的位置需要在游戏区重新标记为蛇身。在存储蛇身坐标信息的结构数组体中,I段蛇身的坐标信息需要更新为i-1段蛇身的坐标信息,而0段即第一段蛇身的坐标信息需要更新为当前蛇头的坐标信息。蛇头的坐标信息需要根据传入的参数X和y重新计算,(请想象蛇在上述过程中移动)
//移动蛇
void MoveSnake(int x,int y){
draw snake(0);//先覆盖当前显示的蛇。
face[body[snake.len - 1]。y][body[snake.len - 1]。x]=孔;//蛇移动后,蛇的尾巴被重新标记为空
face[snake . y][snake . x]=BODY;//蛇移动后,蛇头的位置就变成了蛇身。
//蛇移动后需要更新每条蛇体的位置坐标。
for(int I=snake . len-1;I 0;我-)
{
正文[我]。x=body[i - 1]。x;
正文[我]。y=body[i - 1]。y;
}
//蛇移动后,蛇头的位置信息变成第0个蛇身的位置信息。
正文[0]。x=snake.x
正文[0]。y=snake.y
//蛇头的位置改变
snake . x=snake . x x;
snake . y=snake . y y;
draw snake(1);//在蛇移动后打印蛇
}
十一、游戏主体逻辑函数
11.1主体逻辑函数
第一次进入功能游戏,默认蛇向右移动,然后执行run功能。直到键盘被敲击,然后从运行功能返回游戏功能进行按键读取。读取键值后,需要调整读取键。调整后,按键执行,再按键读取,以此类推。
//游戏主体的逻辑功能
void Game(){
int n=RIGHT//当你开始游戏时,你默认向后移动
int tmp=0;//记录蛇的移动方向
先去;//第一次进入循环,往默认方向走。
while (1){
n=getch();//读取键值
//在执行之前,需要调整读取的键。
开关(n){
案例向上:
case://如果你点击“上”或“下”
如果(tmp!=左tmp!=RIGHT) {//而最后一条蛇的移动方向不是“左”也不是“右”
n=tmp//然后将下一条蛇的移动方向设置为上一条蛇的移动方向。
}
打破;
案例左侧:
case://如果你按“左”或“右”
如果(tmp!=UP tmp!=DOWN) {//而最后一条蛇的移动方向不是“上”也不是“下”
n=tmp//然后将下一条蛇的移动方向设置为上一条蛇的移动方向。
}
案例空间:
案例ESC:
案例“r”:
案例“R”:
打破;//这四个不需要调整
默认值:
n=tmp//其他键无效,默认为最后一条蛇移动的方向。
打破;
}
第一次://第一次进入循环,往默认方向走。
开关(n){
向上://箭头键:向上
run(0,-1);//上移(横坐标偏移量为0,纵坐标偏移量为-1)
tmp=UP//记录当前蛇的移动方向
打破;
向下://箭头键:向下
run(0,1);//下移(横坐标偏移量为0,纵坐标偏移量为1)
tmp=DOWN//记录当前蛇的移动方向
打破;
Left://箭头键:left
运行(-1,0);//向左移动(横坐标偏移量为-1,纵坐标偏移量为0)
tmp=左;//记录当前蛇的移动方向
打破;
右://箭头键:右
run(1,0);//向右移动(横坐标偏移量为1,纵坐标偏移量为0)
tmp=右;//记录当前蛇的移动方向
打破;
案例空间://暂停
system(' pausenul ');//暂停后按任意键继续
打破;
案例退出://退出
系统(“cls”);//清除屏幕
颜色(7);//颜色设置为白色
CursorJump(第8列,第2行);
Printf('游戏结束');
CursorJump(COL - 8,ROW/2 2);
退出(0);
案例“r”:
案例“R”://重新开始
系统(“cls”);//清除屏幕
main();//重新执行主函数
}
}
}
11.2执行按键函数
关键调整机制:
如果“向上”或“向下”键被按下,并且最后一条蛇的移动方向不是“左”或“右”,那么下一条蛇的移动方向被设置为最后一条蛇的移动方向,
即移动方向不变。如果敲击的是“左”或“右”键,并且上一次蛇的移动方向不是“上”或“下”,那么将下一次蛇的移动方向设置为上一次蛇的移动方向,即移动方向不变。如果敲击的按键是空格、Esc、r或是R,则不作调整。其余按键无效,下一次蛇的移动方向设置为上一次蛇的移动方向,即移动方向不变。 //执行按键 void run(int x, int y){ int t = 0; while (1){ if (t == 0) t = 3000; //这里t越小,蛇移动速度越快(可以根据次设置游戏难度) while (--t){ //控制移动速度的,循环3000次会占用一点时间 if (kbhit() != 0) //若键盘被敲击,则退出循环 break; } if (t == 0) //键盘未被敲击{ JudgeFunc(x, y); //判断到达该位置后,是否得分与游戏结束 MoveSnake(x, y); //移动蛇 } else //键盘被敲击{ break; //返回Game函数读取键值 } } }kbhit()函数
Return Value
kbhit returns a nonzero value if a key has been pressed. Otherwise, it returns 0.
执行按键
参数说明:
x:蛇移动后的横坐标相对于当前蛇的横坐标的变化。
y:蛇移动后的纵坐标相对于当前蛇的纵坐标的变化。
给定一定的时间间隔,若在该时间间隔内键盘被敲击,则退出run函数,返回Game函数进行按键读取。若未被敲击,则先判断蛇到达移动后的位置后是否得分或是游戏结束,然后再移动蛇的位置。 若键盘一直未被敲击,则就会一直执行run函数当中的while函数,蛇就会一直朝一个方向移动,直到游戏结束
11.3判断得分与结束
判断得分: 若蛇头即将到达的位置是食物,则得分。得分后需要将蛇身加长,并且更新当前得分,除此之外,还需要重新生成食物。
判断结束: 若蛇头即将到达的位置是墙或者蛇身,则游戏结束。游戏结束后比较本局得分和历史最高得分,给出相应的提示语句,并且询问玩家是否再来一局,可自由发挥。
void JudgeFunc(int x, int y){ //若蛇头即将到达的位置是食物,则得分 if (face[snake.y + y][snake.x + x] == FOOD){ snake.len++; //蛇身加长 grade += 10; //更新当前得分 color(7); //颜色设置为白色 CursorJump(0, ROW); printf("当前得分:%d", grade); //重新打印当前得分 RandFood(); //重新随机生成食物 } //若蛇头即将到达的位置是墙或者蛇身,则游戏结束 else if (face[snake.y + y][snake.x + x] == WALL || face[snake.y + y][snake.x + x] == BODY){ Sleep(1000); //留给玩家反应时间 system("cls"); //清空屏幕 color(7); //颜色设置为白色 CursorJump(2 * (COL / 3), ROW / 2 - 3); if (grade > max){ printf("恭喜你打破最高记录,最高记录更新为%d", grade); WriteGrade(); } else if (grade == max){ printf("与最高记录:%d持平,加油再创佳绩", grade); } else{ printf("请继续加油,当前与最高记录相差%d", max - grade); } CursorJump(2 * (COL / 3), ROW / 2); printf("GAME OVER"); while (1) {//询问玩家是否再来一局 char ch; CursorJump(2 * (COL / 3), ROW / 2 + 3); printf("再来一局?(y/n):"); scanf("%c", &ch); if (ch == 'y' || ch == 'Y'){ system("cls"); main(); } else if (ch == 'n' || ch == 'N'){ CursorJump(2 * (COL / 3), ROW / 2 + 5); exit(0); } else{ CursorJump(2 * (COL / 3), ROW / 2 + 5); printf("选择错误,请再次选择"); } } } }11.4从文件读取历史数据
首先需要使用fopen函数打开“贪吃蛇最高得分记录.txt”文件,若是第一次运行该代码,则会自动创建该文件,并将历史最高记录设置为0,之后再读取文件当中的历史最高记录存储在max变量当中,并关闭文件即可。
11.5更新数据到文件
首先使用fopen函数打开“贪吃蛇最高得分记录.txt”,然后将本局游戏的分数grade写入文件当中即可(覆盖式)。
//更新最高分到文件 void WriteGrade() { FILE* pf = fopen("贪吃蛇最高得分记录.txt", "w"); //以只写的方式打开文件 if (pf == NULL) //打开文件失败 { printf("保存最高得分记录失败\n"); exit(0); } fwrite(&grade, sizeof(int), 1, pf); //将本局游戏得分写入文件当中 fclose(pf); //关闭文件 pf = NULL; //文件指针及时置空 }11.6 主函数
int main() { //#pragma warning(disable: n)将某个警报置为失效 #pragma warning (disable:4996) //可以使用标准C语言提供的库函数 menu(); max = 0, grade = 0; //初始化变量 srand((size_t)time(NULL));//根据当前时间生成随机种子 system("title 贪吃蛇"); //设置cmd窗口的名字 system("mode con cols=84 lines=23"); //设置cmd窗口的大小 HideCursor(); //隐藏光标 ReadGrade(); //从文件读取最高分到max变量 InitInterface(); //初始化界面 InitSnake(); //初始化蛇 RandFood(); //随机生成食物 DrawSnake(1); //打印蛇 PlaySound(TEXT("bgmusic.wav"), NULL, SND_FILENAME | SND_ASYNC | SND_LOOP); Game(); //开始游戏 return 0; }11.7 游戏背景音乐
PlaySound函数介绍
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。