在去年12月中,初次接触c语言,我靠着为数不多的知识,使用数组仿照写了一份贪吃蛇,现在时隔5个月,我已经有能力独立写出真正的贪吃蛇而不是简单的仿照(虽然写的是挺简单的)。
那么我们现在就正式开始今天的主题,贪吃蛇设计:
前置知识:
这一次的知识跨度有点大,介绍了不少新的内容才能完成贪吃蛇的设计,让我们先来看看前置知识:
控制台程序:
我们需要包含头文件<windows.h>
首先就来讲讲控制台的指令
cmd指令:
title指令:
system("title 贪吃蛇")
cls指令:
system("pause");
句柄:
句柄可以理解为一个可以操作其他设备的东西。
GetStdHandle函数:
HANDLE GetStdHandle (DWORD nStdHandle);
GetConsoleCursorInfo函数:
该函数的用处为检索有关指定控制台屏幕缓冲区的光标大小和可见性的信息。
该函数的形式为:
CONSOLE_CURSOR_INFO为存放光标数据的结构体。
SetConsoleCursorInfo函数
形式为:
SetConsoleCursorPosition函数
用于改变光标位置
COORD
setpos函数(自己创建)
按键判断函数GetAsyncKeyState
在贪吃蛇中最重要的内容就是按键判断,通过按键来执行操作。
将键盘上每个键的虚拟键值传递给函数,函数通过返回值来分辨按键的状态。
宽字符:
<locale.h>本地化
setlocale函数
char* setlocale (int category, const char* locale);
宽字符的打印:
程序撰写:
OK,前置知识学习完之后我们就可以进行贪吃蛇的撰写了。
首先我们先理清楚思路
游戏进行过程如下:
1.跳出两张图片提示游戏开始和按键操作
2.第三张图分为框内框外,框的外侧印着分数。
3.框内侧为小蛇和食物
4.小蛇可以通过各种按键进行操控
5.小蛇吃掉食物后会长一节,食物会再次刷新。
大致内容分为以上五部分
我们先来看下函数的头文件
头文件:
col为列数,line为行数
我们将wall,snakebody定义为墙和蛇身,方便后面的书写。
sit为situation的缩写,意味小蛇此时的状态
dir为direction的缩写,意味小蛇此时的方向
我们在定义一个结构体类型snakenode意味蛇节点。
每个节点都有他的左边和下一个节点,蛇身采用的是链表的形式。
使用typedef将蛇节点结构体改名为snakenode,该结构提的指针为psnakenode。
然后我们再写一个蛇结构体,里面存放蛇的各种数据,包括蛇的状态,头结点,单个食物的分值,当前食物的位置,小蛇的方向,总分数和休眠时间(即蛇的速度),同样进行改名操作。
然后下面的函数简单进行声明,我们后面进行介绍。
主函数:
就只有两个内容,一个为切换到本地模式,一个为游戏开始。
函数编写:
首先对随机数进行修改,保证每次游戏都是不同的情况。
然后我们打印菜单栏(即两张图)
菜单:
前面提到过的将光标状态切换为不可见
将窗口大小设置为40行100列
然后找到位置打印文字“欢迎来到贪吃蛇小游戏”
将光标切换到下一行防止接到原文字之后。
文字显示完,按下任意键之后,清屏。
重复同样的操作打印游戏按键即可。
打印墙:
传入两个参数对应行和列
将上下左右四个方向分别打印上墙即可
注意:一个宽字符对应两个普通字符,所以打印最右侧时,需要将x坐标设置为2*(列数-1)
初始化蛇:
我们现将蛇变量创建出来,然后在编写函数用来初始化蛇
传递的为蛇指针
将各项值设置好即可。
需要注意的是我们要给食物指针专门开辟一块空间用来存放食物的,与蛇节点使同一个结构体
创建蛇:
使用链表的方式将蛇节点一个一个穿上即可
创建一个新的节点指针cur。
我们给蛇身创建5个长度即可。
每一个节点都单独开辟一块空间将指针传递给cur,cur的下一个节点指向头指针,将头指针指向cur即可实现增加一个节点,即从0开始的头插。至于设置位置这项操作在头插前还是后进行都没关系。只需要注意宽字符占2个普通字符宽度即可。
最后在每次循环插完节点之后在窗口上打印蛇身即可。
创建食物:
使用goto语句,随机到的节点如果在墙上或者在奇数位置的x上就重新随机,随机完之后再和蛇身的每一个节点进行比较,如果该点在蛇身上那么就重新上面的操作。
取到的位置合适就将蛇结构体中食物位置这一项修改为对应位置即可,在窗口上打印食物。
按键判断:
进入循环,循环退出条件为蛇不再正常。
在墙之外打印上我们的分数以及当前单个食物的分数
休眠时间也是存在蛇结构体中的。时间越长,蛇的速度越快。
在前面我们已经介绍过可以使用
#define pdVK(VK) ((GetAsyncKeyState(VK)&1))
来快速判断按键是否被按下,可以节省打字时间。
方向
如果按键方向不为蛇运动的反方向
则将蛇结构体的方向进行修改
加减速与暂停
加减速不能无上限的加速减速,我们给他设定一个范围,
在这个范围内每次加速可以增加2点食物分值,减速则减少两点,将休眠时间进行相应的增加与减少即可
如果我们按下空格(SPACE),那么就要进行暂停
stop函数很简单,死循环的进行判断即可,如果空格(SPACE)被再次按下即退出循环。
蛇的移动:
最后的最后就是我们的重中之重,蛇的运动了
经过前面的积累,蛇的移动已经显而易见了
创建下一个节点作为新的头结点
新节点为蛇头当前位置加上运动的方向。
修改完新节点后,我们还要进行判断(没错,还有)
如果新节点为食物,就进行吃食物操作
如果不是食物,就进行非食物操作
吃食物与不吃食物
传递新节点与蛇指针。
如果吃食物
那么就将新节点修改为新的头,在新节点的位置打印上蛇身,加个分,然后再创建一个新的食物即可。
如果不吃食物
新节点同样改为头结点,找到倒数第二个节点,通过倒数第二个节点先将最后一个节点的位置修改为' '(宽字符,两个' '),释放掉最后一个节点的内存,将倒数第二个节点的下一个节点置为空,那么原倒数第二个节点就成为了现在的最后一个节点。
到这里为止,大部分内容都已完成,只剩下小蛇吃到自己与撞墙死的判断了。
在小蛇移动后进行判断
撞墙死
很简单,判断蛇头是否在墙的位置,是的话将小蛇状态改为撞墙死,退出循环,否则继续寻找下一个节点,直到全部节点都遍历过。
吃到自己
从蛇头的下一个节点开始比较,如果某个节点和蛇头位置撞了则将蛇的状态修改为吃到自己,退出循环。
游戏结束
小蛇撞到墙或者吃到自己则会导致游戏结束
将光标移动到中间某个位置,打印最终的分数
打印完之后将光标移动到下方避免程序结束出现的文字截断掉贪吃蛇的画面即可
到这里,游戏已经设计完成了,让我们看下最后的效果
效果展示:
ok,文章到这里就结束了,看在博主辛辛苦苦码了这么多字的情况下点个免费的赞吧,球球了(噗通一声倒地不起)