【C语言】贪吃蛇项目(1) - 部分Win32 API详解 及 贪吃蛇项目思路

news2025/1/18 21:01:41

文章目录

  • 一、贪吃蛇项目需要实现的基本功能
  • 二、Win32 API介绍
    • 2.1 控制台
    • 2.2 部分控制台命令及调用函数
      • mode 和 title 命令
      • COORD 命令
      • GetStdHandle(获取数据)
      • GetConsoleCursorInfo(获取光标数据)
      • SetConsoleCursorInfo (设置光标属性)
      • GetAsyncKeyState(获取按键情况)
  • 三、贪吃蛇项目游戏设计和分析
    • 3.1 本地化中宽字符的概念及应用
    • 3.2 蛇身及食物等初始化结构设计
    • 3.3 游戏流程设计


一、贪吃蛇项目需要实现的基本功能

  • 贪吃蛇地图绘制
  • 蛇吃食物的功能(上、下、左、右方向键控制蛇的动作)
  • 蛇撞墙死亡
  • 蛇撞自身死亡
  • 计算得分
  • 蛇身加速、减速
  • 暂停游戏

二、Win32 API介绍

本次实现贪吃蛇会使用到的一些Win32 API知识,接下来我们就学习一下。

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

2.1 控制台

我们这次的贪吃蛇项目需要用到控制台来运行,所以在什么空项目调用时应该出现的时调试控制台,就像下图这样
在这里插入图片描述
如果出现的不是 调试控制台 ,就右键调试栏,选择 属性 后找到终端,将 默认终端应用程序 改成 让Windows决定 然后确定,重新调试就行了
在这里插入图片描述

2.2 部分控制台命令及调用函数

mode 和 title 命令

我们平常调试出来的黑框其实就是控制台,对于这个控制台我们可以改变长宽,也可以改变名字,这就要用到 modetitle 命令,但是在调试时我们需要借用 system 来调用它们

//system 函数可以用来执行系统命令
int main()
{
	设置控制台相关属性
	system("mode con cols=100 lines=30");//cols-行,lines-列 
	system("title 贪吃蛇");

	//getchar(); 停止运行
	system("pause");//程序暂停
	return 0;
}

这里最后需要放上 getchar()system(“pause”) 来暂停程序,否则因为程序运行好就停止了,无法向控制台一样,直接更改控制台名字。调试结果如下
在这里插入图片描述

COORD 命令

COORD 是Windows API中定义的一个结构体,表示一个字符在控制台屏幕幕缓冲区上的坐标,坐标系(0,0)的原点位于缓冲区的顶部左侧单元格。关于控制台的坐标轴大家可以看成下图
在这里插入图片描述
这是 COORD 命令的声明,里面包含了坐标的x和y坐标,需要注意的是这里调用需要添加头文件 <Windows.h>

typedef struct _COORD {
	SHORT X;
	SHORT Y;
} COORD, * PCOORD;

GetStdHandle(获取数据)

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

//函数声明
HANDLE GetStdHandle(DWORD nStdHandle);

利用这个调用函数,我们可以设定某点的坐标,比如这样

int main()
{
	//获得标准输出设备的句柄
	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	return 0;
}

我们观察 HANDlE ,发现它是重命名 void* 的一个指针变量,所以当我们不打算给某点一个确定的坐标值时,可以将它设为 NULL
在这里插入图片描述

GetConsoleCursorInfo(获取光标数据)

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

	//声明
	BOOL WINAPI GetConsoleCursorInfo(
		HANDLE hConsoleOutput,
		PCONSOLE_CURSOR_INFO lpConsoleCursorInfo
	);
	//PCONSOLE_CURSOR_INFO 是指向 CONSOLE_CURSOR_INFO 结构的指针,该结构接收有关主机游标

关于 CONSOLE_CURSOR_INFO ,这个结构体,包含有关控制台光标的信息,它里面的内容是这样

typedef struct _CONSOLE_CURSOR_INFO {
	DWORD dwSize;
	BOOL bVisible;
} CONSOLE_CURSOR_INFO, * PCONSOLE_CURSOR_INFO;
  • dwSize,由光标填充的字符单元格的百分比。此值介于1到100之间。光标外观会变化,范围从完全填充单元格到单元底部的水平线条。
  • bVisible,游标的可见性。如果光标可见,则此成员为 TRUE。我们也可以设置为 FALSE 让它变得不可见

举个例子,这样我们就可以获取和houtput句柄相关的控制台上的光标信息,存放在 cursor_info 中了

int main()
{
	//获得标准输出设备的句柄
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);

	//定义一个光标信息的结构体
	CONSOLE_CURSOR_INFO cursor_info = { 0 };

	//获取和houtput句柄相关的控制台上的光标信息,存放在cursor_info中
	GetConsoleCursorInfo(houtput, &cursor_info);

	return 0;
}

SetConsoleCursorInfo (设置光标属性)

SetConsoleCursorInfo 可以设置指定控制台屏幕缓冲区的光标的大小和可见性。

BOOL WINAPI SetConsoleCursorInfo(
	HANDLE hConsoleOutput,
	const CONSOLE_CURSOR_INFO* lpConsoleCursorInfo
);

比如我们将光标的填充变成100(默认为25)

int main()
{
	//获得标准输出设备的句柄
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);

	//定义一个光标信息的结构体
	CONSOLE_CURSOR_INFO cursor_info = { 0 };

	//获取和houtput句柄相关的控制台上的光标信息,存放在cursor_info中
	GetConsoleCursorInfo(houtput, &cursor_info);

	//修改光标占比
	cursor_info.dwSize = 100;

	//设置和houtput句柄相关的控制台上的光标信息
	SetConsoleCursorInfo(houtput, &cursor_info);

	system("pause");
	return 0;
}

我们可以发现确实发生了变化
在这里插入图片描述
既然这样,我们就可以设计一个封装方法来改变光标的位置,就不用每次改变光标位置时都写这么都行了

void set_pos(int x, int y)
{
	//获得标准输出的设备的句柄
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);

	//定位光标的位置
	COORD pos = { x,y };
	SetConsoleCursorPosition(houtput, pos);
}

int main()
{
	set_pos(10, 20);
	printf("hehe\n");

	set_pos(10, 10);
	printf("hehe\n");

	return 0;
}

在这里插入图片描述

GetAsyncKeyState(获取按键情况)

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

关于虚拟键码,大家可以点击这个链接查看 link:虚拟键码

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

如果我们要判断一个键是否被按过,可以检测GetAsyncKeyState返回值的最低值是否为1。即将它与1按位与得出结果

因此我们可以设计出这样一个宏来实现它

#define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )
//VK即按键的虚拟键码

中间一列就是虚拟键码
在这里插入图片描述

讲到这里差不多就是贪吃蛇项目所需的所有API了,但是控制台所拥有的API函数远不止如此,有兴趣的朋友可以点开下面链接 link:API函数


三、贪吃蛇项目游戏设计和分析

大家看,如果不进行处理我们地图根据坐标和宽度、高度打印出来就会是这样
在这里插入图片描述
很明显高大于宽,这样我们就不好确定贪吃蛇的每个节点,也不方便创建,
所以就需要用到宽字符

3.1 本地化中宽字符的概念及应用

简单来说,C语言设计时只考虑了英语,所以最开始只有8位二进制来存储数据,但是相对于中文的十万汉字等基数极大的语言就非常不够用,因此 本地化 应运而生,宽字符 就是其中之一。

关于本地化,也进行一个简单介绍
<locale.h>提供的函数用于控制C标准库中对于不同的地区会产生不一样行为的部分。在标准中,依赖地区的部分有以下几项:

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

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

  • LC COLLATE:影响字符串比较函数strcoll()和strxfrm()。
  • LC CTYPE:影响字符处理函数的行为。
  • LC MONETARY:影响货币格式。
  • LC_NUMERIC:影响 printf()的数字格式。
  • LC TIME:影响时间格式 strftime()和 wcsftime()。
  • LC ALL-针对所有类项修改,将以上所有类别设置为给定的语言环境。

更多: link

为了修改当前地区我们需要用到 setlocale函数

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

setlocale 的第一个参数可以是前面说明的类项中的一个,那么每次只会影响一个类项,如果第一个参数是LC ALL,就会影响所有的类项。
C标准给第二个参数仅定义了2种可能取值:“C”(正常模式)和""(本地模式)。也可以用”NULL“获取当前的默认模式

宽字符的打印

宽字符的字面量必须加上前缀“L”,否则C语言会把字面量当作窄字符类型处理。前缀“乚”在单引号前面,表示宽字符,对应 wprintf()的占位符为 %lc;在双引号前面,表示宽字符串,对应wprintf()的占位符为 %ls。

这样就能打印出来了

#include <stdio.h>
#include<locale.h>
int main() 
{
	setlocale(LC_ALL, "");
	wchar_t ch1 = L'●';
	wchar_t ch2 = L'比';
	wchar_t ch3 = L'特';
	wchar_t ch4 = L'★';
	printf("%c%c\n", 'a', 'b');
	wprintf(L"%lc\n", ch1);
	wprintf(L"%lc\n", ch2);
	wprintf(L"%lc\n", ch3);
	wprintf(L"%lc\n", ch4);
	return 0;
}

在这里插入图片描述

3.2 蛇身及食物等初始化结构设计

在游戏运行的过程中,蛇每次吃一个食物,蛇的身体就会变长一节,如果我们使用链表存储蛇的信息,那么蛇的每一节其实就是链表的每个节点。每个节点只要记录好蛇身节点在地图上的坐标就行

关于蛇身我们只需要确定蛇头的位置坐标,然后利用链表就可以找到后面的蛇身直至蛇尾

不仅如此,我们对整条蛇还需要进行一个封装,来确定方向、状态等

所以我们先利用枚举罗列方向和状态

//蛇的方向
enum DIRECTION
{
	UP = 1,
	DOWN,
	LEFT,
	RIGHT
};

//蛇的状态
//正常、撞墙、撞到自己、正常退出
enum GAME_STATUS
{
	OK,//正常状态
	KILL_BY_WALL,//撞墙
	KILL_BY_SELF,//撞到自己
	END_NORMAL//正常退出
};

然后再进行整条蛇的封装,为了方便去下一个节点的坐标及对整条蛇的实参进行改变,我们使用指针来重命名各个结构体

//蛇身的节点类型
typedef struct SnakeNode
{
	//坐标
	int x;
	int y;

	//指向下一个节点的指标
	struct SnakeNode* next;
}SnakeNode, * pSnakeNode;//将这个结构体重命名为一个指针

//贪吃蛇
typedef struct Snake
{
	pSnakeNode _pSnake;//指向蛇头的指针
	pSnakeNode _pfood;//指向食物节点的指针
	enum DIRECTION _dir;//蛇的方向
	enum GAME_STATUS _status;//游戏的状态
	int _score;//总成绩
	int _sleep_time;//休息时间,时间越短,速度越快,时间越长,速度越慢
}Snake, * pSnake;

由此一来蛇的基本结构就设置完毕了

3.3 游戏流程设计

整体流程放在下面,具体游戏实现请看下回分解😊

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数字化转型之路-云原生与ChaosMeta

作者&#xff1a;刘凇杉&#xff08;chaosmeta-platform发起人&#xff09; 一.引言 随着科技的快速发展和信息时代的到来&#xff0c;数字化转型已成为企业不可或缺的战略选择。作为中国领先的科技金融企业&#xff0c;蚂蚁集团深谙数字化转型的重要性&#xff0c;并在其转型…

LeetCode 704.二分查找

LeetCode 704.二分查找 1、题目 题目链接&#xff1a;704. 二分查找 2、思路 这道题目是要在有序数组 nums 中找到目标值 target&#xff0c;符合二分查找的前提条件&#xff08;线性表必须是有序的&#xff0c;且采用顺序存储&#xff09;。同时题目还强调数组中无重复元…

2024最新在线工具箱网站系统源码

(购买本专栏可免费下载栏目内所有资源不受限制,持续发布中,需要注意的是,本专栏为批量下载专用,并无法保证某款源码或者插件绝对可用,介意不要购买!购买本专栏住如有什么源码需要,可向博主私信,第二天即可发布!博主有几万资源) 2024最新在线工具箱网站系统源码是一…

怎样将excel的科学计数法设置为指数形式?

对了&#xff0c;这个问题中所谓的“指数形式”是指数学上书写的右上标的指数格式&#xff0c;能不能通过单元格设置来做这个格式的转换呢&#xff1f; 一、几个尝试 以下&#xff0c;以数字123000为例来说明。 情况1.转换成数学上的书写方式&#xff0c;如下图的样子&#x…

基于SpringBoot+Vue的二手车交易系统的设计与实现(源码+文档+包运行)

一.系统概述 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统二手车交易信息管理难度大&#xff0c;容错率低&…

Java面试八股之fail-fast和fail-safe的区别

简述fail-fast和fail-safe的区别 定义与基本概念 fail-fast&#xff1a; 定义&#xff1a;fail-fast是一种迭代器机制&#xff0c;当集合在迭代过程中被结构上修改&#xff08;如添加、删除元素&#xff09;&#xff0c;会立即抛出ConcurrentModificationException异常&…

离岸人民币与人民币国际化

参考 什么是离岸人民币&#xff1f;它有什么用&#xff1f; - 知乎 “人民币就是人民币&#xff0c;为什么要在它前面加上离岸二字&#xff1f;” “既然有离岸人民币&#xff0c;是否有在岸人民币&#xff1f;” 今天我们就简单了解一下什么是离岸人民币。 离岸/在岸人民币…

朗致集团面试-Java架构师

总结 三轮面试&#xff0c;第一轮是逻辑测试性格测试&#xff0c;第二轮是技术面试&#xff08;面试官-刘老师&#xff09;&#xff0c;第三轮是CTO面试&#xff08;面试官-屠老师&#xff09;。如果第三轮面试通过&#xff0c;考官会问你薪资意向&#xff0c;如果满意的话HR就…

5. Mysql的binlog介绍

参考&#xff1a;InnoDB学习&#xff08;三&#xff09;之BinLog 1. BinLog介绍 BinLog又称为二进制日志&#xff0c;是MySQL服务层的数据日志&#xff0c;MySQL所有的存储引擎都支持BinLog。 BinLog记录了MySQL中的数据更新和可能导致数据更新的事件&#xff0c;可以用于主从…

2024阿里云4核8G服务器租用优惠价格700元一年

阿里云4核8G服务器租用优惠价格700元1年&#xff0c;配置为ECS通用算力型u1实例&#xff08;ecs.u1-c1m2.xlarge&#xff09;4核8G配置、1M到3M带宽可选、ESSD Entry系统盘20G到40G可选&#xff0c;CPU采用Intel(R) Xeon(R) Platinum处理器&#xff0c;阿里云优惠 aliyunfuwuqi…

必应Bing国内广告推广,帮助企业降低获客成本!

搜索引擎广告作为数字营销的重要手段之一&#xff0c;因其精准定位和效果可衡量而备受青睐。而在众多搜索引擎平台中&#xff0c;必应Bing以其独特的市场定位和用户群体成为不可忽视的广告推广渠道。云衔科技作为一家专业的数字营销服务提供商&#xff0c;致力于帮助企业实现高…

代码随想录-算法训练营day15【二叉树02:层序遍历、翻转二叉树、对称二叉树】

代码随想录-035期-算法训练营【博客笔记汇总表】-CSDN博客 第六章 二叉树 part02今日内容&#xff1a; ● 层序遍历 10 ● 226.翻转二叉树 ● 101.对称二叉树 2 详细布置 层序遍历 看完本篇可以一口气刷十道题&#xff0c;试一试&#xff0c; 层序遍历并不难&#xff0c;大…

组织机构代码是哪几位?营业执照怎么看组织机构代码?

组织机构代码是哪几位? 组织机构代码通常指的是组织机构代码证上的一组特定数字&#xff0c;它用于唯一标识一个组织或机构。在中国&#xff0c;组织机构代码由9位数字组成&#xff0c;前8位是本体代码&#xff0c;最后1位是校验码。这组代码是按照国家有关标准编制的&#x…

C# danbooru Stable Diffusion 提示词反推 OpenVINO Demo

C# danbooru Stable Diffusion 提示词反推 OpenVINO Demo 目录 说明 效果 模型信息 项目 代码 下载 说明 模型下载地址&#xff1a;https://huggingface.co/deepghs/ml-danbooru-onnx 效果 模型信息 OVVersion { BuildNumber 2023.1.0-12185-9e6b00e51cd-releases/20…

kibana源码编译

一、安装nodejs16.14.2及yarn &#xff08;一&#xff09;nodejs 1、下载 https://cdn.npmmirror.com/binaries/node/v16.14.2/node-v16.14.2-linux-x64.tar.gz2、解压 tar -zxf node-v16.14.2-linux-x64.tar.gz -C /app cd /app mv node-v16.14.2-linux-x64 node3、配置环…

redmibook 14 2020 安装 ubuntu

1. 参考博客 # Ubuntu20.10系统安装 -- 小米redmibook pro14 https://zhuanlan.zhihu.com/p/616543561# ubuntu18.04 wifi 问题 https://blog.csdn.net/u012748494/article/details/105421656/# 笔记本电脑安装了Ubuntu系统设置关盖/合盖不挂起/不睡眠 https://blog.csdn.net/…

运动想象 (MI) 分类学习系列 (7) :CMO-CNN

运动想象分类学习系列:CMO-CNN 0. 引言1. 主要贡献2. 提出的算法3. 数据增强策略4. 结果4.1 学科内分类4.2 跨学科分类4.3 数据增强策略4.4 网络可视化4.4.1 短连接可视化4.4.2 滤波器可视化4.4.3 中间特征的可视化 5. 总结欢迎来稿 论文地址&#xff1a;https://www.sciencedi…

Vue3(六):Vue3其他API、Vue3新组件Teleport、Vue2和3区别

一、其他API 1.shallowRef 与 shallowReactive &#xff08;1&#xff09;shallowRef 1. 作用&#xff1a;创建一个响应式数据&#xff0c;但只对顶层属性进行响应式处理。 2.用法&#xff1a; let myVar shallowRef(initialValue); 3. 特点&#xff1a;只跟踪引用值的变化&…

C语言学习/复习22----阶段测评编程题

一、阶段测评练习 题1&#xff1a; 题2&#xff1a;

【生成式 AI 精英速成计划】了解如何使用大模型平台、训练与部署以及如何打造生成式AI应用

目录 一、生成式 AI 带来的新挑战二、生成式 AI 精英速成计划三、技术开发技能课程体验最后 一、生成式 AI 带来的新挑战 随着计算能力的飞速提升和大数据技术的广泛应用&#xff0c;生成式AI得以取得显著进展&#xff0c;特别是在深度学习的推动下&#xff0c;机器能够生成前…