有情怀的网站设计,宣传片拍摄手法,wordpress启用主题500错误,北京汉邦未来网站建设有限公司1. 游戏任务 使用C语言在Windows环境的控制台中模拟实现小游戏贪吃蛇 游戏中要包含以下功能#xff1a; 1. 贪吃蛇地图绘制 2. 贪吃蛇上下左右移动和吃食物 3. 蛇撞墙#xff0c;或撞到自身死亡 4. 计算得分 5. 蛇身加速、减速 6. 暂停游戏 2. Win32 API 介绍 Windows是一种多…1. 游戏任务 使用C语言在Windows环境的控制台中模拟实现小游戏贪吃蛇 游戏中要包含以下功能 1. 贪吃蛇地图绘制 2. 贪吃蛇上下左右移动和吃食物 3. 蛇撞墙或撞到自身死亡 4. 计算得分 5. 蛇身加速、减速 6. 暂停游戏 2. Win32 API 介绍 Windows是一种多作业的操作系统(同时进行多个任务进程)它除了协调应用程序的执行、分配内存、管理资源之外。它还是一个很大的服务中心服务中心有很多函数接口我们可以通过调用这些函数或者说是服务来帮助应用程序达到开启视窗、描绘图形、使用周边设备等功能。由于这些服务的对象是应用程序所以我们把这些服务称为 Application Programming Interface (应用程序编程接口) 简称API函数
2.1 控制台程序(Console) 首先操作系统是win11的朋友们要注意了我们运行程序的时候弹出的那个黑色窗口不是控制台而是win11新提供的终端窗口在终端窗口中是不能实现控制台程序中的一些功能的 上面这个窗口就是终端窗口下面我们讲解如何改成控制台窗口 鼠标放到下箭头上然后选择设置 在启动中选择Windows控制台主机并保存 下次再运行起来的就是控制台窗口了 下面我们介绍两个控制台程序命令
2.1.1 设置控制台的大小 mode con cols100 lines30 当我们把这段命令敲到cmd里头之后就会发现窗口的大小改变了 cols 控制的是列lines 控制的是行现在我们就可以根据喜好控制游戏窗口的大小了 2.1.2 设置控制台的名字 title 贪吃蛇 现在可以注意到控制台窗口的名字变成了贪吃蛇 2.1.3 system()函数 上面我们是在cmd中进行的操作那么我们如何把这些操作写进C程序中呢这时就用到了system函数system函数就相当于帮你把内容输入到控制台中了这个函数需要引用头文件stdlib.h int system (const char* command); 官网链接system - C Reference 上面我们展示了一下使用的效果我们将窗口大小和名字都修改了但是我在最后输入了一个pause暂停的语句这是因为如果不暂停的话程序就直接结束了紧接着刚刚输入的这些命令就失效了那我们就看不到效果了。 2.2 控制台屏幕上的坐标 COORD COORD 是Windows API中定义的一个结构体表示一个字符在控制台屏幕缓冲区上的坐标坐标系原点(0,0)位于缓冲区的顶部左侧单元格 COORD的类型声明差不多长这个样子 为啥说差不多呢因为在真正的声明中short是大写的因为它前面给重命名了但是其实这些我们都不必关注。 下面说一下如何使用这个结构体首先要引用头文件Windows.h然后搞一个 COORD 类型变量赋值就行 2.3 控制台的操作以及光标控制
2.3.1 GetStdHandle GetStdHandle 是一个Windows API函数它用于从一个特定的标准设备 (标准输入、标准输出或标准错误) 中取得一个句柄(用来标识不同设备的数值)使用对应的句柄可以操作对应的设备。下面我们展示一下这个函数的声明 HANDLE GetStdHandle( DWORD nStdHandle ); 官网资料GetStdHandle 函数 - Windows Console | Microsoft Learn 这个参数的类型 DWORD 看起来很迷但其实这个参数就3种输入情况 本节我们主要是用这个函数来获取控制台的标准输出句柄以此来控制控制台上输出的东西其实说白了就是把光标隐藏掉因为如果不隐藏的话光标在那里一直闪很影响游戏画面的美观性。 当我们使用这个函数的时候要先定义一个HANDLE类型的参数其实HANDLE就是一个被typedef了的 void* 类型名。当然像这种API函数都要引用头文件Windows.h后面再有用到API函数的时候我就不赘述引用头文件了。 2.3.2 GetConsoleCursorInfo 检索有关指定控制台屏幕缓冲区的光标大小和可见性的信息 BOOL WINAPI GetConsoleCursorInfo( HANDLE hConsoleOutput, PCONSOLE_CURSOR_INFO lpConsoleCursorInfo ); 官网资料GetConsoleCursorInfo 函数 - Windows Console | Microsoft Learn PCONSOLE_CURSOR_INFO 是指向 CONSOLE_CURSOR_INFO 结构的指针该指针接收有关主机游标(光标)的信息。 2.3.3 CONSOLE_CURSOR_INFO 这个结构体包含有关控制台光标的信息 typedef struct _CONSOLE_CURSOR_INFO { DWORD dwSize; BOOL bVisible; } CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO; 官网资料CONSOLE_CURSOR_INFO 结构 - Windows Console | Microsoft Learn dwSize 是由光标填充的字符单元格的百分比。此值介于1-100之间。光标外观会发生变化从0到100是光标从最下面一直上长到最上面最后填充满整个字符单元格。 bVisible 是游标的可见性一个布尔类型变量。如果光标可见此成员为true不可见为false 我们现在用一下GetConsoleCursorInfo函数把控制台中的光标信息存放到cursor_info结构体中观察光标信息cursor_info中的值其中dwSize是25对应着光标占25%的字符单元格bVisible是1对应着 true 可见的。后面那个圈出来的光标是我自己点出来的像那样的光标就是dwSize100的光标。 2.3.4 SetConsoleCursorInfo 设置指定控制台屏幕缓冲区的光标的大小和可见性 BOOL WINAPI SetConsoleCursorInfo( HANDLE hConsoleOutput, const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo ); 官网资料SetConsoleCursorInfo 函数 - Windows Console | Microsoft Learn 我们可以用访问并改变结构体cursor_info的成员然后再用SetConsoleCursorInfo把改变后的信息交给程序。像这里我就把光标的dwSize改成了50现在它看起来比25的时候高了不少。 但是我们的主要任务是要隐藏光标所以我们要修改光标的可见性当然在使用布尔类型时要注意引用头文件stdbool.h 2.3.5 SetConsoleCursorPosition 设置指定控制台屏幕缓冲区中的光标位置我们将想要设置的光标信息放在COORD类型的pos中调用SetConsoleCursorPosition函数将光标位置设置到指定的位置。 BOOL WINAPI SetConsoleCursorPosition( HANDLE hConsoleOutput, COORD pos ); 官网资料SetConsoleCursorPosition 函数 - Windows Console | Microsoft Learn 一顿操作之后你就会发现hello world并不是从左上角的(0,0)开始打印了而是从我设置好的光标位置开始打印的了。 当然为了后续方便使用我们可以把这一坨封装到一个函数里头去。 2.3.6 GetAsyncKeyState 获取按键情况GetAsyncKeyState的函数原型如下 SHORT GetAsyncKeyState( int vKey ); 官网资料GetAsyncKeyState function (winuser.h) - Win32 apps | Microsoft LearnGetAsyncKeyState 函数 winuser.h - Win32 apps |Microsoft 学习GetAsyncKeyState function (winuser.h) - Win32 apps | Microsoft Learn 将键盘上每个键的虚拟值(vKey)传递给函数函数通过返回值来分辨按键的状态。 GetAsyncKeyState的返回值时short类型在上一次调用GetAsyncKeyState函数后如果返回的16位short型数据中。如果最高位是1说明按键的状态是按下如果最高位是0说明按键的状态是抬起如果最低位是1说明按键被按过如果最低位是0说明按键没被按过。 所以我们只需要判断返回值最低位是否为1就能知道这个按键是否被按过。 虚拟键值表虚拟键码 (Winuser.h) - Win32 apps | Microsoft Learn 下面我们实现检测数字键的功能就是说我按下哪个数字键就打印出哪个数字 解释一下首先我定义的这个宏 KEY_PRESS(vk) 让得到的虚拟键的反馈值按位与 1 就能知道最后返回值的最后一位是不是1了也就是说能够检测到有没有按这键。然后写一个死循环一直判断这些虚拟键有没有被按过如果按过就把它打印出来。 既然我们能够判断数字键有没有被按过那么我们就能判断上下左右键有没有被按过我们想监测哪个键就把对应的码值写上去就好了如此说来蛇的移动问题就解决了一半了 3. 贪吃蛇游戏设计与分析
3.1 地图 我们最终的贪吃蛇游戏大概是这个样子的那我们的地图该如何布置呢 欢迎界面 操作介绍界面 游戏界面 在游戏地图上我们打印墙体使用宽字符打印蛇身使用宽字符打印食物使用宽字符 普通的字符是占一个字节的但是宽字符占两个字节而且这些宽字符在视觉效果上也是一个普通字符的二倍 这里简单讲一下C语言的国际化特性相关的知识过去C语言并不适合非英语国家使用C语言最初是美国人发明的他们的语言中就26个字母所以可能要使用到的字符非常少但是其他用语言国家就不一定够用了。所以后来为了使C语言国际化C语言的标准中不断加入了国际化的支持。比如宽字符的类型 wchar_t 和宽字符的输入和输出函数加入了locale.h 头文件其中提供了允许程序员针对特定地区调整程序行为的函数。 3.1.1 locale.h本地化 locale.h提供的函数用于控制C标准库中对于不同的地区会产生不一样行为的部分标准中依赖地区的部分有以下几项 1. 数字量的格式 2. 货币量的格式 3. 字符集 4. 日期和时间的表示形式 3.1.2 类项 通过修改地区程序可以改变它的行为来适应世界的不同区域。但地区的改变可能会影响库的许多部分其中一部分可能是我们不希望修改的。所以C语言支持针对不同的类项进行修改下面的每一个宏指定一个类项 LC_COLLATE影响字符串比较函数 strcoll() 和 strxfrm() LC_CTYPE影响字符处理函数的行为 LC_MONETARY影响货币的格式 LC_NUMERIC影响 printf() 的数字格式 LC_TIME影响时间格式 strftime() 和 wcsftime() LC_ALL针对所有类项修改将以上所有类别设置为给定的语言环境 每个类项的详细说明setlocale_wsetlocale | Microsoft Learn 3.1.3 setlocale函数 setlocale 函数用于修改当前的地区可以针对一个类项修改也可以LC_ALL修改所有 char* setlocale (int category, const char* locale); 官网资料setlocale - C Reference (cplusplus.com) setlocale 的第一个参数可以是前面讲到的任何一个类项区别就是影响哪个类项或者是全都影响 setlocale 的第二个参数仅定义了两种可能取值C (正常模式) 和 (本地模式)。本地模式就是一个空字符串就行了然后你的Windows是哪国版本就给你上那个地区的模式 当没有专门调用setlocale来控制模式的话默认是正常模式启动 setlocale的返回值是一个字符串指针表示已经设置好的格式。如果调用失败则返回空指针NULL setlocale() 可以用来查询当前地区这时第二个参数设置为NULL就可以了 setlocale() 在我们贪吃蛇项目中的用处就是把程序本地化然后来让我们使用宽字符 3.1.4 宽字符的打印 宽字符的字面量必须加上前缀 L 否则C语言会把字面量当作普通字符处理。前缀 L 在单引号前面表示宽字符宽字符的打印使用 wprintf() 打印格式前面也要加上 L 对应宽字符的占位符是 %lc 宽字符串占位符是 %ls 。汉字也是宽字符 现在我们就很明显看出来宽字符的宽了它真的占了两个字符的位置。 那么在控制台的坐标系中一个普通的字符是占一列位置的那么一个宽字符事实上要占两列位置但是它们所占的行是一样的都只占一行 3.1.5 地图坐标 我们假设要实现一个27行58列的棋盘再围绕它画出墙如图 棋盘大小可以根据自己喜好设定列数最好是行数的两倍这样差不多能是一个正方形然后列数最好设计成双数的因为棋盘的墙还有里头的蛇和食物都是宽字符 3.1.6 蛇身和食物 初始化状态假设蛇身长度是5蛇身的每个节点是 ● 蛇头出现在一个固定的坐标处比如(24,5) 处开始出现蛇连续5个节点。 注意蛇的每一个节点的x坐标必须是2的倍数否则蛇撞墙的判定会很迷 关于食物就是在墙体内随机生成一个坐标(列也同样必须是2的倍数)坐标不能和蛇身重合然后打印★ 4. 未完待续······ 到此我们贪吃蛇游戏的前置知识就学完了下节我们将着手写出这个游戏