引言:本篇博客所讲解的内容是为了帮助我们完成一个游戏项目——贪吃蛇。我们将会学到如何使用C语言实现对控制台光标位置的改变,光标大小的更改,对光标的隐藏以及对键盘按键情况的获取。
更多有关C语言的知识详解可前往个人主页:计信猫
一,WIN32 API的含义
Windows 这个多作业系统除了协调应用程序的执行、分配内存、管理资源之外, 它同时也是⼀个很大的服务中心,调用这个服务中心的各种服务(每⼀种服务就是⼀个函数),可以帮应用程序达到开启 视窗、描绘图形、使用周边设备等目的,由于这些函数服务的对象是应用程序(Application), 所以便 称之为 Application Programming Interface,简称 API 函数。WIN32 API也就是Microsoft Windows 32位平台的应用程序编程接口。
二,控制台程序的长宽以及标题的更改
1,控制台程序
我们知道,每当我们开始运行一个程序,屏幕上都会出现一个黑框,如下图所示:
而这个黑框程序,其实就叫做我们的控制台程序。
2,控制台程序长宽的更改
对于控制台的大小,其实我们可以使用一个系统函数来更改它的大小。假如我们想要将控制台大小改为100列,30行,那么如下代码便可以达到我们想要的效果。
#include<stdio.h>
#include<stdlib.h>//使用system函数要包含对应头文件
int main()
{
system("mode con cols=100 lines=30");//con代表着console,即控制台
printf("控制台程序\n");
return 0;
}
那么代码一走,控制台的长宽瞬间就变为了我们想要的样子。如下:
3,控制台标题的更改
在贪吃蛇项目中,为了达到游戏界面的完美,我们也需要将控制台的标题进行更改,就是图示位置的标题需要更改为“贪吃蛇”。
那么我们便可以同样使用system函数,对控制台的标题进行更改:
#include<stdio.h>
#include<stdlib.h>//使用system函数要包含对应头文件
int main()
{
system("title 贪吃蛇");//将控制台改名为“贪吃蛇”
system("pause");//暂停程序,观察效果
printf("控制台程序\n");
return 0;
}
代码一走,更改成功!
三,控制台屏幕的坐标COORD
COORD 是Windows API中定义的⼀个结构体,表示⼀个字符在控制台屏幕幕缓冲区上的坐标,坐标系 (0,0) 的原点位于缓冲区的顶部左侧单元格。
而COORD的结构体定义如下所示:
typedef struct _COORD
{
short x;//横坐标
short y;//纵坐标
}COORD,*PCOORD;
于是,我们便可以给坐标赋值:
COORD pos={ 1 , 2 };
四,GetStdHandle函数
GetStdHandle是⼀个Windows API函数。它⽤于从⼀个特定的标准设备(标准输入、标准输出或标准错误)中取得⼀个句柄(用来标识不同设备的数值),使用这个句柄可以操作设备。
HANDLE GetStdHand(DWORD nStdHandle);
如果感觉概念晦涩难懂,那你不是一个人。但是我对于这个函数的作用有一个独到的见解:我认为可以将这个函数类比于文件操作函数中的fopen()函数,它们的作用都相当于对于接下来的操作的一种开端。
就好比当我想要对某个文件进行操作的时候,我就需要先使用fopen()函数先对某个文件进行“读”或者“写”的打开操作,之后再使用其他相关的文件操作函数对文件进行操作;那么就类比该函数,当我想要对某个标准设备(屏幕,光标)进行操作时,我们也首先需要使用该函数进行获取该标准设备的信息,在进行其他的操作。
实例:
//获取标准输出句柄
HANDLE houtput=GetStdHandle(STD_OUTPUT_HANDLE);
五,CONSOLE_CURSOR_INFO结构体
该结构体,用于包含有关主机光标的信息,定义如下:
typedef struct _CONSOLE_CURSOR_INFO
{
DWORD dwSize;//由光标填充的字符单元格的百分⽐。 此值介于1到100之间。
BOOL bVisible;//游标可见性。若可见,则为true,否则为false。
}CONSOLE_CURSOR_INFO,*PCONSOLE_CURSOR_INFO;
dwSize:该成员的含义为光标占一个标准字符大小的百分比。就拿我们标准输出光标来举例吧。
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
int main()
{
HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);//获取标准输出句柄
CONSOLE_CURSOR_INFO cursor_info = { 0 };//初始化结构体成员
GetConsoleCursorInfo(houtput, &cursor_info);//获取光标信息
printf("%d\n", cursor_info.dwSize);//打印出具体占比数值
system("pause");
return 0;
}
代码走起来,我们得到了输出值:25。这也就同时说明了标准输出光标的大小占一个正常字符单元格的25%。
bVisible:该成员表示着光标的可见性,它的返回值为布尔类型,意味着它只有true和false两种值,所以若果我们想隐藏光标,那么我们可以如下设置:
CursorInfo.bVisible = false; //隐藏控制台光标
六,GetConsoleCursorInfo函数
该函数用于检索有关指定控制台屏幕缓冲区的光标大小和可见性的信息。定义如下:
BOOL WINAPI GetConsoleCursorInfo(
HANDLE hConsoleOutput,
PCONSOLE_CURSOR_INFO lpConsoleCursorInfo
);
其中第二个参数代表着指向CONSOLE_CURSOR_INFO结构体的指针。
实例:
HANDLE hOutput = NULL;
//获取标准输出的句柄(⽤来标识不同设备的数值)
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
所以该函数便如此传参。
七,SetConsoleCursorInfo函数
该函数则专门用于设置光标的大小和可见性。函数的定义如下:
BOOL WINAPI SetConsoleCursorInfo(
HANDLE hConsoleOutput,
const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo
);
当使用了GetConsoleCursorInfo()函数检索有关指定控制台屏幕缓冲区的光标大小和可见性的信息后,我们便可以通过一些代码对光标的大小或者可见性进行更改,最后在使用该函数设置这些更改,那么对于光标的修改就成功结束了。
实例:隐藏光标
#include<stdlib.h>
#include<Windows.h>
#include<stdbool.h>
int main()
{
HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);//获取标准输出句柄
CONSOLE_CURSOR_INFO cursor_info = { 0 };//初始化结构体成员
GetConsoleCursorInfo(houtput, &cursor_info);//获取光标信息
cursor_info.bVisible = false;//光标不可见
SetConsoleCursorInfo(houtput, &cursor_info);//设置对光标的更改
return 0;
}
代码一走,结果如下,光标成功被我们隐藏。
八,SetConsoleCursorPosition
该函数用于设置指定控制台屏幕缓冲区中的光标位置。我们将想要设置的坐标信息放在COORD类型的pos中,然后使用SetConsoleCursorPosition()函数将光标位置设置到指定的位置。函数的定义如下:
BOOL WINAPI SetConsoleCursorPosition(
HANDLE hConsoleOutput,
COORD pos
);
实例:改变光标位置
我们使用如下代码,先设置好光标想要出现的位置,再使用该函数设置光标的位置:
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
#include<stdbool.h>
int main()
{
HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);//获取标准输出句柄
COORD pos = { 10,15 };//定义一个光标的坐标
SetConsoleCursorPosition(houtput, pos);//设置对光标的更改
printf("光标到这里来了\n");
return 0;
}
结果如下:
九,GetAsyncKeyState函数
该函数的定义如下:
SHORT GetAsyncKeyState(
int vKey
);
该函数用于获取按键情况,返回值为short类型,在上⼀次调用GetAsyncKeyState()函数后,如果返回的16位的short数据中,最高位是1,说明按键的状态是按下,如果最高是0,说明按键的状态是抬起;如果最低位被置为1则说明,该按键被按过,否则为0。
所以我们便可以如下定义宏来判断某按键是否被按下:
#define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )
而每当我们按下一个按键,都会返回一个值给该函数进行判断,返回的值就被我们称作虚拟键码。