贪吃蛇(上)Win32API

news2024/11/16 15:48:18

感谢大佬的光临各位,希望和大家一起进步,望得到你的三连,互三支持,一起进步

个人主页:LaNzikinh-CSDN博客

文章目录

  • 前言
  • 一、Win32 API
  • 二、地图的绘制和初始化
  • 总结

前言

贪吃蛇(也叫做贪食蛇)游戏是一款休闲益智类游戏,有PC和手机等多平台版本。既简单又耐玩。该游戏通过控制蛇头方向吃蛋,从而使得蛇变得越来越长,使用C语言在Windows环境的控制台中模拟实现经典小游戏贪吃蛇。


在实现这次贪吃蛇小游戏的时候,我们需要应用到一些关于Win32 API的一些知识,所以我们把贪吃蛇游戏的实现分为上下两篇来讲,商品,我们主要就是讲解Win32 API的知识

一.Win32 API

什么是Win32 API:Win32 API Windows 这个多作业系统除了协调应用程序的执行、分配内存、管理资源之外,它同时也是⼀个很大的服务中心,调用这个服务中心的各种服务(每一种服务就是一个函数),可以帮应用程序达到开启视窗、描绘图形、使用周边设备等目的,由于这些函数服务的对象是应用程序(Application), 所以便称之为 Application

Programming Interface,简称 API 函数。WIN32 API也就是Microsoft Windows 32位平台的应用程序编程接口。

控制台程序

我们平常运行起来的黑框,他就是控制台程序,但是其实很多人都不是用的控制台程序,用的是终端,这两个是有区别的,控制台程序,它可以利用一些命令来操控终端就不可以啊,这次的贪吃蛇游戏就必须要应用控制台程序,如果还是终端操控的话,可以在设置里调回控制台程序

然后我们接下来讲一些控制指令

1.1窗口与命名

在说之前我们还要引入一个函数system 函数可以用来执行系统的命令,我们之前写的关机指令就是用的这个,这个在一些游戏项目的实现上,非常有用。

设置窗口mode con cols=100 lines=30,title 贪吃蛇重命名,这两个就是很简单的命令,利用system,可以用来改变控制台窗口的大小和控制台的名字

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

	return 0;
}

用之前记得停一下,不然看不到效果,可以用getchar获取字符来停,也可以直接用命令去暂停

1.2控制台屏幕上的坐标COORD

其实,控制台可以看成一个数轴,居然是一个数轴的话,那么数轴里面每个点就是坐标,控制台有一个特性就是竖着的坐标是横着坐标的两倍,所以说我们要完成这个游戏的话,我们肯定要想办法得知每个点的坐标,计算机中专门定义了一个关于这个坐标的结构体,我们直接用就可以了。

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

int main()
{
	COORD pos1 = { 0,0 };
	COORD pos2 = { 20,30 };

	return 0;
}

1.3 GetStdHandleGetStdHandle 函数 - Windows Console | Microsoft Learn

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

你可以把它抽象的理解成,如果我要炒饭,我炒饭的锅子前我先要获得一个句柄,这样我才能进行炒,我干什么事情之前都需要先引用下这个函数

int main()
{
	HANDLE hOutput = NULL;
	//获取标准输出的句柄
	hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
return 0;
}

这个主要是和别的函数绑定一起用,我们来看下一个

1.4GetConsoleCursorInfoGetConsoleCursorInfo 函数 - Windows Console | Microsoft Learn

这个他主要是可以获取句柄相关的控制台上的光标信息,就是我通过这个函数,我可以获取到一个光标的信息,那我要怎么拉到这个光标的信息,这里这个系统已经提前给我们定义了一个关于光标的结构体CONSOLE_CURSOR_INFO

typedef struct _CONSOLE_CURSOR_INFO {
 DWORD dwSize;
 BOOL bVisible;
} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;
int main()
{
	//获取标准输出的句柄
	HANDLE hOutput = NULL;
	hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

	//这个结构体,包含有关控制台光标的信息
	CONSOLE_CURSOR_INFO CursorInfo;

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

	printf("%d", CursorInfo.dwSize);
	//不可以直接改,因为只看到了台屏幕缓冲区的光标⼤⼩和可⻅性的信息
	return 0;
}

这时候我们会打印出一个结果25是什么意思呢?

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

因为贪吃蛇这个游戏总体下来肯定是不需要看见光标的,所以为了游戏的美观,我们要将光标进行隐藏,但是不可以直接改,因为只看到了台屏幕缓冲区的光标大小和可见性的信息所以。

1.5SetConsoleCursorInfoSetConsoleCursorInfo 函数 - Windows Console | Microsoft Learn

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

int main()
{
	//获取标准输出的句柄
	HANDLE hOutput = NULL;
	hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

	//这个结构体,包含有关控制台光标的信息
	CONSOLE_CURSOR_INFO CursorInfo;

	//获取和hOutput句柄相关的控制台上的光标信息,存放在CursorInfo去
	GetConsoleCursorInfo(hOutput, &CursorInfo);
	
	//修改光标信息
	CursorInfo.bVisible = false;

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

	return 0;
}

这样就完美的将光标隐藏了

1.6SetConsoleCursorPosition SetConsoleCursorPosition 函数 - Windows Console | Microsoft Learn

光标除了被隐藏,那么我们可不可以把光标设置到指定位置去呢?比如说我的贪吃蛇游戏标题我要把它放到中间去,那么我该如何去做呢?

开始首先我们先必须获得标准输出的句柄,然后我就要定位光标的位置先输入,我需要光标的位置,再把光标位置和句柄传入到这个函数中就可以了

int main()
{
	//获取标准输出的句柄
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	//定位光标的位置
	COORD pos= { 10,30 };
	SetConsoleCursorPosition(houtput, pos);	
	return 0;
}

但是在后续我们写贪吃蛇的时候,我们需要大量定位,我们不可能每次都去获取句柄在定位光标,所以我们可以直接把它包装成一个函数,需要的时候就直接调用

void SetPos(short x, short y)
{
	//获取标准输出的句柄
	HANDLE hOutput = NULL;
	hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	//设置标准输出上光标的位置为pos
	COORD pos = { x, y };
	SetConsoleCursorPosition(hOutput, pos);
}

int main()
{
	//获取标准输出的句柄
	HANDLE houtput = NULL;
	houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	//定位光标的位置
	/*COORD pos= { 10,30 };
	SetConsoleCursorPosition(houtput, pos);*/
	SetPos(10, 30);
	
	return 0;
}

1.7GetAsyncKeyStategetAsyncKeyState 函数 (winuser.h) - Win32 apps | Microsoft Learn

我们在玩贪吃蛇小游戏的时候,键盘点击左贪吃蛇就会向左转,他是如何感应到的呢?就和这个函数有关,这个函数它可以判断一个键是否被摁过,我们键盘上的每个键其实都有一个虚拟键代码

虚拟键码 (Winuser.h) - Win32 apps | Microsoft Learn

我们可以通过这个函数和虚拟间代码来判断一个键是是否按过没有,将键盘上每个键的虚拟键值传递给函数,函数通过返回值来分辨按键的状态。

如果我们要判断一个键是否被按过,可以检测GetAsyncKeyState返回值的最低值是否为1.那这样子的话,我们就可以通过一个宏来直接定义

 #define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )

这也是后面会用到的

然后贪吃蛇关于Win32 API的内容就没有了

二.地图的绘制和初始化

我先看看我们这次完成什么

2.1宽字符的打印

在开始前,我们还需要讲一下宽字符的打印,如图三可得地图周围的墙食物还有蛇这些符号都是宽字符,那在四中我们该如何打印宽字符呢?宽字符之所以较宽字符,是因为它跟C语言最初假定的字符不一样C语言最初假定的字符都是单字节的宽字符,他是占两个字节的过去,C语言并不适合非英语地方国家使用,所以关于宽字符的打印和C语言的国际化特性是有关系的,这里我就不多讲了,我们这里要引入一个头文件的概念就可以了

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

然后用里面的setlocale 函数,setlocale 函数用于修改当前地区,可以针对一个类项修改,也可以针对所有类项。setlocale 的第一个参数可以是前⾯说明的类项中的一个,那么每次只会影响一个类项,如果第一个参 数是LC_ALL,就会影响所有的类项。 C标准给第⼆个参数仅定义了2种可能取值:"C"(正常模式)和" "(本地模式)。

宽字符的打印那如果想在屏幕上打印宽字符,怎么打印呢?

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

2.2初始化

我们开始先把游戏进行初始化,贪吃蛇的整个身体,我们肯定要用链表的形式来构建吃一个食物,就头插一下链表,所以我们先创造一个蛇的节点的结构体,肯定要有坐标,还有指向下一个节点的指针。

//蛇身的节点类型
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 _food_weight;//一个食物的分数
	int _score;      //总成绩
	int _sleep_time; //休息时间,时间越短,速度越快,时间越长,速度越慢
}Snake, * pSnake;

蛇的方向和游戏状态,我们有两个枚举变量,方向很好理解就是上下左右

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

状态的划分好几种,比如说正常,那就是蛇没有事撞墙撞到墙撞到自己,还有正常退出游戏这几种

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

2.3地图的绘制

地图的绘制之前,我们首先要打印前面两页东西,欢迎来到贪吃蛇小游戏和游戏规则的讲解,我们直接用下标定位函数来定位注意,我现在已经切换模式了,所以我的打印要用宽字符去打印,欢迎来到游戏之后直接清屏幕,这样子就可以做到一页两页的效果了。欢迎来到游戏之后直接清屏幕

void WelcomeToGame()
{
	SetPos(40, 14);
	wprintf(L"欢迎来到贪吃蛇小游戏\n");
	SetPos(42, 20);
	system("pause");
	system("cls");
	SetPos(25, 14);
	wprintf(L"用 ↑. ↓ . ← . → 来控制蛇的移动,按F3加速,F4减速\n");
	SetPos(25, 15);
	wprintf(L"加速能够得到更高的分数\n");

	SetPos(42, 20);
	system("pause");
	system("cls");
}

先用#define来定义一个墙的宽字符

#define WALL L'□'

然后通过上下左右的顺序来打印,注意横着是竖着的两倍,所以打印左右的时候,特别是右一定要注意是两倍的关系.

void CreateMap()
{
	//上
	int i = 0;
	for (i = 0; i < 29; i++)
	{
		wprintf(L"%lc ", WALL);
	}

	//下
	SetPos(0, 26);
	for (i = 0; i < 29; i++)
	{
		wprintf(L"%lc ", WALL);
	}
	//左
	for (i = 1; i <= 25; i++)
	{
		SetPos(0, i);
		wprintf(L"%lc", WALL);
	}

	//右
	for (i = 1; i <= 25; i++)
	{
		SetPos(56, i);
		wprintf(L"%lc", WALL);
	}

}

总结

这是主要讲解了Win32 API的使用,后面在讲解贪吃蛇的实现

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

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

相关文章

Noir Dark Mode for Safari:夜间浏览的舒适伴侣

Noir Dark Mode for Safari是一款实用的浏览器插件&#xff0c;它使夜间浏览网页变得更加轻松和舒适。通过自动为访问的每个网站添加暗色模式&#xff0c;Noir减少了用户在暗光环境下浏览网页时可能产生的眼睛疲劳。 Noir的自定义功能允许用户根据自己的喜好调整暗色模式的设置…

配电室智能巡检机器人

近年来&#xff0c;生产过程高度自动化&#xff0c;各工矿企业关键场所需定期巡检维护。但目前巡检主要靠人工&#xff0c;既耗时费力效率又低&#xff0c;且受环境等因素影响&#xff0c;巡检难以全面规范&#xff0c;隐患或问题易被忽视。在此情况下&#xff0c;如何利用现有…

IoTDB 入门教程 基础篇③——基于Linux系统快速安装启动和上手

文章目录 一、前文二、下载三、解压四、上传五、启动六、执行七、停止八、参考 一、前文 IoTDB入门教程——导读 二、下载 下载二进制可运行程序&#xff1a;https://dlcdn.apache.org/iotdb/1.3.1/apache-iotdb-1.3.1-all-bin.zip 历史版本下载&#xff1a;https://archive.…

Linux Systemd基础教程

一、什么是systemd&#xff1f; systemd是Linux系统的一套基本构建模块。它提供了一个系统和服务管理器&#xff0c;作为PID 1运行并启动系统的其余部分。 systemd提供积极的并行化功能&#xff0c;使用套接字和D-Bus激活来启动服务&#xff0c;提供按需启动守护进程&#xf…

金属表面粗糙度对信号的影响

在进行PCB的传输线设计时&#xff0c;如果希望仿真结果更加贴合于实际的效果&#xff0c;就需要考虑很多的附加因素&#xff0c;比如&#xff0c;真实的叠构参数、介电常数、损耗角正切值、蚀刻因子、金属表面粗糙度、玻纤效应等&#xff0c;在常规的信号仿真中&#xff0c;前三…

Git系列:如何为不同的Git仓库设置不同的配置项?

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

如何配置X86应用程序启用大地址模式(将用户态虚拟内存从2GB扩充到3GB),以解决用户态虚拟内存不够用问题?(项目实战案例解析)

目录 1、概述 2、为什么不直接将程序做成64位的&#xff1f; 3、进程内存不足导致程序发生闪退的案例分析 3.1、问题说明 3.2、将Windbg附加到程序进程上进行动态调试 3.3、动态调试的Windbg感知到了中断&#xff0c;中断在DebugBreak函数调用上 3.4、malloc或new失败的…

新手去做抖音小店,这七点千万别忽视!建议收藏!

大家好&#xff0c;我是电商小V 今天咱们就来详细的说一下新手操作抖音小店的几个通病&#xff0c;想要去做抖音小店的小伙伴千万要注意&#xff0c;一定要避免&#xff0c;不要踩坑&#xff0c; 第一点&#xff1a;新手刚去做抖音小店不赚钱的主要原因不是因为你选择了大类目&…

从零开始Hadoop安装和配置,图文手把手教你,定位错误(已部署成功)

文章目录 时间急的可以看速成&#xff0c;虚拟机和配置方法已给出&#xff0c;提供下载的为一台主节点一台分结点的虚拟机下载&#xff0c;只需进行ip地址更换即可 [现成Hadoop配置&#xff0c;图文手把手交你](https://blog.csdn.net/weixin_52521533/article/details/1328627…

7.string

目录 学库一定会看文档 1.Member functions string介绍 2.迭代器iterator 1.正向迭代器 2.反向迭代器 3.反向const 4.反向const 3.容量capacity 0.size(),capacity(),max_size(),length() 1.扩容机制&#xff08;vs和Linux g对比&#xff09; 2.clear&#xff08;&a…

从电商系统认识数据与数据的存储

相信各位读者一年不知道要多少次通过电商App浏览和购买商品。既然大家对电商系统都比较熟悉&#xff0c;我将以电商系统作为研究对象&#xff0c;进一步聊聊数据与数据存储的相关内容。 比如我们在某平台搜索“文件系统”这个关键字&#xff0c;想看看这方面的书籍。当我们输入…

环形链表面试题详解

A. 环形链表1 给你一个链表的头节点 head &#xff0c;判断链表中是否有环. 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置…

Typescript语法二

继承 继承是⾯向对象编程中的重要机制&#xff0c;允许⼀个类&#xff08;⼦类或派⽣类&#xff09;继承另⼀个类&#xff08;⽗类或基类&#xff09;的属性和⽅法。⼦类可以直接使⽤⽗类的特性&#xff0c;并根据需要添加新的特性或覆盖现有的特性。这种机制赋予⾯向对象程序良…

OpenCV的周期性噪声去除滤波器(70)

返回:OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇:OpenCV如何通过梯度结构张量进行各向异性图像分割(69) 下一篇 :OpenCV如何为我们的应用程序添加跟踪栏(71) 目录 目标 理论 如何消除傅里叶域中的周期性噪声&#xff1f; 源代码 解释 结果 目…

C语言——指针的奥秘(1.0)

指针 一.内存和地址1.内存2.编址 二.指针变量和指针1.取地址操作符&#xff08;&&#xff09;2.指针变量和解引用操作符&#xff08;*&#xff09;1.指针变量2.拆解指针类型3.解引用操作符4.指针变量的大小 三.指针变量的类型和意义1.指针的解引用2.指针 - 整数3.void* 指针…

54.HarmonyOS鸿蒙系统 App(ArkTS)tcp socket套接字网络连接收发测试

工程代码https://download.csdn.net/download/txwtech/89258409?spm1001.2014.3001.5501 54.HarmonyOS鸿蒙系统 App(ArkTS)tcp socket套接字网络连接收发测试 import socket from ohos.net.socket; import process from ohos.process; import wifiManager from ohos.wifiMana…

redis的哨兵

文章目录 一、概念手动恢复redis主从复制的流程自动回复redis主从复制的流程 二、部署三、哨兵节点的作用演示四、哨兵节点的原理 一、概念 Redis Sentinel 相关名词解释 我主要说一个场景&#xff0c;就是我们上一篇讲到的redis主从复制会遇到的问题&#xff0c;朱姐带你如…

细粒度图像分类论文研读

细粒度图像分类论文研读 摘要Abstract1. 基于细粒度图像分类的视觉语义嵌入模型1.1 文献摘要1.2 创新点1.3 模型网络结构和方法1.3.1 问题陈述1.3.2 两级卷积神经网络1.3.3 局部化 CNN1.3.4 回归排序网络1.3.5 参数学习 1.4 实验1.4.1 数据集1.4.2 实验设置1.4.3 分类结果对比1…

3.SpringSecurity基本原理

SpringSecurity本质是一个过滤器链。十多个过滤器构成一个过滤器链。 这些过滤器在项目启动就会进行加载。每个过滤器执行放行操作才会执行下一个过滤器。 常见过滤器 FilterSecurityInterceptor 是一个方法级的权限过滤器&#xff0c;基本位于过滤器链的最底部。 Excepti…

图神经网络综述和学习路径

应用邻域 应用举例 应用层面&#xff08;节点&#xff0c;连接&#xff0c;子图&#xff0c;全图&#xff09; 概念区别 图神经网络本质上解决了表示学习的问题 可以把神经网络看作一个黑箱&#xff0c;图中的f函数 困难与挑战 现代的深度学习&#xff0c;如何把图输入到神经…