引言
相信大家都玩过贪吃蛇这个游戏!
玩家控制一个不断移动的蛇形角色,在一个封闭空间内移动。随着时间推进,这个蛇形角色会逐渐增长,通常是通过吞食屏幕上出现的物品(如点或者其他标志)来实现。每当贪吃蛇吃掉一个物品时,它就会变得更长一些。
目标是尽可能地让蛇增长而不撞击墙壁、障碍物或自己的身体部分。如果发生了这样的碰撞,则游戏结束。难度主要来源于两方面:一方面是由于贪吃蛇长度不断增加导致操作空间越来越小;另一方面则是速度可能会逐步提升,对玩家反应能力和策略规划提出了更高要求。
那么,我们能否使用C语言在Windows环境的控制台中模拟实现贪吃蛇小游戏呢~
答案是可以!
由于本次实现贪吃蛇会使用一些Win32 API的知识,所以我们先来学习一下Win32 API!
Win32 API
什么是Win32 API
Win32 API(Application Programming Interface)是微软Windows操作系统提供的一套核心接口,用于开发32位和64位的应用程序。这些API为程序员提供了访问Windows系统底层服务的方法,包括窗口管理、文件操作、设备输入输出、内存管理和进程线程控制等。
Win32 API可以分为几个不同的类别:
-
用户界面(User Interface)API:负责创建和管理窗口、对话框以及其他图形用户界面元素。例如CreateWindow()函数就是用来创建一个窗口。
-
图形设备接口(Graphics Device Interface, GDI)API:GDI APIs允许应用程序在屏幕上绘制图形,并处理字体和打印机输出。例如LineTo()函数可以画一条直线。
-
系统服务API:提供对系统级功能如注册表操作、事件日志记录等的访问。例如RegOpenKeyEx()函数可以打开注册表键值。
-
文件与I/O API:允许读写文件系统中的数据,以及与外部设备进行通信。例如ReadFile() 和 WriteFile() 函数可用于文件读写。
-
进程与线程管理API:控制进程和线程生命周期,实现多任务并发执行能力。CreateProcess() 可以启动新进程,而CreateThread() 会创建一个新线程。
-
网络服务API:支持网络通信功能,如TCP/IP连接、数据发送接收等。WSAStartup(), socket(), connect(), send(), recv() 是常见网络编程相关函数。
-
安全性API :涉及到身份验证、权限检查等安全相关功能。
-
多媒体API: 提供音频视频播放录制等多媒体处理能力。
1.控制台程序
我们可以使用cmd命令来设置控制台窗口的长度:比如设置控制台窗口大小为30行 100列
mode con cols=100 lines=30
也可以通过命令来设置控制台窗口的名字
title 贪吃蛇
这些能在控制台窗口执行的命令,也可以调用C语言函数system来执行
objectivec
#include <stdio.h>
#include <stdlib.h>
int main()
{
system("mode con cols=100 lines=30");
//设置控制台窗口大小 30行 100列
system("title 贪吃蛇");
//设置cmd窗口名称
return 0;
}
2.控制台屏幕上的坐标COORD
COORD是Windows API中定义的一个结构体,表示一个字符在控制台屏幕上的坐标
objectivec
typedef struct _COORD{
SHORT x;
SHORT Y;
}COORD,*PCOORD;
给坐标赋值(使用时要包含头文件windows.h)
COORD pos = {10,15};
3.GetStdHandle
句柄:这是一个抽象的概念,用于表示对资源或对象的引用,它通常是一个整数值或者指针,通过这个值可以访问到底层系统资源,如文件,窗口和数据库连接等。
GetStdHandle:是一个Windows API函数。它用于从一个特定的标准设备(标准输出,标准输入或标准错误)中获得一个句柄,使用这个句柄可以操作设备。
HANDLE GetStdHandle(DWORD nstdHandle);
下列代码用于获取标准输出的句柄
objectivec
HANDLE houtput = NULL;
houtput = GetStdHandle(STD_OUTPUT_HANDLE);
4.GetConsoleCursorInfo
该函数检索有关控制台屏幕缓冲区的光标大小和可见性信息
BOOL WINAPI GetConsoleCursorInfo(
HANDLE hConsoleOutput,
PCONSOLE_CURSOR_INFO lpConsoleCursorInfo//是指向CONSOLE_CURSOR_INFO结构的指针,该结构接收有关主机游标的信息
);
objectivec
HANDLE houtput = NULL;
houtput = GetStdHandle(STD_OUTPUT_HANDLE);//获取标准输出的句柄
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(houtput,&CursorInfo);//获取控制台光标信息
5.CONSOLE_CURSOR_INFO
该结构体包含了有关控制台光标的信息,光标大小和可见性数据
objectivec
typedef struct _CONSOLE_CURSOR_INFO{
DWORN dwSize;
BOOL bVisible;
}CONSOLE_CURSOR_INFO,*PCONSOLE_CURSOR_INFO;
- dwSize 由光标填充的字符单元格的百分比。光标的外观会变化,从完全填充单元格到单元底部的水平线条。此值介于1-100之间。
- bVisible 游标的可见性。如果光标可见,此值为TRUE。
objectivec
CursorInfo.bVisible =false;//隐藏控制台光标
6.SetConsoleCursorInfo
设置制定控制台屏幕缓冲区的光标的大小和可见性。
objectivec
BOOL WINAPI SetConsoleCursorInfo{
HANDLE hconsoleoutput,
const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo
};
objectivec
HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(houtput,&CursorInfo);//获取控制台光标信息
CursorInfo.bVisible = false;//隐藏控制台光标
SetConsoleCursorInfo(houtput,&CursorInfo);//设置控制台光标状态
7.SetConsoleCursorPosition
设置制定控制台屏幕缓冲区中的光标位置,我们将想要设置的坐标信息放在COORD类型的pos中,调用该函数将光标位置设定到指定位置
objectivec
BOOL WINAPI SetConsoleCursorPosition(
HANDLE hconsoleoutput,
COORD pos
);
objectivec
COORD pos = {10,5};
HANDLE houtput = NULL;
houtput = GetStdHandle(STD_OUTPUT_HANDLE);//获取标准输出的句柄
SetConsoleCursorPosition(houtput,pos);//设置标准输出上光标位置为pos
由此,我们可以封装一个设置光标位置的函数SetPos
objectivec
void SetPos(short x,short y)
{
COORD pos ={x,y};
HANDLE houtput = NULL;
houtput = GetStdHandle(STD_OUTPUT_HANDLE);//获取标准输出的句柄
SetConsoleCursorPosition(houtput,pos);//设置光标位置
}
8.GetAsyncKeyState
该函数用于获取按键情况,GetAsyncKeyState的函数原型如下
SHORT GetAsyncKeyState(
int vKey;
);
将按键上的每个键的虚拟键值传递给函数,函数通过返回值来分辨按键状态。
GetAsyncKeyState的返回值为short类型,在上一次调用该函数后,如果返回的16位short数据中,最高位是1,说明按键的状态是按下,如果最高位是0,说明按键的状态是抬起;如果最低位被设置成1说明该按键被按过,否则为0
所以要判断一个按键是否被按过,我们可以检测该函数返回值的最低位是否为1
objectivec
#define KEY_PRESS(VK) ((GetAsyncKeyState(VK)&0x1?1:0)
好啦!关于WIN32 API及相关函数的介绍就到这里啦,在下一篇博客中,我将详细实现贪吃蛇小游戏!防止迷路ovo请点赞收藏加关注哦~