目录
游戏说明:
第一个是又是封面,第二个为提示信息,第三个是游戏运行界面
游戏效果展示:
游戏代码展示:
snack.c
test.c
snack.h
控制台程序的准备:
控制台程序名字修改:
参考:mode命令(mode | Microsoft Learn)
游戏框架构建:
控制台屏幕上的坐标COORD:
隐藏光标:
光标跳转
打印颜色设置:
初始化界面:
需要注意的地方就是:
例如第一次的坐标就为 (i,j) 那么下一次坐标就为(i+2,j);
宽字符打印准备:
初始化蛇与蛇的打印:
随机创建食物:
蛇的单向移动:
大致小部分已经实现完成,那么就利用游戏逻辑来实现剩余的代码;
添加方向的改变与判断蛇的各个状态判断:
对该函数里面各个小函数进行代码展示:
最后,还有对应的就是运行是代码的逻辑展示
速度的控制(单位毫秒):
最后的游戏收尾就是提示信息的打印:
最后一步便是锦上添花了,就是打印提示信息:
到这里就已经完成了,一共有三个页面:
第一个是又是封面,第二个为提示信息,第三个是游戏运行界面
游戏说明:
- 按方向键上下左右,可以实现蛇移动方向的改变
- 按F3加速,F4减速
- 按ESC正常退出游戏,按空格暂停游戏
- 加速可以获得更多的分数
- 获得100即可获得胜利
(待优化部分:背景音乐,记录历史最高得分)
第一个是又是封面,第二个为提示信息,第三个是游戏运行界面
游戏效果展示:
贪吃蛇游戏当中蛇的移动速度可以进行调整,动图当中把速度调得较慢(速度太快导致动图上蛇身显示不全),下面给出的代码当中将蛇的速度调整到了合适的位置,大家可以试试。
贪吃蛇
游戏代码展示:
snack.c
#define _CRT_SECURE_NO_WARNINGS
#include"snack.h"
void color(int c)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c); //颜色设置
//注:SetConsoleTextAttribute是一个API(应用程序编程接口)
}
void cursor_hide()
{
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
CursorInfo.bVisible = false; //隐藏控制台光标
SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态
}
void SetPos(int x,int y)
{
//获得标准输出设备的句柄
HANDLE hOutput = NULL;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//定位光标的位置,到pos
COORD pos = { x,y };
SetConsoleCursorPosition(hOutput, pos);
}
void Welcome_game()
{
color(9);
SetPos(35, 12);
wprintf(L"欢迎来到贪吃蛇小游戏\n");
SetPos(36, 18);
system("pause");
system("cls");
SetPos(25, 14);
wprintf(L"用 ↑.↓.←.→ 来控制蛇的移动");
SetPos(25, 15);
wprintf(L"按F3加速,F4减速");
SetPos(25, 16);
wprintf(L"按ESC正常退出游戏,按空格暂停游戏");
SetPos(25, 17);
wprintf(L"加速可以获得更多的分数");
SetPos(25, 18);
wprintf(L"由能力有限公司提供技术支持");
SetPos(0, 25);
system("pause");
system("cls");
color(7);
}
void CreatMap()
{
color(12);
//上
for (int i = 0; i < 29; i++)
{
wprintf(L"%lc", L'□');
}
//下
SetPos(0, 26);
for (int i = 0; i < 29; i++)
{
wprintf(L"%lc", L'□');
}
//左
for (int i = 1; i <= 25; i++)
{
SetPos(0, i);
wprintf(L"%lc", L'□');
}
//右
for (int i = 1; i <= 25; i++)
{
SetPos(56, i);
wprintf(L"%lc", L'□');
}
color(7);
}
void CreateSnack(pSnack ps)
{
color(10);
//默认开始初始化为5个结点
pSnackNode cur = NULL;
for (int i = 0; i < 5; i++)
{
cur =(pSnackNode)malloc(sizeof(SnackNode));
cur->next = NULL;
cur->x = POS_X + i * 2;
cur->y = POS_Y;
if (ps->_psnack == NULL)//第一次头插
{
ps->_psnack = cur;
}
else
{
cur->next = ps->_psnack;
ps->_psnack = cur;
}
}
while (cur)
{
SetPos(cur->x, cur->y);
wprintf(L"%lc", Body);
cur = cur->next;
}
cur= ps->_psnack;
//设置蛇的相关信息
ps->_dir = RIGHT;
ps->_food_weight = 10;
ps->_sleep_time = 200;
ps->_status = OK;
color(7);
}
void CreateFood(pSnack ps)
{
int x = 0;//2-54
int y = 0;//1-25
again:
do{
x = rand() % 53 + 2;
y = rand() % 24 + 1;
} while (x%2!=0);
//检测改坐标是否与蛇身重合
pSnackNode cur = ps->_psnack;
while (cur)
{
if (cur->x == x && cur->y == y)
{
goto again;
}
cur = cur->next;
}
pSnackNode SnackFood = (pSnackNode)malloc(sizeof(SnackNode));
if (SnackFood == NULL)
{
perror("CreateFood malloc fail");
return;
}
color(13);
SnackFood->x = x;
SnackFood->y = y;
SnackFood->next = NULL;
SetPos(x, y);
wprintf(L"%lc", Food);
ps->_pfood = SnackFood;
color(7);
}
void Pause()
{
while (1)
{
Sleep(200);
if (KEY_PRESS(VK_SPACE))
{
break;
}
}
}
void GameStart(pSnack ps)
{
system("mode con cols=100 lines=30");
system("title 贪吃蛇");
//1光标隐藏
cursor_hide();
//2.打印环境界面
//第一个界面,欢迎
// 第二个界面,介绍怎么操作游戏
Welcome_game();//+3.功能介绍
CreatMap();
//创建蛇
CreateSnack(ps);
//创建食物
CreateFood(ps);
//SetPos(0, 29);
//system("pause");
}
void PrintHelpInfo()
{
color(15);
SetPos(64, 10);
wprintf(L"不能穿墙,不能咬到自己");
SetPos(64, 12);
wprintf(L"用 ↑.↓.←.→ 来控制蛇的移动");
SetPos(64, 14);
wprintf(L"按F3加速,F4减速");
SetPos(64, 16);
wprintf(L"按ESC正常退出游戏,按空格暂停游戏");
SetPos(64, 18);
wprintf(L"能力有限公司提供支持");
SetPos(0, 29);
// system("pause");
color(7);
}
bool Next_Is_Food(pSnackNode pn, pSnack ps)
{
return (ps->_pfood->x == pn->x && ps->_pfood->y == pn->y);
}
void Eat_Food(pSnackNode pn, pSnack ps)
{
ps->_pfood->next = ps->_psnack;
ps->_psnack = ps->_pfood;
free(pn);
pn = NULL;
pSnackNode cur = ps->_psnack;
color(10);
while (cur)
{
SetPos(cur->x, cur->y);
wprintf(L"%lc", Body);
cur = cur->next;
}
color(7);
ps->_sum_score += ps->_food_weight;
//在重新生成食物
CreateFood(ps);
}
void No_Food(pSnackNode pn, pSnack ps)
{
pn->next = ps->_psnack;
ps->_psnack = pn;
pSnackNode cur = ps->_psnack;
//打印出来五个了
color(10);
while (cur->next->next != NULL)
{
SetPos(cur->x, cur->y);
wprintf(L"%lc", Body);
cur = cur->next;
}
color(7);
//将第六个位置打印为空格
//释放第六个
SetPos(cur->next->x, cur->next->y);
printf(" ");
free(cur->next);
//再将倒数第二个的next为NULL
cur->next = NULL;
}
void Kill_By_Wall(pSnack ps)
{
if(ps->_psnack->x == 0 || ps->_psnack->x == 56 ||
ps->_psnack->y == 0 || ps->_psnack->y == 26)
{
ps->_status = KILL_BY_WALL;
}
}
void Kill_By_Self(pSnack ps)
{
pSnackNode cur = ps->_psnack -> next;
while (cur)
{
if (cur->x == ps->_psnack->x && cur->y == ps->_psnack->y)
{
ps->_status = KILL_BY_SELF;
break;
}
cur = cur->next;
}
}
void SnackMove(pSnack ps)
{
pSnackNode pNextNode = (pSnackNode)malloc(sizeof(SnackNode));
if (pNextNode == NULL)
{
perror("SnackMove::malloc fail");
return;
}
switch (ps->_dir)
{
case UP:
pNextNode->x = ps->_psnack->x;
pNextNode->y = ps->_psnack->y - 1;
break;
case DOWN:
pNextNode->x = ps->_psnack->x;
pNextNode->y = ps->_psnack->y + 1;
break;
case LEFT:
pNextNode->x = ps->_psnack->x - 2;
pNextNode->y = ps->_psnack->y;
break;
case RIGHT:
pNextNode->x = ps->_psnack->x + 2;
pNextNode->y = ps->_psnack->y;
break;
}
//下一个位置是食物
if (Next_Is_Food(pNextNode, ps))
{
Eat_Food(pNextNode,ps);
}
else
{
No_Food(pNextNode, ps);
}
//检测是否被撞墙死
Kill_By_Wall(ps);
//检测是否被撞自己死
Kill_By_Self(ps);
}
void GameRun(pSnack ps)
{
PrintHelpInfo();
//SetPos(64, 10);
do {
SetPos(64, 6);
wprintf(L"当前的总分数为:");
printf("%d ", ps->_sum_score);
SetPos(64, 8);
wprintf(L"当前单个食物分数为:");
printf("%d ", 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_OK;
}
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;
}
}
//实现蛇的移动
SnackMove(ps);
Sleep(ps->_sleep_time);
} while (ps->_status==OK);
//移动
//实施打印情况
}
void GameEnd(pSnack ps)
{
SetPos(24, 12);
switch (ps->_status)
{
case END_OK:
wprintf(L"您主动结束游戏\n");
break;
case KILL_BY_WALL:
wprintf(L"您撞到墙上,游戏结束\n");
break;
case KILL_BY_SELF:
wprintf(L"您撞到了自己,游戏结束\n");
break;
}
//释放蛇身的链表
pSnackNode cur = ps->_psnack;
while (cur)
{
pSnackNode del = cur;
cur = cur->next;
free(del);
}
}
test.c
#define _CRT_SECURE_NO_WARNINGS
#include"snack.h"
void test()
{
char ch;
do {
//创建贪吃蛇
Snack snack = { 0 };
GameStart(&snack);
//运行游戏
GameRun(&snack);
//结束游戏 - 善后工作
GameEnd(&snack);
SetPos(20, 15);
printf("再来一局吗?(Y/N):");
ch = getchar();
while (getchar() != '\n');
} while (ch == 'Y' || ch == 'y');
SetPos(0, 28);
}
int main()
{
srand((unsigned int)time(NULL));
setlocale(LC_ALL, "");
test();
return 0;
}
snack.h
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<windows.h>
#include<stdbool.h>
#include<stdlib.h>
#include <locale.h>
#include<time.h>
#include<errno.h>
#include<assert.h>
#define Wall L'□'
#define Body L'●'
#define Food L'★'
#define POS_X 24
#define POS_Y 5
//检查某个按键是否被按了
#define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )
//蛇的方向
enum DIRECTION
{
UP = 1,
DOWN,
LEFT,
RIGHT,
};
//蛇的状态
enum GAME_STATUS
{
OK,//正常
KILL_BY_WALL,
KILL_BY_SELF,
END_OK,
};
typedef struct SnackNode
{
int x;
int y;
//指向下一个结点
struct SnackNode* next;
}SnackNode, * pSnackNode;
typedef struct Snack
{
//蛇的头
pSnackNode _psnack;
pSnackNode _pfood;
enum DIRECTION _dir;
enum GAME_STATUS _status;
int _food_weight;//一个食物的分数
int _sum_score;//总成绩
int _sleep_time;//蛇的速度,越小越快
}Snack,*pSnack;
//定位光标
void SetPos(int x, int y);
//游戏开始
void GameStart(pSnack ps);
//欢迎界面
void Welcome_game();
//绘制地图
void CreatMap();
//打印提示操作信息
void PrintHelpInfo();
//创建蛇
void CreateSnack(pSnack ps);
//创建食物
void CreateFood(pSnack ps);
//游戏暂停
void Pause();
//游戏正常运行
void GameRun(pSnack ps);
//贪吃蛇的移动
void SnackMove(pSnack ps);
//检查下一个坐标位置是否为食物
bool Next_Is_Food(pSnackNode pn,pSnack ps);
//吃食物
void Eat_Food(pSnackNode pn, pSnack ps);
//下一个位置不是食物,进行移动
void No_Food(pSnackNode pn, pSnack ps);
//检测是否被撞墙死
void Kill_By_Wall(pSnack ps);
//检测是否被撞自己死
void Kill_By_Self(pSnack ps);
//正常的游戏结束
void GameEnd(pSnack ps);
控制台程序的准备:
需要运用到API
本游戏运行的时候需要用到控制台主机,而不是终端,对应的修改步骤如下:
控制台程序名字修改:
把名字改为贪吃蛇,会更好,那么修改方式如下:
参考:mode命令(mode | Microsoft Learn)
system("title 贪吃蛇");
游戏框架构建:
首先定义游戏界面的大小,定义游戏区行数和列数。
平常我们运⾏起来的黑框程序其实就是控制台程序 我们可以使用cmd命令来设置控制台窗⼝的⻓宽:设置控制台窗⼝的大小,100行,30列
system("mode con cols=100 lines=30");
此外,我们还需要结构体用于表示蛇与食物的结点信息。
typedef struct SnackNode
{
int x;
int y;
//指向下一个结点
struct SnackNode* next;
}SnackNode, * pSnackNode;
此外还有存放游戏蛇的信息与各个游戏相关信息,也需要用结构体封装起来存放:
typedef struct Snack
{
//蛇的头
pSnackNode _psnack;
pSnackNode _pfood;
enum DIRECTION _dir;
enum GAME_STATUS _status;
int _food_weight;//一个食物的分数
int _sum_score;//总成绩
int _sleep_time;//蛇的速度,越小越快
}Snack,*pSnack;
同样也需要存放蛇的状态,比如正常,撞墙死亡,撞自己死亡。
//蛇的状态
enum GAME_STATUS
{
OK,//正常
KILL_BY_WALL,
KILL_BY_SELF,
END_OK,
};
同样蛇的运行方向也需要用一个枚举来存放:
为了增加可读性,我们使用一个数字来定义方向,如向上为1;
//蛇的方向
enum DIRECTION
{
UP = 1,
DOWN,
LEFT,
RIGHT,
};
控制台屏幕上的坐标COORD:
COORD是WindowsAPI中定义的⼀个结构体,表⽰⼀个字符在控制台屏幕幕缓冲区上的坐标,坐标系 (0,0)的原点位于缓冲区的顶部左侧单元格。
隐藏光标:
隐藏光标比较简单,是运用到WIN 32 API,先通过etConsoleCursorInfo(hOutput, &CursorInfo);获取控制台光标信息,再隐藏控制台光标,设置控制台光标状态;
void cursor_hide()
{
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
CursorInfo.bVisible = false; //隐藏控制台光标
SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态
}
光标跳转
光标跳转,也就是让光标跳转到获得标准输出设备的句柄,与隐藏光标的操作步骤类似,然后定位光标的位置,跳转到指定位置:
void SetPos(int x,int y)
{
//获得标准输出设备的句柄
HANDLE hOutput = NULL;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
//定位光标的位置,到pos
COORD pos = { x,y };
SetConsoleCursorPosition(hOutput, pos);
}
打印颜色设置:
颜色设置函数的作用是,将此后输出的内容颜色都更为所指定的颜色,接收的参数c是颜色代码,十进制颜色代码表如下:
void color(int c)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c); //颜色设置
//注:SetConsoleTextAttribute是一个API(应用程序编程接口)
}
初始化界面:
第一步就为打印地图:
需要注意的地方就是:
- 在cmd窗口中一个小方块占两个单位的横坐标,一个单位的纵坐标。我们的墙使用宽字符进行对应的填充,
- 光标跳转函数SetPos接收的是光标将要跳至位置的横纵坐标。
例如第一次的坐标就为 (i,j) 那么下一次坐标就为(i+2,j);
宽字符打印准备:
1:需要引头文件:
#include <locale.h>
2:修改当前地区
setlocale(LC_ALL, "");
3:对应的字符
#define Wall L'□' #define Body L'●' #define Food L'★'
我设置的墙的颜色为红色,可以根据自己喜欢,自己根据上面的图给出的颜色进行调整。
void CreatMap()
{
color(12);
//上
for (int i = 0; i < 29; i++)
{
wprintf(L"%lc", L'□');
}
//下
SetPos(0, 26);
for (int i = 0; i < 29; i++)
{
wprintf(L"%lc", L'□');
}
//左
for (int i = 1; i <= 25; i++)
{
SetPos(0, i);
wprintf(L"%lc", L'□');
}
//右
for (int i = 1; i <= 25; i++)
{
SetPos(56, i);
wprintf(L"%lc", L'□');
}
color(7);
}
初始化蛇与蛇的打印:
我默认开始蛇身加上蛇头一共五个结点大小:
最一开始蛇的坐标:
#define POS_X 24
#define POS_Y 5
我们的蛇是运用结构体,并运用的单链表来创造,那么我们打印只需要遍历就可以,还是比较简单的
初始化的代码如下:(蛇的颜色我设置的是绿色)
void CreateSnack(pSnack ps)
{
color(10);
//默认开始初始化为5个结点
pSnackNode cur = NULL;
for (int i = 0; i < 5; i++)
{
cur =(pSnackNode)malloc(sizeof(SnackNode));
cur->next = NULL;
cur->x = POS_X + i * 2;
cur->y = POS_Y;
if (ps->_psnack == NULL)//第一次头插
{
ps->_psnack = cur;
}
else
{
cur->next = ps->_psnack;
ps->_psnack = cur;
}
}
while (cur)
{
SetPos(cur->x, cur->y);
wprintf(L"%lc", Body);
cur = cur->next;
}
cur= ps->_psnack;
//设置蛇的相关信息
ps->_dir = RIGHT;
ps->_food_weight = 10;
ps->_sleep_time = 200;
ps->_status = OK;
color(7);
}
随机创建食物:
随机在游戏区生成食物,需要对生成后的坐标进行判断,只有该位置为空才能在此生成食物,否则需要重新生成坐标。食物坐标确定后,需要对游戏区该位置的状态进行标记。
食物我设置的是紫色。可以根据自己爱好,设置自己喜欢的颜色。
void CreateFood(pSnack ps)
{
int x = 0;//2-54
int y = 0;//1-25
again:
do{
x = rand() % 53 + 2;
y = rand() % 24 + 1;
} while (x%2!=0);
//检测改坐标是否与蛇身重合
pSnackNode cur = ps->_psnack;
while (cur)
{
if (cur->x == x && cur->y == y)
{
goto again;
}
cur = cur->next;
}
pSnackNode SnackFood = (pSnackNode)malloc(sizeof(SnackNode));
if (SnackFood == NULL)
{
perror("CreateFood malloc fail");
return;
}
color(13);
SnackFood->x = x;
SnackFood->y = y;
SnackFood->next = NULL;
SetPos(x, y);
wprintf(L"%lc", Food);
ps->_pfood = SnackFood;
color(7);
}
蛇的单向移动:
移动蛇函数的作用就是先覆盖当前所显示的蛇,然后再打印移动后的蛇。
对应蛇尾的位置打印变为空格并删除一次蛇尾,然后再次创建一个新的蛇头,更换蛇头
void SnackMove(pSnack ps)
{
pSnackNode pNextNode = (pSnackNode)malloc(sizeof(SnackNode));
if (pNextNode == NULL)
{
perror("SnackMove::malloc fail");
return;
}
pNextNode->x = ps->_psnack->x + 2;
pNextNode->y = ps->_psnack->y;
pn->next = ps->_psnack;
ps->_psnack = pn;
pSnackNode cur = ps->_psnack;
//打印出来五个了
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(" ");
}
大致小部分已经实现完成,那么就利用游戏逻辑来实现剩余的代码;
在玩贪吃蛇的时候,我们知道
在蛇的移动过程,我们可以通过按键修改蛇的移动方向,来进行转弯,而且在移动的过程中,我们还可以随时改变速度,来改变游戏的难度,来增加游戏的可玩性,在行动的过程中,不免会撞墙,撞自己,吃到了食物,没有吃到食物,等等各种不同的情况,那么 对于实现的逻辑就是如上:
那么我先修改蛇的移动使其可以更换方向
在修改蛇的方向前,我们知道我们是通过按键来改变,那么我们就需要通过某种方法得知我们按了什么键来进行修改方向,同样也是API的知识
//检查某个按键是否被按了
#define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 )
添加方向的改变与判断蛇的各个状态判断:
bool Next_Is_Food(pSnackNode pn, pSnack ps)
{
return (ps->_pfood->x == pn->x && ps->_pfood->y == pn->y);
}
void SnackMove(pSnack ps)
{
pSnackNode pNextNode = (pSnackNode)malloc(sizeof(SnackNode));
if (pNextNode == NULL)
{
perror("SnackMove::malloc fail");
return;
}
switch (ps->_dir)
{
case UP:
pNextNode->x = ps->_psnack->x;
pNextNode->y = ps->_psnack->y - 1;
break;
case DOWN:
pNextNode->x = ps->_psnack->x;
pNextNode->y = ps->_psnack->y + 1;
break;
case LEFT:
pNextNode->x = ps->_psnack->x - 2;
pNextNode->y = ps->_psnack->y;
break;
case RIGHT:
pNextNode->x = ps->_psnack->x + 2;
pNextNode->y = ps->_psnack->y;
break;
}
//下一个位置是食物
if (Next_Is_Food(pNextNode, ps))
{
Eat_Food(pNextNode,ps);
}
else
{
No_Food(pNextNode, ps);
}
//检测是否被撞墙死
Kill_By_Wall(ps);
//检测是否被撞自己死
Kill_By_Self(ps);
}
对该函数里面各个小函数进行代码展示:
这里面的小函数都是比较好实现的,这里就不在解释:
Eat_Food(pNextNode,ps);
需要注意的是吃完这个食物后,要记得重新随机创建食物
void Eat_Food(pSnackNode pn, pSnack ps)
{
ps->_pfood->next = ps->_psnack;
ps->_psnack = ps->_pfood;
free(pn);
pn = NULL;
pSnackNode cur = ps->_psnack;
color(10);
while (cur)
{
SetPos(cur->x, cur->y);
wprintf(L"%lc", Body);
cur = cur->next;
}
color(7);
ps->_sum_score += ps->_food_weight;
//在重新生成食物
CreateFood(ps);
}
void No_Food(pSnackNode pn, pSnack ps)
要记得把尾打印改为空格
void No_Food(pSnackNode pn, pSnack ps)
{
pn->next = ps->_psnack;
ps->_psnack = pn;
pSnackNode cur = ps->_psnack;
//打印出来五个了
color(10);
while (cur->next->next != NULL)
{
SetPos(cur->x, cur->y);
wprintf(L"%lc", Body);
cur = cur->next;
}
color(7);
//将第六个位置打印为空格
//释放第六个
SetPos(cur->next->x, cur->next->y);
printf(" ");
free(cur->next);
//再将倒数第二个的next为NULL
cur->next = NULL;
}
void Kill_By_Wall(pSnack ps)
void Kill_By_Wall(pSnack ps)
{
if(ps->_psnack->x == 0 || ps->_psnack->x == 56 ||
ps->_psnack->y == 0 || ps->_psnack->y == 26)
{
ps->_status = KILL_BY_WALL;
}
}
void Kill_By_Self(pSnack ps)
void Kill_By_Self(pSnack ps)
{
pSnackNode cur = ps->_psnack -> next;
while (cur)
{
if (cur->x == ps->_psnack->x && cur->y == ps->_psnack->y)
{
ps->_status = KILL_BY_SELF;
break;
}
cur = cur->next;
}
}
最后,还有对应的就是运行是代码的逻辑展示
void GameRun(pSnack ps)
{
//SetPos(64, 10);
do {
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_OK;
}
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;
}
}
//实现蛇的移动
SnackMove(ps);
Sleep(ps->_sleep_time);
} while (ps->_status==OK);
//移动
//实施打印情况
}
速度的控制(单位毫秒):
void Pause()
{
while (1)
{
Sleep(200);
if (KEY_PRESS(VK_SPACE))
{
break;
}
}
}
最后的游戏收尾就是提示信息的打印:
void GameEnd(pSnack ps)
{
SetPos(24, 12);
switch (ps->_status)
{
case END_OK:
wprintf(L"您主动结束游戏\n");
break;
case KILL_BY_WALL:
wprintf(L"您撞到墙上,游戏结束\n");
break;
case KILL_BY_SELF:
wprintf(L"您撞到了自己,游戏结束\n");
break;
}
//释放蛇身的链表
pSnackNode cur = ps->_psnack;
while (cur)
{
pSnackNode del = cur;
cur = cur->next;
free(del);
}
}
最后一步便是锦上添花了,就是打印提示信息:
void PrintHelpInfo()
{
color(15);
SetPos(64, 10);
wprintf(L"不能穿墙,不能咬到自己");
SetPos(64, 12);
wprintf(L"用 ↑.↓.←.→ 来控制蛇的移动");
SetPos(64, 14);
wprintf(L"按F3加速,F4减速");
SetPos(64, 16);
wprintf(L"按ESC正常退出游戏,按空格暂停游戏");
SetPos(64, 18);
wprintf(L"能力有限公司提供支持");
SetPos(0, 29);
// system("pause");
color(7);
}
与