赞
踩
目录
3.2.4 NextIsFood 判断走的下一个节点是否是食物
使用C语言在Windows环境的控制台中模拟实现经典小游戏贪吃蛇实现基本的功能:
• 贪吃蛇地图绘制
• 蛇吃食物的功能 (上、下、左、右方向键控制蛇的动作)
• 蛇撞墙死亡
• 蛇撞自身死亡
• 计算得分
• 蛇身加速、减速
• 暂停游戏
在Windows中win+R输入cmd即可唤起控制台程序,使用cmd命令可以设置控制台窗口长宽。
mode con cols=120 lines=40
title Snake
GetStdHandle是一个Windows API函数。它用于从一个特定的标准设备(标准输入、标准输出或标准错误)中取得一个句柄(用来标识不同设备的数值,使用这个句柄可以操作设备。
HANDLE GetStdHandle(DWORD nStdHandle);
就单对这个贪吃蛇的项目来说,我们需要在windows的控制台上执行的,也就是我们需要找到这个控制台,取得这个控制台的句柄,建立联系。
实例:
- HANDLE hOutput = NULL;
-
- //获取标准输出的句柄(⽤来标识不同设备的数值)
- hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
检索有关指定控制台屏幕缓冲区的光标大小和可见性的信息
- BOOL WINAPI GetConsoleCursorInfo(
- HANDLE hConsoleOutput, //句柄
- PCONSOLE_CURSOR_INFO lpConsoleCursorInfo //一个结构体接收有关控制台游标的信息
- );
实例
- HANDLE hOutput = NULL;
- //获取标准输出的句柄(用来标识不同设备的数值)
- hOutput = GetStdHandle(STD_OUTPUT_HANDLE); //获取控制台的句柄
-
- CONSOLE_CURSOR_INFO CursorInfo;
- GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
这个结构体,包含有关控制台游标的信息
- typedef struct _CONSOLE_CURSOR_INFO {
- DWORD dwSize;
- BOOL bVisible;
- } CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;
• dwSize,由光标填充的字符单元格的百分比。 此值介于1到100之间。 光标外观会变化,范围从完全填充单元格到单元底部的水平线条。
• bVisible,游标的可见性。 如果光标可见,则此成员为 TRUE。
例如我们要隐藏闪烁的光标:
CursorInfo.bVisible 1 = false; //隐藏控制台光标
设置指定控制台屏幕缓冲区的光标的大小和可见性
- 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);//设置控制台光标状态
- typedef struct _COORD {
- SHORT X;
- SHORT Y;
- } COORD, *PCOORD;
COORD pos={ 10 , 15 };
设置指定控制台屏幕缓冲区中的光标位置,我们将想要设置的坐标信息放在COORD类型的pos中,调用SetConsoleCursorPosition函数将光标位置设置到指定的位置。
- BOOL WINAPI SetConsoleCursorPosition(
- HANDLE hConsoleOutput,
- COORD pos
- );
实例:
- COORD pos = { 10, 5};
- HANDLE hOutput = NULL;
- //获取标准输出的句柄(用来标识不同设备的数值)
- hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
- //设置标准输出上光标的位置为pos
- SetConsoleCursorPosition(hOutput, pos);
SetPos:封装⼀个设置光标位置的函数
- //设置光标的坐标
- void SetPos(short x, short y)
- {
- COORD pos = { x, y };
- HANDLE hOutput = NULL;
- //获取标准输出的句柄(⽤来标识不同设备的数值)
- hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
- //设置标准输出上光标的位置为pos
- SetConsoleCursorPosition(hOutput, pos);
- }
2.8 GetAsyncKeyState
获取按键情况,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 )
在游戏运行的过程中,蛇每次吃一个食物,蛇的身体就会变长一节,如果我们使用链表存储蛇的信
息,那么蛇的每一节其实就是链表的每个节点。每个节点只要记录好蛇身节点在地图上的坐标就行,所以蛇节点结构如下:
- typedef struct SnakeNode
- {
- int x;
- int y;
- struct SnakeNode* next; //链接每一个节点组成的一条蛇
- }SnakeNode, * pSnakeNode;
要管理整条贪吃蛇,我们再封装一个Snake的结构来维护整条贪吃蛇:
- typedef struct Snake {
- pSnakeNode _psnake;//贪吃蛇的第一个节点,头结点的指针
- pSnakeNode _pFood; //指向食物节点的指针
- int _Score;//贪吃蛇累计的总分
- int _FootWeight;//一个食物的分数
- int _SleepTime;//每走一步休息的时间,时间越短,速度越快,时间越长。速度越慢
- enum DIRECTION _Dir;//描述蛇的方向
- enum GAME_STATUS _Status;//游戏的状态:正常、退出、撞墙、吃到自己
- }Snake, * pSnake;
以下是枚举蛇方向和存活状态:
- enum DIRECTION
- {
- UP = 1,
- DOWN,
- LEFT,
- RIGHT
- };
-
- //贪吃蛇的存活的状态
- enum GAME_STATUS {
- OK,//正常运行
- END_NORMAL,//按esc退出
- KILL_BY_WALL,//撞墙
- KILL_BY_SELF//自杀
- };
我们设计这个贪吃蛇分三个步骤,初始化贪吃蛇(包括地图的创建以及贪吃蛇本身的结构)、运行游戏的过程、结束游戏(释放资源),接下来就以这些步骤开始:
游戏的初始化
- //游戏初始化
- void GameStart(pSnake ps) {
- setlocale(LC_ALL, "");
- system("mode con cols=120 lines=40"); //设置了x=120,y=40控制台窗口
- system("title 贪吃蛇");
-
- //1_隐藏光标
- HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); //先获得控制台的句柄
- //一个控制台光标的信息的结构体 CONSOLE_CURSOR_INFO
- CONSOLE_CURSOR_INFO CursorInfo;
- //通过句柄获取控制台的光标信息,并储存在 CursorInfo 内
- GetConsoleCursorInfo(handle, &CursorInfo);
- //通过修改 CursorInfo 内的光标信息 bVisible 隐藏掉,不显示
- CursorInfo.bVisible = false; //需要头文件 <stdbool.h>
- //修改成功后需要执行修改
- SetConsoleCursorInfo(handle, &CursorInfo);
-
- //2_打印欢迎界面
- welComeToGame();
-
- //3_创建地图
- CreateMap();
-
- //4_初始化贪吃蛇
- InitSnake(ps);
-
- //5_创建食物
- CreatFood(ps);
- }
- void welComeToGame() {
- SetPos(51, 18); //定位控制台光标的位置
- printf("欢迎来到贪吃蛇游戏");
-
- SetPos(53, 36);
- //Windows 中暂停的指令,按任意键结束暂停
- system("pause");
-
- //清除之前屏幕上打印的信息
- system("cls");
-
- SetPos(51, 18);
- printf("游戏玩法规则如下:");
-
- SetPos(35, 20);
- printf("←↑→↓来操控贪吃蛇移动,Esc退出游戏,Space暂停游戏");
-
- SetPos(53, 22);
- printf("F3加速,F4减速");
-
- SetPos(53, 36);
- system("pause");
-
- system("cls");
- }
- void CreateMap() {
- //上
- SetPos(0, 0);
- for (int i = 0; i <= 78; i += 2) {
- wprintf(L"%lc", WALL);
- }
- //左
- for (int i = 1; i <= 34; i++) {
- SetPos(0, i);
- wprintf(L"%lc", WALL);
- }
- //右
- for (int i = 1; i <= 34; i++) {
- SetPos(78, i);
- wprintf(L"%lc", WALL);
- }
- //下
- SetPos(0, 34);
- for (int i = 0; i <= 78; i += 2) {
- wprintf(L"%lc", WALL);
- }
- }
- void InitSnake(pSnake ps) {
- pSnakeNode cur = NULL;
- for (int i = 0; i < 5; i++) {
- cur = (pSnakeNode)malloc(sizeof(SnakeNode));
- if (cur == NULL) {
- perror("InitSnake() error!");
- return;
- }
- cur->x = POS_X + i * 2;
- cur->y = POS_Y;
- cur->next = NULL;
-
- //头插法
- if (ps->_psnake == NULL) {
- ps->_psnake = cur;
- }
- else {
- cur->next = ps->_psnake;
- ps->_psnake = cur;
- }
- }
- // 遍历这个链表
- while (cur) {
- SetPos(cur->x, cur->y);
- wprintf(L"%lc", BODY);
- cur = cur->next;
- }
-
- ps->_Status = OK;
- ps->_Score = 50;
- ps->_pFood = NULL;
- ps->_SleepTime = 200;
- ps->_FootWeight = 10;
- ps->_Dir = RIGHT;
- }
- void CreatFood(pSnake ps) {
- //1、坐标应该是随机生成的,但是这个随机是由约束的
- //2、食物坐标必须在方框内
- //3、食物的x坐标必须是2的倍数
- int x = 0;
- int y = 0;
- again:
- do {
- x = rand() % 76 + 2;
- y = rand() % 33 + 1;
- } while (x % 2 != 0);
-
- //4、食物的坐标不能跟蛇身重叠,冲突 ,一一进行比较
- pSnakeNode cur = ps->_psnake;
- while (cur) {
- //比较
- if (cur->x == x && cur->y == y) {
- //出现重叠的就 goto 前面重新来过
- goto again;
- }
- cur = cur->next;
- }
- pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));
- if (pFood == NULL) {
- perror("CreateFood(); malloc error!");
- return;
- }
- pFood->x = x;
- pFood->y = y;
- ps->_pFood = pFood;
-
- SetPos(x, y);
- wprintf(L"%lc", FOOD);
- }
游戏运行期间,右侧打印帮助信息,提示玩家根据游戏状态检查游戏是否继续,如果是状态是OK,游戏继续,否则游戏结束。如果游戏继续,就是检测按键情况,确定蛇下一步的方向,或者是否加速减速,是否暂停或者退出游戏。确定了蛇的方向和速度,蛇就可以移动了。
- void GameRun(pSnake ps) {
- PrintHelpInfo(); //打印游戏规则介绍和分数
- do {
- SetPos(85, 10);
- printf("得分:%05d", ps->_Score);
- SetPos(85, 11);
- printf("食物分数:%2d", ps->_FootWeight);
-
- //检测按键情况
- //本来方向就是向上就不能往相反方向了
- if (KEY_PRESS(VK_UP) && ps->_Dir != DOWN) {
- ps->_Dir = UP;
- }
- else if (KEY_PRESS(VK_DOWN) && ps->_Dir != UP) {
- ps->_Dir = DOWN;
- }
- else if (KEY_PRESS(VK_LEFT) && ps->_Dir != RIGHT) {
- ps->_Dir = LEFT;
- }
- else if (KEY_PRESS(VK_RIGHT) && ps->_Dir != LEFT) {
- ps->_Dir = RIGHT;
- }
- else if (KEY_PRESS(VK_ESCAPE)) {
- ps->_Status = END_NORMAL;
- break;
- }
- else if (KEY_PRESS(VK_SPACE)) {
- //封装一个暂停函数
- Pause();
- }
- //加速
- else if (KEY_PRESS(VK_F3)) {
- if (ps->_SleepTime >= 100) {
- ps->_SleepTime -= 30;
- ps->_FootWeight += 2;
- }
- }
- //减速
- else if (KEY_PRESS(VK_F4)) {
- if (ps->_SleepTime <= 320) {
- ps->_SleepTime += 30;
- ps->_FootWeight -= 2;
- }
- }
- //设置完后要应用休眠的时间
- Sleep(ps->_SleepTime);
- //让蛇移动起来
- SnakeMove(ps);
-
- } while (ps->_Status == OK);
- }
- void PrintHelpInfo() {
-
- SetPos(85, 12);
- printf("1、不能撞墙,不能吃到自己");
-
- SetPos(85, 14);
- printf("2、←↑→↓来操控贪吃蛇移动");
-
- SetPos(85, 16);
- printf("3、F3加速,F4减速");
-
- SetPos(85, 18);
- printf("4、Esc退出游戏,Space暂停游戏");
-
- }
- void Pause() {
- //让系统一直休眠,直到再次按下空格键
- while (1) {
- Sleep(200);
- if (KEY_PRESS(VK_SPACE)) {
- break;
- }
- }
- }
先创建下一个节点,根据移动方向和蛇头的坐标,蛇移动到下一个位置的坐标。确定了下一个位置后,看下一个位置是否是食物(NextIsFood),是食物就做吃食物处理(EatFood),如果不是食物则做前进一步的处理(NoFood)。蛇身移动后,判断此次移动是否会造成撞墙(KillByWall)或者撞上自己蛇身(KillBySelf),从而影响游戏的状态。
- void SnakeMove(pSnake ps) {
- //为下一个移动的点创建一个节点
- pSnakeNode pNext = (pSnakeNode)malloc(sizeof(SnakeNode));
- if (pNext == NULL) {
- perror("SnakeMove() malloc() error!");
- return;
- }
-
- switch (ps->_Dir) {
- case UP:
- {
- pNext->x = ps->_psnake->x;
- pNext->y = ps->_psnake->y - 1;
- }
- break;
- case DOWN: {
- pNext->x = ps->_psnake->x;
- pNext->y = ps->_psnake->y + 1;
- }
- break;
- case LEFT: {
- pNext->x = ps->_psnake->x - 2;
- pNext->y = ps->_psnake->y;
- }
- break;
- case RIGHT: {
- pNext->x = ps->_psnake->x + 2;
- pNext->y = ps->_psnake->y;
- }
- break;
- }
-
- //判断是否是食物
- if (NextIsFood(ps, pNext)) {
- //吃掉食物
- EatFood(ps, pNext);
- }
- else {
- //不吃
- NoFood(ps, pNext);
- }
-
- 判断是否撞墙
- KillByWall(ps);
- 判断是否自杀
- KillBySelf(ps);
- }
- int NextIsFood(pSnake ps, pSnakeNode pNext) {
- if (ps->_pFood->x == pNext->x && ps->_pFood->y == pNext->y) {
- return 1;
- }
- return 0;
- }
- void EatFood(pSnake ps, pSnakeNode pNext) {
- pNext->next = ps->_psnake;
- ps->_psnake = pNext;
-
-
- pSnakeNode cur = ps->_psnake;
- while (cur) {
- SetPos(cur->x, cur->y);
- wprintf(L"%lc", BODY);
- cur = cur->next;
- }
-
- //给总分加上分数
- ps->_Score += ps->_FootWeight;
-
- free(ps->_pFood);
- //还得重新创建新的食物
- CreatFood(ps);
- }
- void NoFood(pSnake ps, pSnakeNode pNext) {
- //头插入节点
- pNext->next = ps->_psnake;
- ps->_psnake = pNext;
-
- //释放尾节点
- pSnakeNode cur = ps->_psnake;
- while (cur->next->next != NULL) {
- SetPos(cur->x, cur->y);
- wprintf(L"%lc", BODY);
- cur = cur->next;
- }
- SetPos(cur->next->x, cur->next->y);
- printf(" ");
- free(cur->next);
- cur->next = NULL;
- }
- void KillByWall(pSnake ps) {
- if (ps->_psnake->x == 0 || ps->_psnake->y == 35 || ps->_psnake->x == 80 || ps->_psnake->y == 0) {
- ps->_Status = KILL_BY_WALL;
- }
- }
- void KillBySelf(pSnake ps) {
- pSnakeNode cur = ps->_psnake->next;
- while (cur) {
- if (ps->_psnake->x == cur->x && ps->_psnake->y == cur->y) {
- ps->_Status = KILL_BY_SELF;
-
- }
- cur = cur->next;
- }
- }
- void GameEnd(pSnake ps) {
- SetPos(39, 16);
- switch (ps->_Status) {
- case END_NORMAL:
- printf("退出游戏成功!(っ °Д °;)っ下次还要再来一把");
- break;
- case KILL_BY_WALL:
- printf("撞墙啦!(╯°□°)╯︵ ┻━┻");
- break;
- case KILL_BY_SELF:
- printf("自杀啦!你怎么咬到自己了啊!( ´・・)ノ(._.`)");
- break;
- }
-
- SetPos(39, 18);
-
- pSnakeNode cur = ps->_psnake;
- while (cur) {
- pSnakeNode del = cur;
- cur = cur->next;
- free(del);
- }
- }
- #define _CRT_SECURE_NO_WARNINGS 1
- #pragma once
-
- #include<stdio.h>
- #include<stdlib.h>
- #include<locale.h>
- #include<stdbool.h>
- #include<windows.h>
- #include<time.h>
-
- //检测按键定义的宏
- #define KEY_PRESS(VK) (GetAsyncKeyState(VK)& 0x1 ? 1:0)
- #define WALL L'□'
- #define BODY L'●'
- #define FOOD L'★'
-
-
- #define POS_X 24
- #define POS_Y 5
-
- //方向
- enum DIRECTION
- {
- UP = 1,
- DOWN,
- LEFT,
- RIGHT
- };
-
- //贪吃蛇的存活的状态
- enum GAME_STATUS {
- OK,//正常运行
- END_NORMAL,//按esc退出
- KILL_BY_WALL,//撞墙
- KILL_BY_SELF//自杀
- };
-
-
- //贪吃蛇本身的节点
- typedef struct SnakeNode {
- int x;
- int y;
- struct SnakeNode* next;
- }SnakeNode, * pSnakeNode; //相当于 typedef struct SnakeNode* pSnakeNode;
-
- //描述这条贪吃蛇结构
- typedef struct Snake {
- pSnakeNode _psnake;//贪吃蛇的第一个节点,头结点的指针
- pSnakeNode _pFood; //指向食物节点的指针
- int _Score;//贪吃蛇累计的总分
- int _FootWeight;//一个食物的分数
- int _SleepTime;//每走一步休息的时间,时间越短,速度越快,时间越长。速度越慢
- enum DIRECTION _Dir;//描述蛇的方向
- enum GAME_STATUS _Status;//游戏的状态:正常、退出、撞墙、吃到自己
- }Snake, * pSnake;
-
- //定位控制台光标
- void SetPos(int x, int y);
-
-
- //游戏初始化
- void GameStart(pSnake ps);
-
- //2_打印欢迎界面
- void welComeToGame();
-
- //3_创建地图
- void CreateMap();
-
- //4_初始化贪吃蛇
- void InitSnake(pSnake ps);
-
-
- //————————————————————————————————————————————————————————
- //运行过程
- void GameRun(pSnake ps);
-
- //打印基本信息
- void PrintHelpInfo();
-
- //暂停
- void Pause();
-
- //蛇移动
- void SnakeMove(pSnake ps);
-
- //判断是否是食物
- int NextIsFood(pSnake ps, pSnakeNode pNext);
-
- //吃掉食物
- void EatFood(pSnake ps, pSnakeNode pNext);
-
- //不吃食物
- void NoFood(pSnake ps, pSnakeNode pNext);
-
- //判断是否撞墙
- void KillByWall(pSnake ps);
-
- //判断是否自杀
- void KillBySelf(pSnake ps);
-
-
- //————————————————————————————————————————————————————————————
- //游戏结束
- void GameEnd(pSnake ps);
- #include"Snake.h"
-
- void SetPos(int x, int y) {
- //获取控制台句柄
- HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
- //COORD是控制台存储一个坐标的结构体,
- COORD pos = { x,y };
- //设置光标的所在位置 SetConsoleCursorPosition
- SetConsoleCursorPosition(handle, pos);
- }
-
-
- //打印欢迎界面
- void welComeToGame() {
- SetPos(51, 18);
- printf("欢迎来到贪吃蛇游戏");
-
- SetPos(53, 36);
- //Windows 中暂停的指令,按任意键结束暂停
- system("pause");
-
- //清除之前屏幕上打印的信息
- system("cls");
-
- SetPos(51, 18);
- printf("游戏玩法规则如下:");
-
- SetPos(35, 20);
- printf("←↑→↓来操控贪吃蛇移动,Esc退出游戏,Space暂停游戏");
-
- SetPos(53, 22);
- printf("F3加速,F4减速");
-
- SetPos(53, 36);
- system("pause");
-
- system("cls");
- }
-
- //游戏地图
- void CreateMap() {
- //上
- SetPos(0, 0);
- for (int i = 0; i <= 78; i += 2) {
- wprintf(L"%lc", WALL);
- }
- //左
- for (int i = 1; i <= 34; i++) {
- SetPos(0, i);
- wprintf(L"%lc", WALL);
- }
- //右
- for (int i = 1; i <= 34; i++) {
- SetPos(78, i);
- wprintf(L"%lc", WALL);
- }
- //下
- SetPos(0, 34);
- for (int i = 0; i <= 78; i += 2) {
- wprintf(L"%lc", WALL);
- }
- }
-
- //初始化贪吃蛇
- void InitSnake(pSnake ps) {
- pSnakeNode cur = NULL;
- for (int i = 0; i < 5; i++) {
- cur = (pSnakeNode)malloc(sizeof(SnakeNode));
- if (cur == NULL) {
- perror("InitSnake() error!");
- return;
- }
- cur->x = POS_X + i * 2;
- cur->y = POS_Y;
- cur->next = NULL;
-
- //头插法
- if (ps->_psnake == NULL) {
- ps->_psnake = cur;
- }
- else {
- cur->next = ps->_psnake;
- ps->_psnake = cur;
- }
- }
- // 遍历这个链表
- while (cur) {
- SetPos(cur->x, cur->y);
- wprintf(L"%lc", BODY);
- cur = cur->next;
- }
-
- ps->_Status = OK;
- ps->_Score = 50;
- ps->_pFood = NULL;
- ps->_SleepTime = 200;
- ps->_FootWeight = 10;
- ps->_Dir = RIGHT;
- }
-
- //创建食物
- void CreatFood(pSnake ps) {
- //1、坐标应该是随机生成的,但是这个随机是由约束的
- //2、食物坐标必须在方框内
- //3、食物的x坐标必须是2的倍数
- int x = 0;
- int y = 0;
- again:
- do {
- x = rand() % 76 + 2;
- y = rand() % 33 + 1;
- } while (x % 2 != 0);
-
- //4、食物的坐标不能跟蛇身重叠,冲突 ,一一进行比较
- pSnakeNode cur = ps->_psnake;
- while (cur) {
- //比较
- if (cur->x == x && cur->y == y) {
- //出现重叠的就 goto 前面重新来过
- goto again;
- }
- cur = cur->next;
- }
- pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));
- if (pFood == NULL) {
- perror("CreateFood(); malloc error!");
- return;
- }
- pFood->x = x;
- pFood->y = y;
- ps->_pFood = pFood;
-
- SetPos(x, y);
- wprintf(L"%lc", FOOD);
-
- }
-
- //游戏初始化
- void GameStart(pSnake ps) {
- setlocale(LC_ALL, "");
- system("mode con cols=120 lines=40");
- system("title 贪吃蛇");
- //1_隐藏光标
-
- HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); //先获得控制台的句柄
- //一个控制台光标的信息的结构体 CONSOLE_CURSOR_INFO
- CONSOLE_CURSOR_INFO CursorInfo;
- //通过句柄获取控制台的光标信息,并储存在 CursorInfo 内
- GetConsoleCursorInfo(handle, &CursorInfo);
- //通过修改 CursorInfo 内的光标信息 bVisible 隐藏掉,不显示
- CursorInfo.bVisible = false; //需要头文件 <stdbool.h>
- //修改成功后需要执行修改
- SetConsoleCursorInfo(handle, &CursorInfo);
-
- //2_打印欢迎界面
- welComeToGame();
-
- //3_创建地图
- CreateMap();
-
- //4_初始化贪吃蛇
- InitSnake(ps);
-
- //5_创建食物
- CreatFood(ps);
- }
-
- //—————————以下是运行过程——————————————————————————————————————————————————
- //打印基本信息
- void PrintHelpInfo() {
-
- SetPos(85, 12);
- printf("1、不能撞墙,不能吃到自己");
-
- SetPos(85, 14);
- printf("2、←↑→↓来操控贪吃蛇移动");
-
- SetPos(85, 16);
- printf("3、F3加速,F4减速");
-
- SetPos(85, 18);
- printf("4、Esc退出游戏,Space暂停游戏");
-
- }
-
- //暂停
- void Pause() {
- while (1) {
- Sleep(200);
- if (KEY_PRESS(VK_SPACE)) {
- break;
- }
- }
- }
-
- //判断是否是食物
- int NextIsFood(pSnake ps, pSnakeNode pNext) {
- if (ps->_pFood->x == pNext->x && ps->_pFood->y == pNext->y) {
- return 1;
- }
- return 0;
- }
-
- //吃掉食物
- void EatFood(pSnake ps, pSnakeNode pNext) {
- pNext->next = ps->_psnake;
- ps->_psnake = pNext;
-
-
- pSnakeNode cur = ps->_psnake;
- while (cur) {
- SetPos(cur->x, cur->y);
- wprintf(L"%lc", BODY);
- cur = cur->next;
- }
-
- //给总分加上分数
- ps->_Score += ps->_FootWeight;
-
- free(ps->_pFood);
- //还得重新创建新的食物
- CreatFood(ps);
- }
-
- //不吃食物
- void NoFood(pSnake ps, pSnakeNode pNext) {
- //头插入节点
- pNext->next = ps->_psnake;
- ps->_psnake = pNext;
-
- //释放尾节点
- pSnakeNode cur = ps->_psnake;
- while (cur->next->next != NULL) {
- SetPos(cur->x, cur->y);
- wprintf(L"%lc", BODY);
- cur = cur->next;
- }
- SetPos(cur->next->x, cur->next->y);
- printf(" ");
- free(cur->next);
- cur->next = NULL;
- }
-
- //判断是否撞墙
- void KillByWall(pSnake ps) {
- if (ps->_psnake->x == 0 || ps->_psnake->y == 35 || ps->_psnake->x == 80 || ps->_psnake->y == 0) {
- ps->_Status = KILL_BY_WALL;
- }
- }
-
- //判断是否自杀
- void KillBySelf(pSnake ps) {
- pSnakeNode cur = ps->_psnake->next;
- while (cur) {
- if (ps->_psnake->x == cur->x && ps->_psnake->y == cur->y) {
- ps->_Status = KILL_BY_SELF;
-
- }
- cur = cur->next;
- }
- }
-
- //蛇移动
- void SnakeMove(pSnake ps) {
- //为下一个移动的点创建一个节点
- pSnakeNode pNext = (pSnakeNode)malloc(sizeof(SnakeNode));
- if (pNext == NULL) {
- perror("SnakeMove() malloc() error!");
- return;
- }
-
- switch (ps->_Dir) {
- case UP:
- {
- pNext->x = ps->_psnake->x;
- pNext->y = ps->_psnake->y - 1;
- }
- break;
- case DOWN: {
- pNext->x = ps->_psnake->x;
- pNext->y = ps->_psnake->y + 1;
- }
- break;
- case LEFT: {
- pNext->x = ps->_psnake->x - 2;
- pNext->y = ps->_psnake->y;
- }
- break;
- case RIGHT: {
- pNext->x = ps->_psnake->x + 2;
- pNext->y = ps->_psnake->y;
- }
- break;
- }
-
- //判断是否是食物
- if (NextIsFood(ps, pNext)) {
- //吃掉食物
- EatFood(ps, pNext);
- }
- else {
- //不吃
- NoFood(ps, pNext);
- }
-
- 判断是否撞墙
- KillByWall(ps);
- 判断是否自杀
- KillBySelf(ps);
- }
-
- void GameRun(pSnake ps) {
- PrintHelpInfo();
- do {
- SetPos(85, 10);
- printf("得分:%05d", ps->_Score);
- SetPos(85, 11);
- printf("食物分数:%2d", ps->_FootWeight);
-
- //检测按键情况
- //本来方向就是向上就不能往相反方向了
- if (KEY_PRESS(VK_UP) && ps->_Dir != DOWN) {
- ps->_Dir = UP;
- }
- else if (KEY_PRESS(VK_DOWN) && ps->_Dir != UP) {
- ps->_Dir = DOWN;
- }
- else if (KEY_PRESS(VK_LEFT) && ps->_Dir != RIGHT) {
- ps->_Dir = LEFT;
- }
- else if (KEY_PRESS(VK_RIGHT) && ps->_Dir != LEFT) {
- ps->_Dir = RIGHT;
- }
- else if (KEY_PRESS(VK_ESCAPE)) {
- ps->_Status = END_NORMAL;
- break;
- }
- else if (KEY_PRESS(VK_SPACE)) {
- //封装一个暂停函数
- Pause();
- }
- //加速
- else if (KEY_PRESS(VK_F3)) {
- if (ps->_SleepTime >= 100) {
- ps->_SleepTime -= 30;
- ps->_FootWeight += 2;
- }
- }
- //减速
- else if (KEY_PRESS(VK_F4)) {
- if (ps->_SleepTime <= 320) {
- ps->_SleepTime += 30;
- ps->_FootWeight -= 2;
- }
- }
- //设置完后要应用休眠的时间
- Sleep(ps->_SleepTime);
- //让蛇移动起来
- SnakeMove(ps);
-
- } while (ps->_Status == OK);
- }
- //————————游戏善后———————————————————————————————————————————————————
-
-
- //游戏结束
- void GameEnd(pSnake ps) {
- SetPos(39, 16);
- switch (ps->_Status) {
- case END_NORMAL:
- printf("退出游戏成功!(っ °Д °;)っ下次还要再来一把");
- break;
- case KILL_BY_WALL:
- printf("撞墙啦!(╯°□°)╯︵ ┻━┻");
- break;
- case KILL_BY_SELF:
- printf("自杀啦!你怎么咬到自己了啊!( ´・・)ノ(._.`)");
- break;
- }
-
- SetPos(39, 18);
-
- pSnakeNode cur = ps->_psnake;
- while (cur) {
- pSnakeNode del = cur;
- cur = cur->next;
- free(del);
- }
- }
- #include"Snake.h"
-
- void test() {
- int ch = 0;
- do {
- Snake snake = { 0 };//创建贪吃蛇
- //初始化状态界面
- //1、游戏开始 - 初始化游戏
- GameStart(&snake);
- //2、游戏运行 - 游戏的正常运行过程
- GameRun(&snake);
- //3、游戏结束 - 游戏善后(释放资源)
- GameEnd(&snake);
- printf("是否再来一把(Y/N)");
- ch = getchar();
- getchar();//清理
- } while (ch == 'Y' || ch == 'y');
-
- }
-
- int main()
- {
- setlocale(LC_ALL, ""); //使用本地的ASCII环境
- srand((unsigned int)time(NULL)); //随机数的设置
- test();
-
- return 0;
- }
-
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。