C语言·贪吃蛇游戏(上)

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 cols=100 lines=30

        当我们把这段命令敲到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 可见的。后面那个圈出来的光标是我自己点出来的,像那样的光标就是dwSize=100的光标。

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. 未完待续······

        到此,我们贪吃蛇游戏的前置知识就学完了,下节我们将着手写出这个游戏

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/364655.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Jenkins】配置及使用|参数化|邮件|源码|报表|乱码

目录 一、Jenkins 二、Jenkins环境搭建 1、下载所需的软件包 2、部署步骤 3、其他 三、Jenkins全局设置 &#xff08;一&#xff09;Manage Jenkins——Tools系统管理->全局工具配置分别配置JDK、Maven、Allure、Git&#xff0c;可以配置路径或者直接选择版本安装 1…

网络流的认识

网络流的认识 什么是流网络 网络&#xff08;network&#xff09;是指一个特殊的有向图 G ( V , E ) G (V,E) G(V,E)&#xff0c;其与一般有向图的不同之处在于有容量和源汇点&#xff0c;不考虑反向边。 其中&#xff0c;我们有以下变量来方便表示&#xff1a; S S S&…

2024美赛C题保姆级分析完整思路代码数据教学

2024美国大学生数学建模竞赛C题保姆级分析完整思路代码数据教学 C题 Momentum in Tennis 网球中的动量 在2023年温布尔登男单决赛中&#xff0c;20岁的西班牙新星卡洛斯阿尔卡拉兹击败了36岁的诺瓦克德约科维奇。这是德约科维奇自2013年以来在温布尔登的首次失利&#xff0c;也…

SwiftUI 动画入门之二:几何特效动画(GeometryEffect)

概览 在上一篇博文 SwiftUI 动画入门之一:路径动画(Path Animations)中,我们讨论了如何打造折线图(LinesGrap)形状上的路径动画。 而在本篇博文中,我们在前篇实现基础之上通过 GeometryEffect 特效为任意路径动画加上了活泼可爱的“小尾巴”。这是怎么做到的呢? 在本…

格式化内存卡后,如何找回丢失的监控视频?

随着摄像头的应用越来越广泛&#xff0c;很多监控摄像头采用了内存卡作为存储介质&#xff0c;方便用户存储和查看摄像头拍摄的视频文件。然而&#xff0c;由于各种原因&#xff0c;监控摄像头的内存卡有时会被意外格式化导致重要数据的丢失&#xff0c;给用户带来诸多困扰。 那…

有色金属矿山采选智能工厂数字孪生可视化,推进矿采选业数字化转型

有色金属矿山采选智能工厂数字孪生可视化&#xff0c;推进矿采选业数字化转型。随着科技的不断发展&#xff0c;数字化转型已经成为各行各业发展的必然趋势。有色金属矿采选业作为传统工业的重要组成部分&#xff0c;也面临着数字化转型的挑战。为了更好地推进有色金属矿采选业…

C语言字符、字符串

一、c语言字符串的本质 1、char类型数组 c语言没有专门用来存储字符串的变量类型&#xff0c;字符串都是存储在char类型的数组中&#xff0c;char类型的连续空间中每个存储单元存储一个字符&#xff0c;数组末尾以’\0’结束&#xff0c;标志字符串的结束。\0’是空字符&…

开源编辑器:ONLYOFFICE文档又更新了!

办公软件 ONLYOFFICE文档最新版本 8.0 现已发布&#xff1a;PDF 表单、RTL、单变量求解、图表向导、插件界面设计等更新。 什么是 ONLYOFFICE 文档 ONLYOFFICE 文档是一套功能强大的文档编辑器&#xff0c;支持编辑处理文本文档、电子表格、演示文稿、可填写的表单、PDF&#…

大语言模型之LlaMA系列- LlaMA 2及LLaMA2_chat(上)

LlaMA 2是一个经过预训练与微调的基于自回归的transformer的LLMs&#xff0c;参数从7B至70B。同期推出的Llama 2-Chat是Llama 2专门为对话领域微调的模型。 在许多开放的基准测试中Llama 2-Chat优于其他开源的聊天模型&#xff0c;此外Llama 2-Chat还做了可用性与安全性评估。 …

IP定位如何进行业务风控反欺诈

IP地址作为接入互联网的唯一标识&#xff0c;分析其归属地及网络类型等多维度信息&#xff0c;帮助识别虚假流量和欺诈账号&#xff0c;保障账号和交易安全&#xff0c;帮助企业持续优化风控与反欺诈模型&#xff0c;降低经济损失。 交易聚集分析 通过IP地址数据服务得到的交易…

Pytorch从零开始实战18

Pytorch从零开始实战——人脸图像生成 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——人脸图像生成环境准备模型定义开始训练可视化总结 环境准备 本文基于Jupyter notebook&#xff0c;使用Python3.8&#xff0c;Pytorch2.0.1cu118&#…

Linux下gcc的使用与程序的翻译

gcc和程序的翻译过程 gcc介绍程序的翻译过程预编译编译汇编链接 命令行式宏定义 gcc介绍 gcc是一款编译C语言编译器&#xff0c;可以把我们用vim写的代码编译成可执行程序。编译C用g进行编译&#xff0c;C的文件后缀是test.cc或test.cpp或test.cxx 如果要安装g就执行以下命令 …

一文详解docker swarm

文章目录 1、简介1.1、涉及到哪些概念&#xff1f;1.2、需要注意什么&#xff1f; 2、集群管理2.1、创建集群2.2、将节点加入集群2.3、查看集群状态。2.4、将节点从集群中移除2.5、更新集群2.6、锁定/解锁集群 3、节点管理4、服务部署4.1、准备4.2、服务管理4.2.1、常用命令4.2…

TCP 连接掉线自动重连

文章目录 TCP 连接掉线自动重连定义使用连接效果 TCP 接收数据时防止掉线。TCP 连接掉线自动重连。多线程环境下TCP掉线自动重连。 欢迎讨论更好的方法&#xff01; TCP 连接掉线自动重连 定义 定义一个类&#xff0c;以编写TCP连接函数Connect()&#xff0c;并且&#xff1a…

分发糖果[困难]

优质博文&#xff1a;IT-BLOG-CN 一、题目 n个孩子站成一排。给你一个整数数组ratings表示每个孩子的评分。你需要按照以下要求&#xff0c;给这些孩子分发糖果&#xff1a; 【1】每个孩子至少分配到1个糖果。 【2】相邻两个孩子评分更高的孩子会获得更多的糖果。 请你给每个孩…

JavaScript基础五对象 内置对象 Math.random()

内置对象-生成任意范围随机数 Math.random() 随机数函数&#xff0c; 返回一个0 - 1之间&#xff0c;并且包括0不包括1的随机小数 [0, 1&#xff09; 如何生成0-10的随机数呢&#xff1f; Math.floor(Math.random() * (10 1)) 放大11倍再向下取整 如何生成5-10的随机数&…

【智能算法】11种混沌映射算法+2种智能算法示范【鲸鱼WOA、灰狼GWO算法】

1 主要内容 混沌映射算法是我们在智能算法改进中常用到的方法&#xff0c;本程序充分考虑改进算法应用的便捷性&#xff0c;集成了11种混合映射算法&#xff0c;包括Singer、tent、Logistic、Cubic、chebyshev、Piecewise、sinusoidal、Sine、ICMIC、Circle、Bernoulli&#xf…

css实现按钮边框旋转

先上效果图 本质&#xff1a;一个矩形在两个矩形互相重叠遮盖形成的缝隙中旋转形成&#xff0c;注意css属性z-index层级关系 直接上代码 <div class"bg"><div class"button">按钮</div></div><style>.bg {width: 100%;heigh…

数字图像处理(实践篇)四十一 OpenCV-Python 使用sift算法检测图像上的特征点实践

目录 一 涉及的函数 二 实践 2004年,D.Lowe在论文Distinctive Image Features from Scale-Invariant Keypoints中提出了一种新算法,即尺度不变特征变换 (SIFT),该算法提取关键点并计算其描述符。SIFT提取图像的局部特征,在尺度空间寻找极值点,并提取出其位置尺度和方向…

绝地求生:“龙腾”通行证和新空投任务内容一览:二十级依然有图纸!

大家好&#xff0c;27.2版本终于更新完了&#xff0c;先为大家带来这次龙腾通行证的详细内容&#xff0c;显放上详细的兑换点数大家可以慢慢看。 省流: 通行证分支3仍然可解锁图纸和500G-COIN奖励&#xff0c;空投任务也可以通过做很简单的游戏任务70代币兑换获得1张图纸。 这次…