当前位置:   article > 正文

项目实践:贪吃蛇

项目实践:贪吃蛇

     1.贪吃蛇的实现环境

                在实现贪吃蛇之前,我们得先把环境改成Windows环境的控制台中来实现,而不是在终端上。

终端

 修改成控制台

        但有些电脑就算改成让Windows决定也还是终端,解决办法就是直接改成Windows控制台主机即可

2.贪吃蛇项目目标

        使用C语言在Windows环境的控制台中实现。

        实现基本功能:

。贪吃蛇地图的绘制

。贪吃蛇的创建

。蛇身的控制(上、下、左、右控制蛇的移动)

。蛇身的加速、减速

。计算得分

。暂停游戏

。蛇撞墙死亡

。蛇撞自身死亡等

        涉及的知识点:

。C语言函数

。枚举

。结构体

。动态内存管理

。预处理命令

。链表

。Win32 API 等

        要用到的Win32 API知识

1.mode命令(修改窗口大小)

2.title命令(修改窗口名字)

3.COORD(修改屏幕上的坐标)

4.GetStdHandle(用来获取句柄,并对设备进行操作)

5.GetConsoleCursorInfo(获取控制台屏幕上的光标信息)

6.CONSOLE_CURSOR_INFO修改控制台屏幕上的光标大小和可见性

7.SetConsoleCursorInfo(设置控制台屏幕上的光标大小和可见性)

8.SetConsoleCursorPosition(设置控制台屏幕上光标的位置)

9.GetAsyncKeyState(获取按键情况,通过返回值来判断按键的状态)

        这里要用到的一系列知识点就不一一介绍了,各位可以自行去了解,在贪吃蛇实现部分我也会去讲到
 

3.贪吃蛇的游戏设计与实现

        实现贪吃蛇游戏,我们需要创建三个文件:一个头文件和两个源文件

Gsnake.h :用来定义函数,贪吃蛇蛇身(链表)和贪吃蛇的各种属性

Gsnake.c :用来实现游戏的逻辑和代码

test.c        :用来测试

3.1 游戏的初始化

        首先就是初始化地图,初始化之前我们得先知道我们想要的地图样式以及如何去实现

        首先介绍第一个界面的打印,打印之前我们得知道坐标的概念(很重要)

坐标分为X轴和Y轴,就像数学里面的那种,但跟数学里的坐标图略有不同

                这里实现的是27行 , 58列的地图,所以我们在打印欢迎界面时要先找到我们要打印的坐标位置(往中间点就好),上代码:

        需要的头文件在Gsnake.h文件中去定义,然后再test.c和Gsnake.c文件中包含就可以了

        在test.c文件中,主要的逻辑就是测试,这里直接创建函数,然后去Gsnake.c文件中去实现就可以

        在Gsnake.c文件中要实现的就是游戏的整体思路,首先第一步,就是设置贪吃蛇界面的光标,想象一下当我们在打游戏时如果有个光标一直在闪,会玩的舒服吗?所以第一步要做的就是把光标的可见性设置成false(不可见);

        

        第二步:我们需要打印欢迎界面和游戏介绍,这里的话,如果我们直接打印,就会打印在最上面,那我们怎么让我们的字体往中间打印呢?

        这里我们就可以设置光标的坐标,让它在指定的位置进行打印,而且我们后面可能也会继续用到这个坐标的定位(如:食物的定位),所以这里干脆就分装成一个函数,每次要使用时,只需对其进行调用就可以了。

具体代码:

 Gsnake.c:

        创建函数用来实现光标的定位

        创建函数实现欢迎界面和游戏的介绍

 第二步代码的实现

        现在我们已经解决完了第一步和第二步,那么现在————

        第三步,让我们来创建墙

        墙要怎么去初始化呢?首先就是要有一个字符来做成墙,这里就用输入法自带的方框‘□’,这里我们使用宽字符来进行打印,什么是宽字符呢?一个正常的字符只占一个字节,而宽字符都是占两个字节,我们如果要用宽字符进行打印的话,就要包含头文件<locale.h>。

        前面提到,我们要初始化的地图大小是 27 行 58 列 ,如果要用宽字符进行打印,一个字符为两个字节,58/2 就是我们要打印的墙的数量,也就是29 。墙体的打印,上面跟下面是一样的,但左面和右面,怎么去实现呢?

        这里我们注意,宽字符往左右时,占两个字节,但是在往上下时,只占了一个,这是因为上下的宽度比左右宽。所以我们在打印左墙右墙时,要打印25个(包括上墙和下墙,也就是27),我们在打印时只需要改变行数就行。

        要想使用宽字符进行打印,就要进行本地化(在test.c中会展示如何本地化),宽字符的打印需要wpeintf,当然,也需要包含头文件#include<locale.h>。

上代码!

test.c:

Gsnake.c:

 Gsnake.h:

        记得定义一下使用的函数

        第四步:创建蛇和其属性

        首先,我们先分析一下蛇身要怎么去创建,经典的贪吃蛇游戏中,蛇身都是一个点和一个点连在一起进行移动,所以我们如果想实现蛇身的创建,就要创建一个链表,来对蛇身进行维护,而链表就定义在Gsnake.h头文件中,方便后续使用

Gsnake.h:

        创建完蛇身的链表之后,我们是不是还得给贪吃蛇设置属性呢?例如:蛇的速度,状态什么的,还有关于游戏的所有属性,我就笼统的放进一个结构体里面,方便进行管理和使用

        另外关于蛇的状态(游戏的状态)一般有四种:正常,撞墙死亡,撞蛇身死亡,正常退出游戏。那我们为了方便后续直接去设置游戏的状态,就可以使用枚举,把这些状态一一列举使用。还有蛇身的方向同样如此,蛇身的方向只会有上下左右这四个,所以我们这里也可以一一列举出来。

Gsnake.h:

        

        创建好之后,就可以在Gsnake.c文件中实现蛇身的创建和属性的初始化了

Gsnake.c:

        当然,头文件也有所改变(只展示新添,最后面会附上gitee,可以自行去查看)

Gsnake.h:

tect.c:

运行图:

         第五步:创建食物

         上面我们看到,游戏的相关属性除了食物都已初始化,这第五步,我们就来对食物进行初始化

        首先,食物的坐标肯定得是随机的,这里我们就要用到rand函数,但众所周知rand函数产生的值是伪随机数,所以我们得用srand添加种子来初始化它,让它达到随机数的效果

在test.c中:

        其次,产生的食物必须在2的倍数上,所以产生的随机数必须能被2整除,并且随机值不能跟蛇重叠,达成这些条件后,就可以创建食物节点进行打印了,上代码:

Gsnake.c:

        别忘记去定义一下,Gsnake.h:

代码运行图:

        好了,讲到这里,关于贪吃蛇的初始化已经全部完成了,接下来就是实现游戏的运行部分了

3.2 游戏的运行

        游戏的运行都需要些什么呢?让我们来一步步分析

        首先第一步:打印帮助信息和成绩

        首先我想在控制台屏幕的右界面上再打印一次游戏的规则来进行提示,并且把游戏的总成绩也打印出来,这里我就直接上代码了:

        这里帮助界面就打印完了,接下来的第二步,开始我们的游戏运行思路:

        第二步:判断蛇走的方向

        我们要怎么去判断用户按的是哪一个键,是想往上走,还是往下,或是想往左右?这里我们就需要去判断按键的情况,来获取用户的按键信息,前面在介绍一些Win API时,有一个函数可以获取键盘上的按键情况,这个函数就是:GetAsyncKeyState”,函数的返回值是short。

        此函数的使用必须传递虚拟按键过去,函数再通过返回值来判断按键的状态,如果返回的16位中,最高位为1,说明按键的状态是按下,如果是0,说明按键的状态是抬起。

        如果最低位被置为1则说明该按键被按过,反之为0.

贪吃蛇需要的虚拟按键:

。上 : VK_UP

。下 :VK_DOWN

。左 :VK_LEFT

。右 :  VK_RIGHT

。空格:VK_SPACE

。ESC:  VK_ESCAPE

。F3 :    VK_F3

。F4 :    VK_F4

        先把判断键盘状态的代码写出来,怎么去写呢?这里我们是要频繁获取键盘的状态,所以我们自己给这个函数定义一个宏,方便后续直接调用,我们只需要判断函数的返回值是否为1即可。

        另外,我们在一开始定义蛇的方向时,定义了右边,那如果用户上来就按左键,这样的话是不是就跟蛇身冲突了,如果蛇身在往上的时候,如果按往下的键,同样也跟蛇身冲突了,所以这里我们在判断的时候,如果蛇身往右,用户输入的方向就不能往蛇身的反方向,否则就退出判断。当然,这里的加速,减速,暂停,退出游戏,以及蛇走一步的状态,都要在此循环里面实现,上一下代码:

Gsnake.c:

        当我们判断完蛇的走向,下一步是不是得实现蛇的移动啊?所以第三步,蛇的移动以及状态

        第三步:蛇的移动以及状态

        蛇的移动的话,我们只需要创建一个新节点,然后让新节点指向蛇头的下一个位置,最后再把尾节点置为“  ”,然后释放掉,这里为什么要改成“  ”之后才释放,而不是直接释放掉呢?这里是因为那块空间已经被我们使用了,如果直接释放掉,就会有蛇尾留在那里

        就像图片中的蛇,其实长度只有5个,但因为我没有把尾节点置为空格释放,所以先改成空格再释放

             捋一下整体的逻辑:

1. 首先判断蛇的下一步位置是上下还是左右,并且让其移动

2. 然后判断下一个节点处是否是食物,如果是就吃掉食物,蛇变长一节,如果不是食物就继续走,

3.判断蛇是否撞到墙或者撞到自己

代码:

Gsnake.c

        

Gsnake.h:

        到此,关于游戏运行方面的问题已经全部解决,接下来便是游戏的善后

3.3游戏的善后工作

        游戏的善后都要做些什么呢?

1.打印死亡的原因

2.释放为贪吃蛇开辟的空间

3.是否继续游戏

上代码:

test.c:

Gsnake.h:

Gsnake.c:

        讲到这,关于贪吃蛇的实现已经全部完成,奉上博客

test - 2 - 25: 学习仓库icon-default.png?t=N7T8https://gitee.com/small-bit-f/test---2---25.git(路径在指针里面的贪吃蛇博客里面)

        那么下篇见!!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/524687
推荐阅读
相关标签
  

闽ICP备14008679号