赞
踩
目录
SetConsoleCursorPosition - 设置光标位置
注意事项:
在此项目中我们需要用到 Win32 API 中的一些函数完成对控制台应用程序的操作,接下来我们将挨个介绍
Win32 API(Windows 32-bit Application Programming Interface)是微软为Windows操作系统提供的一套应用程序编程接口(API)。它允许开发者使用C或C++等编程语言来编写Windows桌面应用程序。Win32 API涵盖了从基本的窗口管理、图形绘制到更高级的网络编程、文件I/O和线程同步等各种功能。
控制台应用程序的一些属性:
1.控制台名称,控制的窗口大小
2.控制台光标位置
3.控制台光标的大小属性
除了控制台名称以外的属性,接下来我们都要使用Win32 API 中的函数 来对它们进行修改
mode con cols= 100 lines= 30
也可以通过命令设置控制台窗⼝的名字:
title 贪吃蛇
这些能在控制台窗口执行的命令,也可以调⽤C语⾔函数system来执⾏。例如:
- #include <stdio.h>
- int main()
- {
- //设置控制台窗⼝的⻓宽:设置控制台窗⼝的⼤⼩,30⾏,100列
- system("mode con cols=100 lines=30");
-
- //设置cmd窗⼝名称
- system("title 贪吃蛇");
-
- return 0;
- }
想要精确的定位控制台光标的位置,我们首先要知道控制台是有坐标轴的。
有了坐标轴的概念,我们才能更好的去设置控制
COORD是 Windows API 中定义的⼀个结构体,表示⼀个字符在控制台屏幕幕缓冲区上的坐标
COORD类型的声明:
typedef struct _ COORD {SHORT X;SHORT Y;} COORD, *PCOORD;
创建一个COORD类型的结构体类型变量,并赋值:
COORD pos = { 10, 15 };
包含 <windows.h>
头文件中
函数原型:HANDLE GetStdHandle(DWORD nStdHandle);
GetStdHandle函数为Windows API 中的一个函数,它用于获取特定设备上(标准输入,标准输出,标准错误)中获取一个句柄(用来获取设备不同的数值),使用这个句柄可以操作设备
参数:
DWORD nStdHandle:标准设备,此参数的取值可为下列值之一
值 | 含义 |
STD_INPUT_HANDLE | 标准输入设备,通常为键盘 |
STD_OUTPUT_HANDLE | 标准输出设备,通常为屏幕 |
STD_ERROR_HANDLE | 标准错误设备,通常为屏幕 |
返回值:
HANDLE : 该返回值其实是一个指向HANDLE结构体的指针
经过重命名 --- typedef void *HANDLE 为 HANDLE
也可以把它称为一个句柄,通过句柄我们可以修改控制台的属性
使用:
- int main() {
-
- //创建一个HANDLE指针变量
- HANDLE hOutput = NULL;
-
- //获取标准输出的句柄(⽤来标识不同设备的数值)
- hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
-
- return 0;
- }
包含 <windows.h>
头文件中
函数原型:
BOOL WINAPI SetConsoleCursorPosition (HANDLE hConsoleOutput,COORD pos);
设置屏幕缓冲区新的光标位置
参数:
HANDLE hConsoleOutput : HANDLE指针变量(控制台屏幕的句柄)
COORD pos : 指定新光标位置(以字符为单位)的 COORD 结构。
返回值:
如果该函数成功,则返回值为非零值。
如果函数失败,则返回值为零。
使用:
将光标的位置定位到 x = 10 y = 5 的位置
- int main(){
- //创建一个HANDLE指针变量
- HANDLE hOutput = NULL;
-
- //获取标准输出的句柄(⽤来标识不同设备的数值)
- hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
-
- //设置COORD结构体变量的 x y 值
- COORD pos = { 10 , 5 };
-
- //设置新的光标位置
- SetConsoleCursorPosition(hOutput, pos);
-
- getchar();
- }
- //设置光标的坐标
- void SetPos(short x, short y)
- {
-
- //获取标准输出的句柄
- HANDLE hOutput = NULL;
- hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
-
- //设置标准输出上光标的位置为pos
- COORD pos = { x, y };
- SetConsoleCursorPosition(hOutput, pos);
-
- }
typedef struct _ CONSOLE_CURSOR_INFO {DWORD dwSize;BOOL bVisible;} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;
成员 DWORD dwSize --- 由光标填充的字符单元格的百分⽐。 此值介于1到100之间。 光标外观会变化,范围从完全填充单元格到单元底部的⽔平线条。
成员 BOOL bVisible --- 游标的可⻅性。 如果光标可⻅,则此成员为 true,如果光标不可见,则此成员为 false
创建一个COORD类型的结构体类型变量,并赋值:
- int main(){
-
- //创建一个CONSOLE_CURSOR_INFO结构体变量,并且赋值
- CONSOLE_CURSOR_INFO CursorInfo = {50 , false };
-
- return 0;
- }
包含 <windows.h>
头文件中
函数原型:
BOOL WINAPI SetConsoleCursorInfo (HANDLE hConsoleOutput,const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo);
为指定的控制台屏幕缓冲区设置光标的大小和可见性。
参数:
HANDLE hConsoleOutput :HANDLE指针变量(控制台屏幕的句柄)
const CONSOLE_CURSOR_INFO *lpConsoleCursorInfo :指向 CONSOLE_CURSOR_INFO 结构的指针,该结构为控制台屏幕缓冲区的光标提供新的规范。
返回值 :
如果该函数成功,则返回值为非零值。
如果函数失败,则返回值为零。
使用 :
隐藏控制台光标操作
- int main(){
- //影藏光标操作
-
- HANDLE hOutput = NULL;
- //获取标准输出的句柄(⽤来标识不同设备的数值)
- hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
-
- CONSOLE_CURSOR_INFO CursorInfo = { 1,false };//创建结构体,并赋值以你想要设置的控制台光标属性
-
- SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标新的属性
-
- return 0;
- }
包含 <windows.h>
头文件中
函数原型:
SHORT GetAsyncKeyState (int vKey);
确定调用函数时键是向上还是向下,以及上次调用 GetAsyncKeyState 后是否按下了该键。
参数:
int vKey --- 键盘上各个按键的虚拟键码 具体虚拟键码点击此处查看
返回值:
函数的返回值是一个SHORT
类型,表示指定键的状态。如果指定的键被按下,则返回值的最高位(位15)为1,同时如果自上次调用GetAsyncKeyState
以来键已被按过,则最低位(位0)也为1。如果键未被按下,则返回值为0。因此,如果返回值是负数,表示该键此前被按下并一直保持按下状态。
使用:
- //原理 : 判断返回值的最低为是否为1,是的话返回 1,不是的话返回 0
- #define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )
我们最终实现的游戏大概长这个样子
包含 <locale.h>
头文件中
函数原型:char* setlocale (int category, const char* locale);
对编译器进行本地化设置,编译器才能支持我们宽字符(汉字)的输出
参数 :
int category :
受影响的类项,主要有下面这几个参数
参数 | 受影响的类项 |
LC_COLLATE
|
影响字符串⽐较函数
strcoll()
和
strxfrm()
|
LC_CTYPE
|
影响字符处理函数的⾏为
|
LC_MONETARY
|
影响货币格式
|
LC_NUMERIC
|
影响
printf()
的数字格式
|
LC_TIME
|
影响时间格式
strftime()
和
wcsftime()
|
LC_ALL
|
针对所有类项修改,将以上所有类别设置为给定的语⾔环境
|
const char* locale :
C标准给第⼆个参数仅定义了2种可能取值:"C"(正常模式)和" "(本地模式)
在任意程序开始执行的时候都会隐藏执行调用:
setlocale(LC_ALL, "C");
返回值 :
成功后,指向 C 字符串的指针
如果函数无法设置新的区域设置,则不会修改此设置,并返回空指针
使用:
设置本地化模式,后就⽀持宽字符(汉字)的输出等。
setlocale(LC_ALL, " ");//切换到本地环境
宽字符的定义:
宽字符数据类型为 wchar_t 当我们定义一个宽字符常量的时候,我们要在应号之前加上 :L
例如:
- #include <stdio.h>
- #include<locale.h>
- int main() {
-
- setlocale(LC_ALL, "");
- wchar_t ch1 = L'●';
- wchar_t ch2 = L'玖';
- wchar_t ch3 = L'伍';
- wchar_t ch4 = L'★';
-
- return 0;
- }
宽字符的打印:
宽字符的打印需要用到函数 wprintf () ,用法与printf ()类似
宽字符的占位符为:%lc
例外在函数wprintf()格式的前面也要加上 :L ,才能正确的打印宽字符
例如:
- #include <stdio.h>
- #include<locale.h>
-
- int main() {
- setlocale(LC_ALL, "");
- wchar_t ch1 = L'●';
- wchar_t ch2 = L'玖';
- wchar_t ch3 = L'伍';
- wchar_t ch4 = L'★';
-
-
- wprintf(L"%lc\n", ch1);
- wprintf(L"%lc\n", ch2);
- wprintf(L"%lc\n", ch3);
- wprintf(L"%lc\n", ch4);
-
- return 0;
-
- }
例如我们想实现27行 ,58 列的一个贪吃蛇地图,在围绕着地图填充墙体
注意:
一个窄字符在屏幕缓冲区上是一个长方形
一个宽字符在屏幕缓冲区上占两个窄字符
所以当我们围绕贪吃蛇地图填充墙的时候,会变成图上这样
设计一个结构体来管理我们的贪吃蛇
- //蛇的身体
- typedef struct SnakeNode {
- int x;
- int y;
- struct SnakeNode* next;
- }SnakeNode,* pSnakeNode;
-
- //蛇头的方向
- enum DIRECTION {
- UP = 1,
- DOWN,
- LEFT,
- RIGHT
- };
-
- //贪吃蛇的状态
- enum GAME_STATUSL {
- OK,//正常状态
- KILL_BY_WALL,//撞到墙死了
- KILL_BY_SELF,//撞到自己死了
- END_NORMAL//游戏正常退出
- };
-
- //贪吃蛇对象
- typedef struct Snake {
- pSnakeNode _pSnake; //指向蛇头的指针
- pSnakeNode _pFood; //指向食物节点的指针
- enum DIRECTION _dir; //蛇头的方向
- enum GAME_STATUSL _status; //游戏此时的状态
- int _food_weight; //一个食物的分数
- int _score; //游戏总分
- int _sleep_time; //游戏休眠的时间,休眠时间越短,速度越快,休眠时间越长,速度越慢
- }Snake,* pSnake;
贪吃蛇的属性我们选着利用结构体来维护它
- #pragma once
- #include<stdio.h>
- #include<windows.h>
- #include<stdlib.h>
- #include<stdbool.h>
- #include<locale.h>
- #include<time.h>
-
- #define WALL L'□'
- #define pos_x 24
- #define pos_y 5
- #define BODY L'●'
- #define FOOD L'☆'
-
- #define KEY_PRESS(VK) ((GetAsyncKeyState(VK) & 1) ? 1 : 0)
-
- //蛇的身体
- typedef struct SnakeNode {
- int x;
- int y;
- struct SnakeNode* next;
- }SnakeNode, * pSnakeNode;
-
- //蛇头的方向
- enum DIRECTION {
- UP = 1,
- DOWN,
- LEFT,
- RIGHT
- };
-
- //贪吃蛇的状态
- enum GAME_STATUSL {
- OK,//正常状态
- KILL_BY_WALL,//撞到墙死了
- KILL_BY_SELF,//撞到自己死了
- END_NORMAL//游戏正常退出
- };
-
- //贪吃蛇对象
- typedef struct Snake {
- pSnakeNode _pSnakeHead; //指向蛇头的指针
- pSnakeNode _pFood; //指向食物节点的指针
- enum DIRECTION _dir; //蛇头的方向
- enum GAME_STATUSL _status; //游戏此时的状态
- int _food_weight; //一个食物的分数
- int _score; //游戏总分
- int _sleep_time; //游戏休眠的时间,休眠时间越短,速度越快,休眠时间越长,速度越慢
- }Snake, * pSnake;
-
- //1.游戏开始
- void GameStart(pSnake ps);
-
- //定位光标函数
- void SetPos(short x,short y);
-
- //打印欢迎界面
- WelcomeToGame();
-
- //地图绘制
- CreateMap();
-
- //创建一条贪吃蛇,并且部分初始化
- void InitSnake(pSnake ps);
-
- //创建食物
- void CreatFood(pSnake ps);
-
- //2.游戏运行
- void GameRun(pSnake ps);
-
- //暂停
- void Pause();
-
- //蛇走一步的过程
- void SnakeMove(pSnake ps);
-
- //判断下一个位置是不是食物
- int NextIsFood(pSnakeNode pn, pSnake ps);
-
- //吃掉食物
- void EatFood(pSnakeNode pn, pSnake ps);
-
- //不是食物走一步
- void NoFood(pSnakeNode pn, pSnake ps);
-
- //检测蛇是否撞到墙
- void KillByWall(pSnake ps);
-
- //检测蛇是否撞到自己
- void KillBySelf(pSnake ps);
-
- //3.游戏结束
- void GameOvre(pSnake ps);
- #define _CRT_SECURE_NO_WARNINGS 1
- #include"Snake.h"
- //定位光标函数
- void SetPos(short x,short y) {
-
- //获取句柄
- HANDLE hOutput = NULL;
- hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
-
- //设置标准输出上光标的位置为pos
- COORD pos = { x, y };
- SetConsoleCursorPosition(hOutput, pos);
-
- }
-
- //打印欢迎界面
- WelcomeToGame() {
-
- SetPos(35,13);
- wprintf(L"欢迎来到贪吃蛇小游戏");
- SetPos(36, 17);
- system("pause");
-
- system("cls");
-
- SetPos(24, 13);
- wprintf(L"按↑ . ↓ . ← . → 来控制蛇的移动,F3加速 ,F4减速");
- SetPos(35, 14);
- wprintf(L"加速能够得到更高的分数");
- SetPos(36, 17);
- system("pause");
-
- system("cls");
-
- }
-
- //绘制地图
- CreateMap() {
-
- //上墙
- for (int i = 0; i < 29; i++)
- {
- wprintf(L"%lc", WALL);
- }
-
- //下墙
- SetPos(0,26);
- for (int i = 0; i < 29; i++)
- {
- wprintf(L"%lc", WALL);
- }
-
- //左墙
- for (int i = 1; i <= 25; i++)
- {
- SetPos(0,i);
- wprintf(L"%lc", WALL);
- }
-
- //右墙
- for (int i = 1; i <= 25; i++)
- {
- SetPos(56, i);
- wprintf(L"%lc", WALL);
- }
- }
-
- //创建一条贪吃蛇,并且部分初始化
- void InitSnake(pSnake ps) {
- //初始化蛇头方向,一个食物分数,总分数,屏幕休眠时间,蛇状态
- ps->_dir = RIGHT;
- ps->_food_weight = 10;
- ps->_score = 0;
- ps->_sleep_time = 200;
- ps->_status = OK;
-
- //初始化蛇身
- pSnakeNode cur = NULL;
-
- for (int i = 0; i < 5; i++)
- {
- cur = (pSnakeNode)malloc(sizeof(SnakeNode));//创建新的蛇身节点
- if (cur == NULL)
- {
- perror("InitSnak()::malloc()");
- return;
- }
-
- //设置蛇身节点坐标,即让每个节点成为新的蛇头
- cur->x = pos_x + i * 2; //每次新的节点x轴坐标都比前一个蛇身节点多2格
- cur->y = pos_y;
- cur->next = NULL;
-
- //使用头插法把蛇身节点都连接起来
- if (ps->_pSnakeHead == NULL)
- {
- ps->_pSnakeHead = cur; //蛇身一个节点都没有的情况
- }
- else
- {
- cur->next = ps->_pSnakeHead;
- ps->_pSnakeHead = cur;
- }
-
- }
-
- //将蛇打印在地图上
- cur = ps->_pSnakeHead;
- while (cur)
- {
- SetPos(cur->x,cur->y);
- wprintf(L"%lc",BODY);
- cur = cur->next;
- }
-
- }
-
- //创建食物
- void CreatFood(pSnake ps) {
- int x;
- int y;
- //为食物创建随机的坐标
- again:
- do
- {
- //食物的坐标要在墙体内
- x = rand() % 53 + 2; //x轴的范围是 2 ~ 54
- y = rand() % 25 + 1; //y轴的范围是 1 ~ 25
- } while (x % 2 != 0);
-
- //检查食物坐标是否与蛇身重叠
- pSnakeNode cur = ps->_pSnakeHead;
- while (cur)
- {
- if ((cur->x == x) && (cur->y == y))
- {
- goto again;//若重叠,则重新为食物创建坐标
- }
- cur = cur->next;
- }
-
- //创建食物节点
- pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));
- if (pFood == NULL)
- {
- perror("CreatFood()::malloc()");
- }
- pFood->x = x;
- pFood->y = y;
- pFood->next = NULL;
-
- //记录食物节点到贪吃蛇中
- ps->_pFood = pFood;
-
- //打印食物
- SetPos(x,y);
- wprintf(L"%lc", FOOD);
-
- }
-
- //一.游戏开始
- void GameStart(pSnake ps) {
- //1.设置窗口大小,名称
- system("mode con cols=100 lines=30");
- system("title 贪吃蛇");
-
- //2.隐藏光标
- HANDLE hOutput = NULL;
- //获取标准输出的句柄(⽤来标识不同设备的数值)
- hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
- CONSOLE_CURSOR_INFO CursorInfo = { 1,false }; //创建结构体,并赋值以你想要设置的控制台光标属性
- SetConsoleCursorInfo(hOutput, &CursorInfo);
-
- //3.打印欢迎界面
- WelcomeToGame();
-
- //4.地图绘制
- CreateMap();
-
- //5.将贪吃蛇属性部分初始化
- InitSnake(ps);
-
- //6.创建食物
- CreatFood(ps);
-
- /*getchar();*/
-
- }
- PrintfHelpInfo() {
-
- SetPos(62, 10);
- wprintf(L"%ls", L"不能穿墙,不能撞到自己");
- SetPos(62, 11);
- wprintf(L"%ls", L"按↑ . ↓ . ← . → 来控制蛇的移动");
- SetPos(62, 12);
- wprintf(L"%ls", L"F3加速 ,F4减速");
- SetPos(62, 13);
- wprintf(L"%ls", L"按Esc退出游戏,按空格暂停游戏");
-
- SetPos(62, 16);
- wprintf(L"%ls", L"———玖伍出品———");
- }
-
- //暂停
- void Pause() {
- while (1) {
- Sleep(200);//为了省性能加上屏幕睡眠时间,否者一直死循环浪费新能
- if (KEY_PRESS(VK_SPACE))
- {
- break;
- }
- }
- }
-
- //判断下一个位置是不是食物
- int NextIsFood(pSnakeNode pn, pSnake ps) {
- return ((pn->x == ps->_pFood->x) && (pn->y == ps->_pFood->y));
- }
-
- //吃掉食物
- //pSnakeNode psn 是计算的下⼀个节点的地址
- //pSnake ps 维护蛇的指针
- void EatFood(pSnakeNode pn, pSnake ps) {
-
- //头插法,将即将要吃掉的食物节点成为新的头结点
- ps->_pFood->next = ps->_pSnakeHead;//食物节点成为新的头节点
- ps->_pSnakeHead = ps->_pFood; //改变贪吃蛇的蛇头属性
-
- //打印蛇
- pSnakeNode cur = ps->_pSnakeHead;
- while (cur)
- {
- SetPos(cur->x, cur->y);
- wprintf(L"%c", BODY); //第一次循环就将原来的食物节点覆盖了,不用做过多的处理
- cur = cur->next;
- }
-
- //吃到食物加总分
- ps->_score += ps->_food_weight;
-
- //释放我们计算的下一个节点
- free(pn);
- pn = NULL;
-
- //创建新的食物
- CreatFood(ps);
- }
-
- //不是食物走一步
- void NoFood(pSnakeNode pn, pSnake ps) {
-
- //走一步的过程:将计算的下一个节点头插,打印新的蛇(除了尾节点),最后在释放尾节点
-
- //将计算的下一个节点成为新的蛇头
- pn->next = ps->_pSnakeHead;
- ps->_pSnakeHead = pn;
-
- //打印的蛇头,覆盖食物的图案
- pSnakeNode cur = ps->_pSnakeHead;
- SetPos(cur->x, cur->y);
- wprintf(L"%lc", BODY);
-
- //找到新蛇倒数第二个节点,我们后面要让他成为新的尾节点,和释放旧的尾节点
- while (cur->next->next != NULL)
- {
- cur = cur->next;
- }
-
- //清除屏幕上残留的旧尾节点图案
- SetPos(cur->next->x, cur->next->y);
- printf(" ");
-
- //释放尾节点
- free(cur->next);
- cur->next = NULL;
-
- //将新为节点的next指向NULL
- cur->next = NULL;
- }
-
- //检测蛇是否撞到墙
- void KillByWall(pSnake ps) {
- if (ps->_pSnakeHead->x == 0 || ps->_pSnakeHead->x == 56 ||
- ps->_pSnakeHead->y == 0 || ps->_pSnakeHead->y == 26)
- {
- ps->_status = KILL_BY_WALL;
- }
- }
-
- //检测蛇是否撞到自己
- void KillBySelf(pSnake ps) {
-
- pSnakeNode cur = ps->_pSnakeHead->next;
- while (cur)
- {
- //若蛇头与某个蛇身体节点重叠就撞到自己了
- if (cur->x == ps->_pSnakeHead->x && cur->y == ps->_pSnakeHead->y)
- {
- ps->_status = KILL_BY_SELF;
- break;
- }
- cur = cur->next;
- }
- }
-
- //蛇走一步的过程
- void SnakeMove(pSnake ps) {
-
- //计算蛇头的下一刻的位置
- pSnakeNode pNextNode = (pSnakeNode)malloc(sizeof(SnakeNode));
- if (pNextNode == NULL)
- {
- perror("SnakeMove()::malloc");
- }
-
- switch (ps->_dir)
- {
- case UP:
- pNextNode->x = ps->_pSnakeHead->x;
- pNextNode->y = ps->_pSnakeHead->y - 1;
- break;
- case DOWN:
- pNextNode->x = ps->_pSnakeHead->x;
- pNextNode->y = ps->_pSnakeHead->y + 1;
- break;
- case RIGHT:
- pNextNode->x = ps->_pSnakeHead->x + 2;
- pNextNode->y = ps->_pSnakeHead->y;
- break;
- case LEFT:
- pNextNode->x = ps->_pSnakeHead->x - 2;
- pNextNode->y = ps->_pSnakeHead->y;
- break;
- }
-
- //判断下一个位置是不是食物
-
- if (NextIsFood(pNextNode,ps))//是食物此函数返回1,否者返回0
- {
- //下一个位置是食物,就吃掉
- EatFood(pNextNode, ps);
- }
- else
- {
- //下一个位置不是食物,蛇整体走一步
- NoFood(pNextNode, ps);
- }
-
- //检测蛇是否撞到墙
- KillByWall(ps);
-
- //检测蛇是否撞到自己
- KillBySelf(ps);
- }
- //2.游戏运行
- void GameRun(pSnake ps) {
-
- //1.右侧打印帮助信息
- PrintfHelpInfo();
-
- //2.贪吃蛇在地图里行走,当蛇的状态!= OK时,结束行走
- do {
-
- //食物分数与总分数随着游戏的进行会被改变,所以要一直打印,直至游戏结束
- SetPos(64, 7);
- printf("总得分:%d ", ps->_score);
- SetPos(64, 8);
- printf("每个食物得分:%2d分", ps->_food_weight);
-
- 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_SPACE))
- {
- //暂停
- Pause();
- }
- else if (KEY_PRESS(VK_ESCAPE))
- {
- //正常退出游戏
- ps->_status = END_NORMAL;
- }
- else if (KEY_PRESS(VK_F3))
- {
- //加速
- if (ps->_sleep_time > 80)
- {
- ps->_sleep_time -= 30;
- ps->_food_weight += 2;
- }
- }
- else if (KEY_PRESS(VK_F4))
- {
- //减速
- if (ps->_food_weight > 2)
- {
- ps->_sleep_time += 30;
- ps->_food_weight -= 2;
- }
- }
-
- //蛇走一步的过程
- SnakeMove(ps);
- Sleep(ps->_sleep_time);
-
- }while(ps->_status == OK);//当状态不是OK时结束行走
-
- }
-
- //3.游戏结束
- void GameOvre(pSnake ps) {
- SetPos(24, 12);
- switch (ps->_status)
- {
- case END_NORMAL:
- printf("您主动结束了游戏");
- break;
- case KILL_BY_WALL:
- printf("您撞上了墙,结束了游戏");
- break;
- case KILL_BY_SELF:
- printf("您撞上了自己,结束了游戏");
- break;
- }
-
- //释放链表
- pSnakeNode cur = ps->_pSnakeHead;
- while (cur)
- {
- pSnakeNode del = cur;
- cur = cur->next;
- free(del);
- }
- }
- #define _CRT_SECURE_NO_WARNINGS 1
- #include"Snake.h"
-
-
- int main() {
-
- setlocale(LC_ALL, "");
- srand((unsigned int)time(NULL));
- int ch = 0;
-
- do
- {
- system("cls");
- //游戏开始
- Snake snake = { 0 };
- GameStart(&snake);
-
- //游戏中
- GameRun(&snake);
-
- //游戏结束
- GameOvre(&snake);
-
- SetPos(20, 15);
- printf("在来一局吗?(Y/N)");
- ch = getchar();
- //清理回车
- while (getchar() != '\n');
-
- } while (ch == 'y' || ch == 'Y');
-
- SetPos(0, 27);
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。