目录
前言
1976年,Gremlin平台推出了一款经典街机游戏Blockade。游戏中,两名玩家分别控制一个角色在屏幕上移动,所经之处砌起围栏。角色只能向左、右方向90度转弯,游戏目标保证让对方先撞上屏幕或围栏。 听起来有点复杂,其实就是下面这个样子:
基本上就是两条每走一步都会长大的贪吃蛇比谁后完蛋,玩家要做的就是避免撞上障碍物和越来越长的身体。更多照片、视频可以看 GamesDBase 的介绍。
Blockade 很受欢迎,类似的游戏先后出现在 Atari 2600、TRS-80、苹果 2 等早期游戏机、计算机上。但真正让这种游戏形式红遍全球的还是21年后随诺基亚手机走向世界的贪吃蛇游戏——Snake。
1. 游戏背景
贪吃蛇是久负盛名的游戏,它也和俄罗斯方块,扫雷等游戏位列经典游戏的行列。在编程语言的教学中,我们以贪吃蛇为例,从设计到代码实现来提升学生的编程能力和逻辑能力。
2. 游戏效果演示
贪吃蛇
3. 目标
使用C语言在Windows环境的控制台中模拟实现经典小游戏贪吃蛇实现基本的功能:
- 贪吃蛇地图绘制
- 蛇吃食物的功能 (上、下、左、右方向键控制蛇的动作)
- 蛇撞墙死亡
- 蛇撞自身死亡
- 计算得分
- 蛇身加速、减速
- 暂停游戏
- 退出游戏
4. 项目定位
- 趣味性强
- 对C语言语法做一个基本巩固
- 启发游戏开发的兴趣
- 项目适合C语言学完,有一定的代码能力,初步接触数据结构中的链表的学者
5. 技术要点
C语言函数、枚举、结构体、动态内存管理、预处理指令、链表、Win32 API等。
6. Win 32 API 介绍
6.1 Win32 API
本次实现贪吃蛇会使用到的一些Win32 API知识,需要学习
Windows 这个多作业系统除了协调应用程序的执行、分配内存、管理资源之外, 它同时也是一个很大的服务中心,调用这个服务中心的各种服务(每一种服务就是一个函数),可以帮应用程序达到开启视窗、描绘图形、使用周边设备等目的。由于这些函数服务的对象是应用程序(Application), 所以便称之为 Application Programming Interface,简称 API 函数。WIN32 API也就是Microsoft Windows 32位平台的应用程序编程接口。
6.2 控制台程序(Console)
新版WIN 11操作系统提供的终端如上图,此控制台有些功能无法完成,此项目也无法实现,需要修改
选择Windows控制台主机并保存
修改成功!
也可以修改回去
右击鼠标选择属性
平常运行起来的黑框程序其实就是控制台程序,可以使用cmd命令来设置控制台窗口的长宽,设置控制台窗口的大小,如:30行,100列
1 mode con cols=100 lines=30
也可以通过命令设置控制台窗口的名字:
1 title 贪吃蛇
这些能在控制台窗口执行的命令,也可以调用C语言函数system来执行。例如:
#include<stdio.h>
#include<stdlib.h>
int main()
{
//设置控制台窗口的长度:设置控制台窗口的大小,30行,100列
system("mode con cols=100 lines=30");
//设置cmd窗口名称
system("title 贪吃蛇");
//getchar();
system("pause");//pause暂停
return 0;
}
运行结果
使用getchar函数观察效果或system函数都可以
6.3 控制台屏幕上的坐标COORD
COORD 是Windows API中定义的一个结构体,表示一个字符在控制台屏幕缓冲区上的坐标,坐标系(0,0)的原点位于缓冲区的顶部左侧单元格
1 typedef struct _COORD {
2 SHORT X;
3 SHORT Y;
4 } COORD,* PCOORD;
给坐标赋值:(使用时包含头文件windows.h)
1 COORD pos = { 10, 15 };
6.4 GetStdHandle
参考:GetStdHandle 函数 - Windows Console | Microsoft Learn
GetStdHandle是一个Windows API函数。它用于从一个特定的标准设备(标准输入、标准输出或标准错误)中取得一个句柄(用来标识不同设备的数值),使用这个句柄可以操作设备。
1 HANDLE GetStdHandle(DWORD nStdHandle);
实例:
1 HANDLE hOutput = NULL;
2
3 //获取标准输出的句柄(用来标识不同设备的数值)
4 hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
6.5 GetConsoleCursorInfo
参考:GetConsoleCursorInfo 函数 - Windows Console | Microsoft Learn
检索有关指定控制台屏幕缓冲区的光标大小和可见性的信息
1 1 BOOL WINAPI GetConsoleCursorInfo (
2 HANDLE hConsoleOutput,
3 PCONSOLE_CURSOR_INFO lpConsoleCursorInfo);
4 );
实例:
1 HANDLE hOutput = NULL;
2 //获取标准输出的句柄(用来标识不同设备的数值)
3 hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
4
5 CONSOLE_CURSOR_INFO CursorInfo;
6 GetConsoleCursorInfo(hOutput, & CursorInfo);//获取控制台光标信息
6.5.1 CONSOLE_CURSOR_INFO
这个结构体,包含有关控制台光标的信息
1 typedef struct _CONSOLE_CURSOR_INFO {
2 DWORD dwSize; BOOL bVisible;
3 } CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;
- dwSize,由光标填充的字符单元格的百分比。 此值介于1到100之间。 光标外观会变化,范围从完全填充单元格到单元底部的水平线条。
- bVisible,游标的可见性。 如果光标可见,则此成员为 TRUE。
1 CursorInfo.bVisible = false; //隐藏控制台光标
6.6 SetConsoleCursorInfo
参考:SetConsoleCursorInfo 函数 - Windows Console | Microsoft Learn
设置指定控制台屏幕缓冲区的光标的大小和可见性。
1 BOOL WINAPI SetConsoleCursorInfo(
2 HANDLE hConsoleOutput,
3 const CONSOLE_CURSOR_INFO * lpConsoleCursorInfo
4 );
实例:
1 HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
2
3 //影藏光标操作
4 CONSOLE_CURSOR_INFO CursorInfo;
5 GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
6 CursorInfo.bVisible = false; //隐藏控制台光标
7 SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态
6.7 SetConsoleCursorPosition
设置指定控制台屏幕缓冲区中的光标位置,我们将想要设置的坐标信息放在COORD类型的pos中,调用SetConsoleCursorPosition函数将光标位置设置到指定的位置。
1 BOOL WINAPI SetConsoleCursorPosition(
2 HANDLE hConsoleOutput,
3 COORD pos
4 );
实例:
1 COORD pos = { 10, 5 };
2 HANDLE hOutput = NULL;
3 //获取标准输出的句柄(用来标识不同设备的数值)
4 hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
5 //设置标准输出上光标的位置为pos
6 SetConsoleCursorPosition(hOutput, pos);
SetPos:封装一个设置光标位置的函数
1 //设置光标的坐标
2 void SetPos(short x, short y)
3 { COORD pos = { x, y };
3 HANDLE hOutput = NULL;
4 //获取标准输出的句柄(用来标识不同设备的数值)
5 hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
6 //设置标准输出上光标的位置为pos
7 SetConsoleCursorPosition(hOutput, pos);
8 }
6.8 GetAsyncKeyState
参考:GetAsyncKeyState function (winuser.h) - Win32 apps | Microsoft Learn
获取按键情况,GetAsyncKeyState的函数原型如下:
1 SHORT GetAsyncKey State(
2