1.贪吃蛇游戏
那么在实现贪吃蛇游戏之前,我们先了解一下贪吃蛇的玩法:
相信很多人都玩过贪吃蛇游戏,没有玩过的举手一下。
游戏规则:
1)蛇不能穿墙
2)蛇不能咬自己
3)使用键盘上的↑,↓,←,→来控制蛇的移动
4)F1为蛇加速
5)F2为蛇减速
6)ESC退出游戏
7)space 空格键,暂停游戏
接下来,我们先需要绘制一个地图
2.实现要求
使用C语言在windows环境的控制台中模拟实现贪吃蛇游戏
3.会涉及到那些技术要点
C语言函数,枚举,结构体,动态内存管理,预处理指令,链表,win32 API
4.win32 API 控制台的知识讲解
4.1 windows是多作业系统用于协调应用程序的执行、分配内存、管理资源之外,他同时也是一个很大的服务中心。
调用这个服务中心的各种服务(每一种服务就是一个可执行的函数),可以帮助应用程序达到开启视窗、描绘图形、使用周边设备。
由于这些函数服务的对象是应用程序(Application),所以称之为Application programming interface 简称为API 函数,也就是WIN32 API ,32位平台应用程序编程接口。
总结:每一种操作系统在完成正常的操作系统该有的功能,例如文件管理,内存管理等。
还提供了一些API接口,而这些接口就是函数,将这些函数提供给程序员调用,从而实现自己想要的功能,而这个接口也叫做API。
以windows环境为例:这些接口统称为win32 API
5.cmd的程序-终端,也叫控制台
可以使用cmd命令来设置控制台窗口的长宽,设置控制台窗口大小,30行,100列
控制台:console
windows键+R 可以快速进入CMD
然后设置控制台的大小:
mode con cols=100 lines=100
然后回车enter
6.接下来我们创建一个空项目,来进行贪吃蛇游戏的编写
写一个test.c文件
接下来开始代码编写:
7.如何在代码上面调整控制窗口的大小?
#include <stdio.h>
#include <stdlib.h> //包含系统函数的头文件
int main()
{
system("mode con cols=50 lines=50"); //使用系统函数设置控制台的大小,行50,列50
printf("hehe\n");
return 0;
}
编译执行,很显然控制台窗口已被设置成了cols=50,lines=50,只使用于window 平台的操作dos
第二种调整方法:点击窗口上面右键,然后点击属性
从布局这边设置长宽,也就是设置cols,lines
如果我们想要了解更多关于mode指令
我们可以去微软网站,下面链接直接抵达:
而我们刚才运用到的mode的显示功能就在这里:
修改title ,可以修改控制台的名字:
那么现在就可以看到贪吃蛇游戏在控制台显示。
那么如果在程序代码里面怎么设置:
#include <stdio.h>
#include <stdlib.h> //包含系统函数的头文件
int main()
{
system("mode con cols=50 lines=50"); //使用系统函数设置控制台的大小,行50,列50
system("title 贪吃蛇"); //改变控制台名字
printf("hehe\n");
return 0;
}
8.控制台屏幕上的坐标COORD
COORD是Windows API中定义的一个结构体,表示一个字符在控制台屏幕缓冲区上的坐标,坐标系(0,0)的原点缓冲区的顶部左侧单元格。
观察一个数据:在控制台打印的时候,hehe数据都是默认从左上角开始打印:
我们要知道,这个窗口是有坐标系的:
如果(0,0)坐标要移动那么则是往X++,Y++的方向移动响应的坐标
COORD 类型的声明:
#include <windows.h> //需要包含这样的一个头文件
typedef struct _COORD{
SHORT X;
SHORT Y;
}COORD,*PCOORD;
COORD POS = {10,12};
9.GetStdHandle
也是windows API函数,它用于从一个特定的标准设备(标准输入、标准输出或者标准错误)中取得一个句柄(用来标识不同设备的数值),使用这个句柄可以操作设备。
HANDLE WINAPI GetStdHandle(
_In_ DWORD nStdHandle
);
HANDLE 是一个指针
因此可以先定义一个空指针来接收:
HANDLE handle = NULL; //定义一个空指针来接收输出
handle = GetstdHandle(STD_OUTPUT_HANDLE);
或者也可也这么写:
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); //定义一个指针handle句柄,用来获取输出设备
10.GetConsoleCursorInfo 检索有关指定控制台屏幕缓冲区的光标大小和可见性的信息
hConsoleOutput是控制台屏幕缓冲区的句柄,该句柄具有GENERIC_READ的访问权限。
lpConsoleCursorInfo是指向GetConsoleCursorInfo 是一个结构的指针,并用于接收有关主机光标的信息。
BOOL
WINAPI
GetConsoleCursorInfo(
_In_ HANDLE hConsoleOutput,
_Out_ PCONSOLE_CURSOR_INFO lpConsoleCursorInfo
);
10.1 CONSOLE_CURSOR_INFO 这是一个结构体变量,该结构变量存放了有关控制台光标的信息
dwSize 由光标填充的字符单元格的百分比,此值介于1到100之间,光标外观会发生变化,范围从完全填充单元格到单元底部的水平线条。
bVisible 光标的可见性,如果光标可见,则该成员位TRUE,否则位false
//这个结构体,存放了有关控制台光标的信息
typedef struct _CONSOLE_CURSOR_INFO {
DWORD dwSize;
BOOL bVisible;
} CONSOLE_CURSOR_INFO, * PCONSOLE_CURSOR_INFO;
cursor_info.bVisible = false; //当光标不可见是设置为false;
10.2 当我们设置cursor_info.dwSize=100; //也就是光标的刻度是满的,最大就是100
#include <stdio.h>
#include <stdlib.h> //包含系统函数的头文件
#include <windows.h>
int main()
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); //定义一个指针handle句柄,用来获取输出设备
CONSOLE_CURSOR_INFO cursor_info;//cursor_info 用来存放控制台光标信息
GetConsoleCursorInfo(handle, &cursor_info); //把句柄传进来,获取的信息放哪里,控制台光标信息会放到cursor_info里面
cursor_info.dwSize = 100; //百分之百 范围只能是从1~100之间
//cursor_info.bVisible = true; //光标可见 默认就是为真1
//cursor_info.bVisible = false; //光标隐藏
SetConsoleCursorInfo(handle, &cursor_info);
return 0;
}
10.3 如果我们要隐藏光标,那么设置cursor_info.bVisible = false
此时,我们需要包含头文件 #include <stdbool.h>这个头文件之后就可以使用true和false了
#include <stdio.h>
#include <stdlib.h> //包含系统函数的头文件
#include <windows.h>
#include <stdbool.h>
int main()
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); //定义一个指针handle句柄,用来获取输出设备
CONSOLE_CURSOR_INFO cursor_info;//cursor_info 用来存放控制台光标信息
GetConsoleCursorInfo(handle, &cursor_info); //把句柄传进来,获取的信息放哪里,控制台光标信息会放到cursor_info里面
cursor_info.dwSize = 100; //百分之百 范围只能是从1~100之间
//cursor_info.bVisible = true; //光标可见 默认就是为真1
cursor_info.bVisible = false; //光标隐藏
SetConsoleCursorInfo(handle, &cursor_info);
return 0;
}
那么如果我们有没有办法知道光标是不是真的隐藏了呢?
不妨可以使用getchar()来输入字符,并获取字符后观察光标是否还在?
10.4 SetConsoleCursorPostion 设置指定光标的位置
设置指定控制台屏幕缓冲器中的光标位置,我们将想要设置的坐标信息放在COORD类型的pos中,调用SetConsoleCursorPosition函数将光标位置设置到指定的位置
BOOL
WINAPI
SetConsoleCursorPosition(
_In_ HANDLE hConsoleOutput,
_In_ COORD dwCursorPosition
);
当我们设置
COORD POS = { 10,20 };
SetConsoleCursorPosition(handle, POS);
如果我输出的值要在别的坐标打印呢?
只需要在ch=getchar();的后面加上指定的位置即可:
COORD POS1 = { 20,10 }; //设置字符输出光标的坐标
SetConsoleCursorPosition(handle, POS1);
int main()
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); //定义一个指针handle句柄,用来获取输出设备
//CONSOLE_CURSOR_INFO cursor_info;//cursor_info 用来存放控制台光标信息
//GetConsoleCursorInfo(handle, &cursor_info); //把句柄传进来,获取的信息放哪里,控制台光标信息会放到cursor_info里面
//cursor_info.dwSize = 100; //百分之百 范围只能是从1~100之间
//cursor_info.bVisible = true; //光标可见 默认就是为真1
//cursor_info.bVisible = false; //光标隐藏
COORD POS = { 10,20 };
SetConsoleCursorPosition(handle, POS);
//SetConsoleCursorInfo(handle, &cursor_info);
int ch = getchar();
COORD POS1 = { 20,10 };
SetConsoleCursorPosition(handle, POS1);
putchar(ch);
return 0;
}
通过打印可以看到,我们输入的字符r在坐标(20,10)的位置打印出来了。
但是这里还有个问题,如果每次想要在不同的位置打印字符,那每一次都要对这个COORD pos={10,20}的坐标进行设置,设置到指定的位置上,这样好像很麻烦。
有没有更好的办法?
10.5 SetPos(int x,int y) 编写一个函数专门用于存放光标的坐标.
作用:设置某个控制台的坐标
编写好函数之后,我们在SetPos(5,5)这个坐标打印xixi!
那么我们后续想要设置其他控制台的光标,就可以使用这个函数了。
void SetPos(int x, int y)
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos = { x,y };
SetConsoleCursorPosition(handle, pos);
}
int main()
{
SetPos(5, 5);
printf("xixi!\n");
return 0;
}