C语言实现贪吃蛇小游戏(相关Win32API介绍)

游戏实现目的

  • 贪吃蛇是久负盛名的游戏,它也和俄罗斯⽅块,扫雷等游戏位列经典游戏的⾏列。
    在学习完C语言与初步接触数据结构中的链表后,我们可以使⽤C语言在Windows环境的控制台中模拟实现经典⼩游戏贪吃蛇。巩固C语言语法,也可以提高大家对编程的兴趣。

知识要点

  • C语言函数,枚举,结构体,动态内存管理,预处理指令,链表,Win32API等。除了Win32API,其他知识点想必大家都很熟悉了,所以我们简单介绍一下实现贪吃蛇所需要的相关Win32API函数

Win32API

  • Windows 这个多作业系统除了协调应⽤程序的执⾏、分配内存、管理资源之外, 它同时也是⼀个很⼤的服务中⼼,调⽤这个服务中⼼的各种服务(每⼀种服务就是⼀个函数),可以帮应⽤程序达到开启视窗、描绘图形、使⽤周边设备等⽬的,由于这些函数服务的对象是应⽤(Application), 所以便称之为 Application Programming Interface,简称 API 函数。Win32API也就是Microsoft Windows32位平台的应⽤程序编程接⼝。
  • 通俗的说就是,每一种操作系统在完成正常的操作系统该有的功能,如文件管理,内存管理等等还提供了一些接口(函数),这些函数提供给程序员,让程序员自己调用,能够实现一些自己想要的功能。这些接口就称为API。以windows为例,这些接口称为WIN32API

控制台程序

  • 前面我们提到了在Windows环境的控制台中模拟实现经典⼩游戏贪吃蛇,也就是说我们实现的贪吃蛇游戏是在控制台中进行的
  • 控制台
  • 上面这个运行起来的黑框框程序就是我们的控制台程序(以VS2019为例)
  • 既然我们的游戏要在控制台中运行,那么我们就应该对控制台进行一些设置来达到我们的要求
    • 我们通过调⽤C语⾔函数system来对控制台的大小,名字进行操作
    • 我们通过mode命令,和title命令来进行操作
    • 设置控制台大小:mode con cols=100 lines=30
    • 设置控制台名字:title 贪吃蛇
    • 在这里插入图片描述
      在这里插入图片描述
    • 可以看到在设置不同的mode命令之后控制台大小也随之变化

WIN32API相关函数

  • 在平常的控制台窗口里我们都能看到有一闪一闪的光标,为了游戏的界面效果我们需要将光标隐匿起来,这就要用到前面提到的win32API了

GetStdHandle

  • GetStdHandle是⼀个Windows API函数。它⽤于从⼀个特定的标准设备(标准输⼊、标准输出或标准错误)中取得⼀个句柄(⽤来标识不同设备的数值),使⽤这个句柄可以操作设备。
        HANDLE GetStdHandle(DWORD nStdHandle);
  • 这里的Handle是一个结构体指针
  • 参数为标准输⼊、标准输出或标准错误(我们要对控制台进行相关操作,所以这里的参数是标准输出)
  • 实例
HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput= GetStdHandle(STD_OUTPUT_HANDLE);
  • 通俗来说就是我们要是想去操作控制台的相关信息,就要获得对应的权限,这个句柄就是授权,有了这个授权我们才能进行相关操作。就如同要使用一把斧头,我们只有握住斧柄才能使用

GetConsoleCursorInfo

  • 检索有关指定控制台屏幕缓冲区的光标⼤⼩和可⻅性的信息
 BOOL WINAPI GetConsoleCursorInfo(
 HANDLE hConsoleOutput,
 PCONSOLE_CURSOR_INFO lpConsoleCursorInfo
 );
 PCONSOLE_CURSOR_INFO 是指向 CONSOLE_CURSOR_INFO 结构的指针,该结构接收有关主机游标
  • 函数有两个参数,第一个是上面提到的句柄,第二个是一个指向CONSOLE_CURSOR_INFO结构体的指针,这个结构体包含了光标的信息
  • 实例
 HANDLE hOutput = NULL;
 //获取标准输出的句柄(⽤来标识不同设备的数值)
 hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

 CONSOLE_CURSOR_INFO CursorInfo;
 GetConsoleCursorInfo(hOutput, &CursorInfo);
  • 这个函数使我们可以获取光标的信息并对其进行修改,而这些信息都是包含在CONSOLE_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

  • CONSOLE_CURSOR_INFO

  • 在默认条件下光标是可见的,大小为四分之一个格子

  • 我们可以通过修改这两个数据来对光标进行修改。

SetConsoleCursorInfo

  • 设置指定控制台屏幕缓冲区的光标的⼤小和可见性
BOOL WINAPI SetConsoleCursorInfo(
 HANDLE hConsoleOutput,
 const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo
);
  • 这里的参数有两个,都是上面提到过的句柄和指向光标信息的结构体
  • 实例
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//影藏光标操作
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
CursorInfo.bVisible = false; //隐藏控制台光标
SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态
  • 当我们了解这个函数后我们就能对控制台的光标信息进行修改了

  • 如对光标大小进行修改,将正常的CurSorInfo.dwSize=25,改为CurSorInfo.dwSize=100

  • 在这里插入图片描述

  • 当我们进行修改后,左上角的光标已近变为一个格子的大小了

  • 接下来我们将光标隐匿起来,所以我们将CurSorInfo.bVisible=false(使用false要包函头文件<stdbool.h>)即可

  • 在这里插入图片描述

  • 此时我们可以看见光标已经隐匿起来了

光标隐匿代码

  • 此时隐匿光标的任务就完成了,我们只需要了解即可,这些函数都是windows已经提供好的,我们只需要知道如何使用就行
  • 以下就是光标隐匿的代码只需要包含<windows.h>,<stdbool.h>这两个头文件即可
//控制台窗口的设置
	system("mode con cols=100 lines=30");
	system("title 贪吃蛇");
	//光标影藏掉//*
	HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	//影藏光标操作
	CONSOLE_CURSOR_INFO CursorInfo;
	GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
	CursorInfo.bVisible = false; //隐藏控制台光标
	SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态
  • 完成光标隐匿后我们再学习一个设置坐标的函数

控制台屏幕上的坐标 COORD

  • COORD 是Windows API中定义的⼀个结构体,表⽰⼀个字符在控制台屏幕幕缓冲区上的坐标,坐标系
    (0,0) 的原点位于缓冲区的顶部左侧单元格。
    在这里插入图片描述
  • COORD类型的声明:
typedef struct _COORD {
 SHORT X;
 SHORT Y;
} COORD, *PCOORD;
  • 给坐标赋值:
 COORD pos = { 10, 15 };
  • 这里的COORD是一个结构体类型,其参数有X,Y坐标,这是windows设计好的函数。

setconsolecursorposition

  • 设置指定控制台屏幕缓冲区中的光标位置,我们将想要设置的坐标信息放在COORD类型的pos中,调⽤SetConsoleCursorPosition函数将光标位置设置到指定的位置。
BOOL WINAPI SetConsoleCursorPosition(
 HANDLE hConsoleOutput,
 COORD pos
);
  • 参数
    • 第一个参数依旧是一个句柄
    • 第二个参数是COORD这个结构体的变量,即我们要设置的坐标
  • 实例
COORD pos = { 10, 5};
 HANDLE hOutput = NULL;
 //获取标准输出的句柄(⽤来标识不同设备的数值)
 hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
 //设置标准输出上光标的位置为pos
 SetConsoleCursorPosition(hOutput, pos);

在这里插入图片描述

  • 通过测试我们可以看到第二次打印的haha确实打印在我们设置的坐标上,而且从这里可以看到控制台的坐标的长宽并不是等大的。

坐标设置代码SetPos

  • 在贪吃蛇实现过程中,我们会多次定位坐标,所以我们将上面的代码封装成一个函数SetPos
//设置光标的坐标
void SetPos(short x, short y)
{
 COORD pos = { x, y };
 HANDLE hOutput = NULL;
 //获取标准输出的句柄(⽤来标识不同设备的数值)
 hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
 //设置标准输出上光标的位置为pos
 SetConsoleCursorPosition(hOutput, pos);
}

getAsyncKeyState

  • 我们再看最后一个贪吃蛇中最后一个相关的API函数
  • 获取按键情况,GetAsyncKeyState的函数原型如下:
SHORT GetAsyncKeyState(
 int vKey
);
  • 将键盘上每个键的虚拟键值传递给函数,函数通过返回值来分辨按键的状态。
    GetAsyncKeyState 的返回值是short类型,在上⼀次调⽤ GetAsyncKeyState 函数后,如果
    返回的16位的short数据中,最⾼位是1,说明按键的状态是按下,如果最⾼是0,说明按键的状态是抬起;如果最低位被置为1则说明,该按键被按过,否则为0。
    如果我们要判断⼀个键是否被按过,可以检测GetAsyncKeyState返回值的最低值是否为1.
#define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )
  • 我们定义一个宏来检测对应按键是否被按过,通过让GetAsyncKeyState(vk)的返回值按位与上一个十六进制的1来判断是否按过
    虚拟键码 (Winuser.h) - Win32 apps
  • 这就是我们用键盘控制蛇的方向的函数,键盘对应的虚拟值都在上面的虚拟键码中,我们可以按照自己的习惯来定义控制蛇移动方向的按键

setlocale函数

  • 最后我们再介绍一个C语言的函数setlocale,其头文件为locale.h

  • 由于我们打印的墙边,蛇身,蛇头,食物的符号是宽字符(长为1,宽为2),在C语言标准模式下是不支持的,所以我们要改为本地模式才能使图标正确打印

  • 下图可以看出平常的单字符是长宽都为1的,但宽字符长为1,宽为2,在后面食物创建时也要留意这个问题

  • 在这里插入图片描述

  • setlocale 函数⽤于修改当前地区,可以针对⼀个类项修改,也可以针对所有类项。setlocale 的第⼀个参数可以是前⾯说明的类项中的⼀个,那么每次只会影响⼀个类项,如果第⼀个参数是LC_ALL,就会影响所有的类项。C标准给第⼆个参数仅定义了2种可能取值:“C”(正常模式)" "(本地模式)。在任意程序执⾏开始,都会隐藏式执⾏调⽤:

  • 当程序运⾏起来后想改变地区,就只能显⽰调⽤setlocale函数。⽤" "作为第2个参数,调⽤setlocale函数就可以切换到本地模式,这种模式下程序会适应本地环境。
    ⽐如:切换到我们的本地模式后就⽀持 宽字符(汉字)的输出等。

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

参数

  • 第一个参数是要修改的类项,我们直接全部本地化就行,使用LC_ALL详细类项点击查看
  • 第二个参数只有“C”(正常模式)和" "(本地模式),""是不含空格的
  • 实例
 setlocale(LC_ALL, " ");//切换到本地环境

总结

  • 关于贪吃蛇里相关的win32API函数就介绍完了,我们只需要了解如何使用就可以,现成的代码也已奉上,想要详细了解这些函数也可以打开对应链接查看,接下来就是贪吃蛇具体实现的讲解
  • 12
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值