首页文章贪吃蛇---C语言---详解手机h游戏「贪吃蛇---C语言---详解」

贪吃蛇---C语言---详解手机h游戏「贪吃蛇---C语言---详解」

时间2025-01-16 15:18:25发布yu分类文章浏览135
导读:C语言已经学了不短的时间的,这期间已经开始C++和Python的学习,想给我的C语言收个尾,想起了小时候见过别人的老人机上的贪吃蛇游戏,自己父母的手机又没有这个游戏,当时成为了我的一大遗憾,这两天发现C语言实现这个...

C语言已经学了不短的时间的,这期间已经开始C++和Python的学习,想给我的C语言收个尾,想起了小时候见过别人的老人机上的贪吃蛇游戏,自己父母的手机又没有这个游戏,当时成为了我的一大遗憾,这两天发现C语言实现这个项目似乎并不难,于是查了一些WindowsAPI的控制台函数,实现了这一游戏。如果你觉得你的C语言基础语法学的差不多了,又想实现贪吃蛇这样一个小游戏,那么就跟我一起来实现它吧。下面是最终成品的样子:

本贪吃蛇是用控制台实现,其中¥是贪吃蛇的食物,⚪是贪吃蛇,■是墙体。

在开始我们的代码之前,像讲一下关于Win32 API的相关知识,Windows这个多作业系统除了协调应用程序的执行,分配内存,管理资源之外,它同时也是一个很大的服务中心,调用这个服务中心的各种服务(每一种服务就是一个函数),可以帮应用程序达到开启视窗,绘制图形,使用周边设备等目的,由于这些函数的服务对象是应用程序(Application),所以便称之为Application Programming Interface,简称API函数。Win32 API也就是Microsoft Windows32位平台的应用程序编程接口。

平常我们运行起来的黑框其实是就是控制台程序

我们可以用cmd命令来控制控制台窗口的长宽:比如设置窗口大小,30行,100列

mode con cols=100 lines=30

同时也可以通过命令修改窗口的名字:

title 贪吃蛇

这里注意一下,在改名字之后加一个getchar()保证程序处在运行状态,这样才能正确观察到要改后的名字。

这些能在控制台窗口执行的命令,像我上方图片中的代码一样,可以用C语言函数system来执行。

代码放在下面:

 

这里注意一下system的头文件是

#include <stdlib.h>

COORD是Windows API中定义的一个结构体,表示一个字符在控制台屏幕上的坐标,下面是关于对COORD的定义:

 

其中x轴和y轴如图

同时可以给上方结构体(坐标)赋值:

COORD pos = {10,15};

GetStdHandle是一个Windows API函数。它用于一个特定的标准设备(标准输入,标准输出或标准错误)中取得一个句柄(用来标识不同设备的数值),使用这个句柄可以操作设备。

HANDLE GetStdHandle(DWORD nStdHandle);//函数的参数为标准设备

句柄是什么?

句柄相当于一个操作工具,你可以通过操作某设备的句柄去获得和修改某标准设备的信息

实例(获得句柄)

 
 

检索有关指定控制台屏幕缓冲区的光标大小和可见性信息

 

实例:

 

CONSOLE_CURSOR_INFO

在上一份代码中CursorInfo,里面存的是光标信息,类型是CONSOLE_CURSOR_INFO,我们可以来看看这个类型是如何定义的

 
  • dwSize,由光标填充的字符单元格的百分比。此值介于1到100之间。光标外观会变化,范围从完 全填充单元格到单元底部的水平线条。
  • bVisible,游标的可见性。如果光标可见,则此成员为TRUE

我们在运行打印贪吃蛇的过程中将光标设置为不可见,就不会影响到整个游戏的美观

 
 

上方的GetConsoleCursorInfo是通过函数获取光标信息,这次的函数是通过函数实在改变控制台光标信息,下面是本函数声明

 

下面看一组改变控制台光标信息的实例:

 
 

设置指定控制台缓冲区的光标位置,我们可以将坐标信息放到COORD类型的pos中,调用SetConsoleCursorPosition函数将光标位置设置到指定的控制台位置

 

 实例:

 

看到这里,我们是否可以考虑封装一个函数,可以专门通过传入坐标来控制光标位置,于是封装了一个这样的函数Setpos

 
 

这个函数用于获取按键情况,原型如下:

 

将键盘上每个键的虚拟键值传递给函数,函数通过返回值来分辨按键的状态。

GetAsyncKeyState的返回值是short类型,在上一次调用GetAsyncKeyState函数后,如果返回的16位short数据中,最高位是1,说明按键的状态是按下,如果是0,说明最高位的状态是抬起;如果最低为被设置为1则说明,该按键被按过,否则为0。

如果我们要判断一个按键是否被按过,可以检测GetAsyncKeyState的返回值最低为的值是否为1,可据此写出一个宏

 

这样就可以通过向KEY_PRESS传入键值直接监测按键是否被按过了。

下面是关于不同键值介绍的链接

Virtual-Key Codes (Winuser.h) - Win32 apps | Microsoft Learn

不过目前我们知道:

  1. VK_UP 向上箭头键 
  2. VK_DOWN 向下箭头键
  3. VK_LEFT 向左箭头键
  4. VK_RIGHT 向右箭头键
  5. VK_ESCAPE ESC按键
  6. VK_F3 F3按键
  7. VK_F4 F4按键

这些VK_XXX已经是头文件中用宏定义好的常量,直接用就行,不需要知道具体的值

就足够用了

如果想用控制台窗口打印地图,就需要了解一下控制台窗口坐标的知识

如下图所示,横向是X轴,从左向右增长,纵向是Y轴,从上到下依次增长

在地图上,我们打印墙体用宽字符■,打印蛇用宽字符●,打印食物我这里用的是宽字符¥(因为我个人比较喜欢)如果你在字符表里如果有别的喜欢的字符,也当然可以灵活的根据个人爱好改变

刚刚我介绍的时候介绍的字符是宽字符,意思是占两个字节的字符,普通的字符占一个字节

可以看看占两个字节字符和占一个字节字符的区别:

 由观察可以发现,一个占两字节的字符在控制台打印的时候也是占两个一字节字符所占的位置的

这里还需要引入一下C语言的国际化特性相关的知识,过去C语言并不适合非英语国家(地区)使用。 C语言最初假定字符都是但自己的。但是这些假定并不是在世界的任何地方都适用。

下面引用一段介绍:

C语⾔字符默认是采⽤ASCII编码的,ASCII字符集采⽤的是单字节编码,且只使⽤了单字节中的低7 位,最⾼位是没有使⽤的,可表⽰为0xxxxxxxx;可以看到,ASCII字符集共包含128个字符,在英语 国家中,128个字符是基本够⽤的,但是,在其他国家语⾔中,⽐如,在法语中,字⺟上⽅有注⾳符 号,它就⽆法⽤ASCII码表⽰。于是,⼀些欧洲国家就决定,利⽤字节中闲置的最⾼位编⼊新的符 号。⽐如,法语中的é的编码为130(⼆进制10000010)。这样⼀来,这些欧洲国家使⽤的编码体 系,可以表⽰最多256个符号。但是,这⾥⼜出现了新的问题。不同的国家有不同的字⺟,因此,哪 怕它们都使⽤256个符号的编码⽅式,代表的字⺟却不⼀样。⽐如,130在法语编码中代表了é,在希 伯来语编码中却代表了字⺟Gimel,在俄语编码中⼜会代表另⼀个符号。但是不管怎样,所有这 些编码⽅式中,0--127表⽰的符号是⼀样的,不⼀样的只是128--255的这⼀段。 ⾄于亚洲国家的⽂字,使⽤的符号就更多了,汉字就多达10万左右。⼀个字节只能表⽰256种符号, 肯定是不够的,就必须使⽤多个字节表达⼀个符号。⽐如,简体中⽂常⻅的编码⽅式是GB2312,使 ⽤两个字节表⽰⼀个汉字,所以理论上最多可以表⽰256x256=65536个符号。

后来为了使C语言适应国际化,C语言的标准中不断加入了国际化的支持。比如:加入宽字符的类型wchar_t和宽字符的输入,输出函数,加入<locale.h>头文件,其中提供了允许程序员针对特定地区(通常是国家或者说某种特定语言的地理区域)调整程序行为的函数。

刚才打印方框的过程提到了本地化,如果不进行本地化,■将无法被程序编译识别,最终只会打印问号,所以接下来我们讲讲如何运用<locale.h>以及其函数对编译环境进行本地化。

<locale.h>提供的函数用于控制C标准库中对于不同的地区会产生不一样的行为的部分。

标准中,依赖地区的部分有以下几项:

  • 数字的格式
  • 货币量的格式
  • 字符集
  • 日期和时间的表示形式

类项

通过修改地区,程序可以改变它的行为来适应世界的不同区域。但地区的改变可能会影响库的许多部 分,其中⼀部分可能是我们不希望修改的。所以C语言支持针对不同的类项进行修改,下面的⼀个宏, 指定⼀个类项:

  • LC_COLLATE
  •  LC_CTYPE 
  • LC_MONETARY
  • LC_NUMERIC
  • LC_TIME
  •  LC_ALL---针对所有类项修改

关于每个类项的详细说明,可参考

setlocale 函数

char* setlocale (int category, const char* locale);

setlocale函数用于修改当前地区,可以针对一个类项修改,也可以针对所有类项。

setlocale的第一个参数可以是前面说明的类项中的一个,那么只会影响一个类项,如果第一个参数是LC_ALL,那么就直接影响所有类项。

C标准给第二个参数仅定义了2种可能的取值:"C"和""。

在任意程序执行开始,都会隐藏式执行调用:

setlocale(LC_ALL,"C");

当地区设为"C"时,库函数按正常方式执行。

如果想在程序运行时改变地区,就只能显示调用setlocale函数。用""作为第二个参数,调用setlocale函数就可以切换到本地模式,这种模式会适应本地环境。

当切换到我们本地模式后,就可以支持一些宽字符(如汉字)的占位输出了。

setlocale(LC_ALL, " ");//切换到本地环境

宽字符的打印

 

这里比对的更加清晰一些,⼀个普通字符占⼀个字符的位置 但是打印⼀个汉字字符,占⽤2个字符的位置,那么我们如果 要在贪吃蛇中使⽤宽字符,就得处理好地图上坐标的计算。

关于普通字符和宽字符的处理展示大概是这个样子:

我们可以假设实现一个地图,27行,58列,围绕周围画出地图:

蛇和食物

初始化的时候,假设蛇长为5,蛇的每个节点宽字符●。这里要注意的是,蛇的每个节点和食物出现的X轴位置都要保证是二的倍数,不然会出现蛇和食物无法对齐或者蛇一半卡在墙体中的情况。

上面说了这么多,到现在终于可以讲代码了,在学了这些控制台操作和地图分析之后,相信其实聪明的你已经基本能大概想出来如何去实现贪吃蛇的逻辑了,在开始代码之前,来介绍一下我们对我们对贪吃蛇数据的维护和设计

这里讲一下定义的每个节点的结构体:

 

如果要管理整条蛇,还需要我们封装一个Snake来维护整条蛇🐍:

 

在维护整条蛇的结构体类型中,定义了两个枚举类型,分别用来表示

游戏当前的状态:

 

蛇当前的前进方向:

 
 

这里介绍整个游戏过程中的运行逻辑,我们基本也是这个顺序展开代码

 
 
 

SetPos-设置光标位置

 

CreateMap-绘制地图

 

CreateFood-初始化创建食物

 
 
 

SnakeMove-蛇移动

 
EatFood-吃到食物后蛇增长
 
NotEatFood-没有吃到食物向后移动
 
KillByWall-撞墙判定
 
KillBySelf-咬到自己判定
 
 
 
 

写了这么多,大概就介绍完了所有函数,现在将它们放到三个文件中,相应创建文件CV一下应该就能在你们的VS跑了

 
 
 
 
 
 

 

 

 

到这里,本篇博客的内容基本上就结束了,写博客不易,如果感觉对你有帮助的话,还请留个赞留个关注再走啊。博主的C语言语法学习之路到现在也算是真正结束,统计下来C语言将近学了三四遍了,在后面的时间里,我准备好好开始过数据结构的内容,这些时日是没有特别多的时间去写题攻算法了,给自己报了一堆比赛还需要去准备,还是要先把C++和Python在假期赶快速成一下,数据结构系统仔细的过上一遍,给未来打好基础。后期我还会继续产出有意思的内容,请大家多多关注我吧!

宣威版权声明:本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕,E-mail:xinmeigg88@163.com

展开全文READ MORE
贪吃蛇C语言详解解手
降价且补差价!红米K60价格直降300元,你会心动吗?红米手机价格「降价且补差价!红米K60价格直降300元,你会心动吗?」 入门智能机实惠诺基亚5250仅售850元诺基亚触屏手机「入门智能机实惠诺基亚5250仅售850元」