贪吃蛇(下)游戏的实现
感谢大佬的光临各位,希望和大家一起进步,望得到你的三连,互三支持,一起进步
个人主页:LaNzikinh-CSDN博客
文章目录
- 前言
- 一.蛇和食物的打印
- 二.游戏的运行逻辑
- 三.结束游戏 (善后工作)
- 四.游戏的测试逻辑
- 总结
- 总代码
前言
我们前面讲解Win API的知识和贪吃蛇初始化和地图的绘制,这次来完结贪吃蛇,把他项目实现讲解
shack - Microsoft Visual Studio 2024-05-05 12-56-52
一.蛇和食物的打印
我们前面讲了关于地图的绘制,在实现项目之前,我们还需要把蛇和食物也打印下来
首先我肯定是要先创建一个贪吃蛇的结构体变量,然后我要初始化游戏设置游戏的相关信息,运行游戏最后就是结束工作以及善后
void test()
{int ch = 0;do{system("cls");//创建贪吃蛇Snake snake = { 0 };//初始化游戏//1. 打印环境界面//2. 功能介绍//3. 绘制地图//4. 创建蛇//5. 创建食物//6. 设置游戏的相关信息GameStart(&snake);//运行游戏GameRun(&snake);//结束游戏 - 善后工作GameEnd(&snake);} while ();}
关于初始化游戏前面,我们只定义了贪吃蛇需要的一些初始化变量,还有绘制的地图,介绍了游戏和功能,我们还剩了一些创建蛇和创建食物的功能,所以我们先来写一个初始化游戏的函数,利用前面所学的Win API知识,我没有将光标先隐藏了之后再设置
void GameStart(pSnake ps)
{//0. 先设置窗口的大小,再光标隐藏system("mode con cols=100 lines=30");system("title 贪吃蛇");HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);//影藏光标操作CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(houtput, &CursorInfo);//获取控制台光标信息CursorInfo.bVisible = false; //隐藏控制台光标SetConsoleCursorInfo(houtput, &CursorInfo);//设置控制台光标状态//1. 打印环境界面和功能介绍WelcomeToGame();//2. 绘制地图CreateMap();//3. 创建蛇InitSnake(ps);//4. 创建食物CreateFood(ps);
}
然后我们现在来创建蛇和食物
蛇的创建
初始化蛇身,我首先肯定要传一个贪吃蛇的结构体来,初始化的蛇,我定义的是五个节点位于控制台的中间,所以我就创造五个节点,再将每个节点中的坐标负值利用头插法插入再把它们打印下来就可以了,结束的时候再设置一下当前初始情况下贪吃蛇的默认属性
void InitSnake(pSnake ps)
{int i = 0;pSnakeNode cur = NULL;for (i = 0; i < 5; i++){cur = (pSnakeNode)malloc(sizeof(SnakeNode));/*if (cur == NULL){perror("InitSnake()::malloc()");return;}*/assert(cur);cur->next = NULL;cur->x = POS_X + 2 * i;cur->y = POS_Y;//头插法插入链表if (ps->_pSnake == NULL) //空链表{ps->_pSnake = cur;}else //非空{cur->next = ps->_pSnake;ps->_pSnake = cur;}}cur = ps->_pSnake;while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}//设置贪吃蛇的属性ps->_dir = RIGHT;//默认向右ps->_score = 0;ps->_food_weight = 10;ps->_sleep_time = 200;//单位是毫秒ps->_status = OK;}
注意贪吃蛇是插入是这样插的!!
查找完之后,我们来创建食物食物的创建肯定是要生成随机数,我们在很久之前的数字游戏中已经了解到了随机数是如何生成的,但是在这里的随机数要注意2点第一点就是食物,首先肯定不能越出墙外也不可能和蛇的身体冲突,然后就是坐标的差异,横的是竖的两倍,所以X +2,Y +1
#include<time.h>,srand((unsigned int)time(NULL));随机数
void CreateFood(pSnake ps)
{int x = 0;int y = 0;//生成x是2的倍数//x:2~54//y: 1~25
again:do{x = rand() % 53 + 2;y = rand() % 25 + 1;} while (x % 2 != 0);//x和y的坐标不能和蛇的身体坐标冲突pSnakeNode cur = ps->_pSnake;while (cur){if (x == cur->x && y == cur->y){goto again;}cur = cur->next;}//创建食物的节点pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));/*if (pFood == NULL){perror("CreateFood()::malloc()");return;}*/assert(pFood);pFood->x = x;pFood->y = y;pFood->next = NULL;SetPos(x, y);//定位位置wprintf(L"%lc", FOOD);ps->_pFood = pFood;
}
二.游戏的运行逻辑
我们现在进行的是游戏的运行逻辑,首先我们肯定要跟上面一样写一个总的运行逻辑,然后再不断地完成他的分支,在游戏开始的时候,我们肯定要先打印一个帮助信息来记录分数,还有一些规则的提醒,然后就是一些按键的规则,如果你按上的时候要有反应的话,那么目前蛇就不能往下走,剩下左右都是这个道理,那如何判断我之前按的什么键呢?就有我们之前讲的Win API的知识(#define KEY_PRESS(vk) ((GetAsyncKeyState(vk)&1)?1:0)),那个宏定义,规定完按键之后呢,就是蛇走一步的过程,我们在游戏运行的时候蛇必须动,然后蛇没走一步之后还有休息,这样子才能看到蛇移动的过程,游戏用do while循环来实现判断条件就是状态,只要是正常就可以一直继续
void GameRun(pSnake ps)
{//打印帮助信息PrintHelpInfo();do{//打印总分数和食物的分值SetPos(64, 10);printf("总分数:%d\n", ps->_score);SetPos(64, 11);printf("当前食物的分数:%2d\n", 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)){//加速}else if (KEY_PRESS(VK_F4)){//减速}SnakeMove(ps);//蛇走一步的过程Sleep(ps->_sleep_time);} while (ps->_status == OK);
}
然后现在我们先来打印一下帮助信息
打印帮助信息
void PrintHelpInfo()
{SetPos(64, 14);wprintf(L"%ls", L"不能穿墙,不能咬到自己");SetPos(64, 15);wprintf(L"%ls", L"用 ↑. ↓ . ← . → 来控制蛇的移动");SetPos(64, 16);wprintf(L"%ls", L"按F3加速,F4减速");SetPos(64, 17);wprintf(L"%ls", L"按ESC退出游戏,按空格暂停游戏");}
注意:这些坐标不是用眼睛看出来的,是通过不断地尝试和严格的定义定位到的,自己写的时候不要直接照抄坐标,要自己去尝试!!!!
然后上面其实还有一些功能,就是加速减速功能的实现,以及暂停退出游戏的实现
暂停和退出游戏
退出游戏很简单,把状态改为退出就可以了,暂停的话就直接让他不断地睡眠就可以了
void Pause()
{while (1){Sleep(200);//如果点了接触暂停就退出if (KEY_PRESS(VK_SPACE)){break;}}
}
加速减速功能
我们前面定义蛇的时候说了,休息时间,时间越短,速度越快,时间越长,速度越慢
如果你点了F3就加速,如果你点了F4就减速加速的话,就是让睡眠时间减少,然后分数增加减速的话同理,但是你不能一直加速,所以我要规定减到80就不减了,减速也是一样,食物分数肯定不能减到零
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;}
}
蛇走一步的过程
最复杂的就是蛇走一步的过程,他又要分好几点,很多项目就是这样子的,就是分岔路口一样,一个实现又需要好多个节点,就像一棵树
然后我们来看看蛇走一步需要干什么,我们要创造一个节点,表示即将到的下一个节点,贪吃蛇移动的思想,注意:他并不是五个节点往前移动,而是增加前面节点销毁后面那个节点,所以我先用一个选择语句来看我的方向,如果向上走就往上移,向下走就往下移,注意:坐标关系,然后我就要判断是否遇到食物,如果遇到的的话怎么样没有遇到怎么样,然后还要判断退出条件,我是撞墙了还是撞到自己了
void SnakeMove(pSnake ps)
{//创建一个结点,表示蛇即将到的下一个节点pSnakeNode pNextNode = (pSnakeNode)malloc(sizeof(SnakeNode));if (pNextNode == NULL){perror("SnakeMove()::malloc()");return;}switch (ps->_dir){case UP:pNextNode->x = ps->_pSnake->x;pNextNode->y = ps->_pSnake->y - 1;break;case DOWN:pNextNode->x = ps->_pSnake->x;pNextNode->y = ps->_pSnake->y + 1;break;case LEFT:pNextNode->x = ps->_pSnake->x - 2;pNextNode->y = ps->_pSnake->y;break;case RIGHT:pNextNode->x = ps->_pSnake->x + 2;pNextNode->y = ps->_pSnake->y;break;}//检测下一个坐标处是否是食物if (NextIsFood(pNextNode, ps)){EatFood(pNextNode, ps);}else{NoFood(pNextNode, ps);}//检测蛇是否撞墙KillByWall(ps);//检测蛇是否撞到自己KillBySelf(ps);
}
判断下一个坐标是不是食物
int NextIsFood(pSnakeNode pn, pSnake ps)
{return (ps->_pFood->x == pn->x && ps->_pFood->y == pn->y);
}
是食物
如果是食物的话,我就继续用头插法将食物变成贪吃蛇的节点,然后我要释放原来的食物节点,然后再重新把蛇打印出来就可以了,最后在次创建食物
void EatFood(pSnakeNode pn, pSnake ps)
{//头插法ps->_pFood->next = ps->_pSnake;ps->_pSnake = ps->_pFood;//释放下一个位置的节点free(pn);pn = NULL;pSnakeNode cur = ps->_pSnake;//打印蛇while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}ps->_score += ps->_food_weight;//重新创建食物CreateFood(ps);
}
不是食物
如果不是食物的话,我们把下一个节点头插到蛇上,然后找到最后一个节点是放掉,并且把最后一个节点打印成空格再把倒数第二个节点指为空
void NoFood(pSnakeNode pn, pSnake ps)
{//头插法pn->next = ps->_pSnake;ps->_pSnake = pn;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);//把倒数第二个节点的地址置为NULLcur->next = NULL;
}
检测蛇是否撞墙
下一个节点坐标不能等于墙坐标,如果等于的话就把状态改为out
void KillByWall(pSnake ps)
{if (ps->_pSnake->x == 0 || ps->_pSnake->x == 56 ||ps->_pSnake->y == 0 || ps->_pSnake->y == 26){ps->_status = KILL_BY_WALL;}
}
检测蛇是否撞到自己
撞到自己也是同理的,下一个坐标不能等于自己的坐标
void KillBySelf(pSnake ps)
{pSnakeNode cur = ps->_pSnake->next;while (cur){if (cur->x == ps->_pSnake->x && cur->y == ps->_pSnake->y){ps->_status = KILL_BY_SELF;break;}cur = cur->next;}
}
三.结束游戏 (善后工作)
这个也是最轻松的结束游戏善后工作了,状态的判断,我们前面写了很多种退出游戏的状态,接下来就依依的收尾了,根据每个退出状态写出对应的状态就可以了,然后再把蛇身的所有列表释放就结束了
void GameEnd(pSnake ps)
{SetPos(24, 12);switch (ps->_status){case END_NORMAL:wprintf(L"您主动结束游戏\n");break;case KILL_BY_WALL:wprintf(L"您撞到墙上,游戏结束\n");break;case KILL_BY_SELF:wprintf(L"您撞到了自己,游戏结束\n");break;}//释放蛇身的链表pSnakeNode cur = ps->_pSnake;while (cur){pSnakeNode del = cur;cur = cur->next;free(del);}
}
四.游戏的测试逻辑
因为你结束了之后可能还要再玩一局,如果你要玩的话就输入Y,不玩的话就输入N,字符获取函数来接收一下。这个在总逻辑上改
void test()
{int ch = 0;do{system("cls");//创建贪吃蛇Snake snake = { 0 };//初始化游戏//1. 打印环境界面//2. 功能介绍//3. 绘制地图//4. 创建蛇//5. 创建食物//6. 设置游戏的相关信息GameStart(&snake);//运行游戏GameRun(&snake);//结束游戏 - 善后工作GameEnd(&snake);SetPos(20, 15);printf("再来一局吗?(Y/N):");ch = getchar(); } while (ch == 'Y' || ch == 'y');SetPos(0, 27);
}
总结
贪吃蛇游戏把C语言学过的很多知识都全部运用上了,甚至还讲起了一些设置台控制的一些知识,完整的写出来还是能收获到不少的东西的
总代码
shack.h#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <windows.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include<assert.h>#define POS_X 24
#define POS_Y 5#define WALL L'□'
#define BODY L'●'
#define FOOD L'★'//类型的声明//蛇的方向
enum DIRECTION
{UP = 1,DOWN,LEFT,RIGHT
};//蛇的状态
//正常、撞墙、撞到自己、正常退出
enum GAME_STATUS
{OK, //正常KILL_BY_WALL, //撞墙KILL_BY_SELF, //撞到自己END_NORMAL //正常退出
};//蛇身的节点类型
typedef struct SnakeNode
{//坐标int x;int y;//指向下一个节点的指针struct SnakeNode* next;
}SnakeNode, * pSnakeNode;//typedef struct SnakeNode* pSnakeNode;//贪吃蛇
typedef struct Snake
{pSnakeNode _pSnake;//指向蛇头的指针pSnakeNode _pFood;//指向食物节点的指针enum DIRECTION _dir;//蛇的方向enum GAME_STATUS _status;//游戏的状态int _food_weight;//一个食物的分数int _score; //总成绩int _sleep_time; //休息时间,时间越短,速度越快,时间越长,速度越慢
}Snake, * pSnake;//函数的声明//定位光标位置
void SetPos(short x, short y);//游戏的初始化
void GameStart(pSnake ps);//欢迎界面的打印
void WelcomeToGame();//创建地图
void CreateMap();//初始化蛇身
void InitSnake(pSnake ps);//创建食物
void CreateFood(pSnake ps);//游戏运行的逻辑
void GameRun(pSnake ps);//蛇的移动-走一步
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);//游戏善后的工作
void GameEnd(pSnake ps);shack.c#define _CRT_SECURE_NO_WARNINGS 1
#include "shack.h"
void SetPos(short x, short y)
{//获得标准输出设备的句柄HANDLE houtput = NULL;houtput = GetStdHandle(STD_OUTPUT_HANDLE);//定位光标的位置COORD pos = { x, y };SetConsoleCursorPosition(houtput, pos);
}void WelcomeToGame()
{SetPos(40, 14);wprintf(L"欢迎来到贪吃蛇小游戏\n");SetPos(42, 20);system("pause");system("cls");SetPos(25, 14);wprintf(L"用 ↑. ↓ . ← . → 来控制蛇的移动,按F3加速,F4减速\n");SetPos(25, 15);wprintf(L"加速能够得到更高的分数\n");SetPos(42, 20);system("pause");system("cls");
}void CreateMap()
{//上int i = 0;for (i = 0; i < 29; i++){wprintf(L"%lc ", WALL);}//下SetPos(0, 26);for (i = 0; i < 29; i++){wprintf(L"%lc ", WALL);}//左for (i = 1; i <= 25; i++){SetPos(0, i);wprintf(L"%lc", WALL);}//右for (i = 1; i <= 25; i++){SetPos(56, i);wprintf(L"%lc", WALL);}}void InitSnake(pSnake ps)
{int i = 0;pSnakeNode cur = NULL;for (i = 0; i < 5; i++){cur = (pSnakeNode)malloc(sizeof(SnakeNode));/*if (cur == NULL){perror("InitSnake()::malloc()");return;}*/assert(cur);cur->next = NULL;cur->x = POS_X + 2 * i;cur->y = POS_Y;//头插法插入链表if (ps->_pSnake == NULL) //空链表{ps->_pSnake = cur;}else //非空{cur->next = ps->_pSnake;ps->_pSnake = cur;}}cur = ps->_pSnake;while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}//设置贪吃蛇的属性ps->_dir = RIGHT;//默认向右ps->_score = 0;ps->_food_weight = 10;ps->_sleep_time = 200;//单位是毫秒ps->_status = OK;}void CreateFood(pSnake ps)
{int x = 0;int y = 0;//生成x是2的倍数//x:2~54//y: 1~25
again:do{x = rand() % 53 + 2;y = rand() % 25 + 1;} while (x % 2 != 0);//x和y的坐标不能和蛇的身体坐标冲突pSnakeNode cur = ps->_pSnake;while (cur){if (x == cur->x && y == cur->y){goto again;}cur = cur->next;}//创建食物的节点pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));/*if (pFood == NULL){perror("CreateFood()::malloc()");return;}*/assert(pFood);pFood->x = x;pFood->y = y;pFood->next = NULL;SetPos(x, y);//定位位置wprintf(L"%lc", FOOD);ps->_pFood = pFood;
}void GameStart(pSnake ps)
{//0. 先设置窗口的大小,再光标隐藏system("mode con cols=100 lines=30");system("title 贪吃蛇");HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);//影藏光标操作CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(houtput, &CursorInfo);//获取控制台光标信息CursorInfo.bVisible = false; //隐藏控制台光标SetConsoleCursorInfo(houtput, &CursorInfo);//设置控制台光标状态//1. 打印环境界面和功能介绍WelcomeToGame();//2. 绘制地图CreateMap();//3. 创建蛇InitSnake(ps);//4. 创建食物CreateFood(ps);
}void PrintHelpInfo()
{SetPos(64, 14);wprintf(L"%ls", L"不能穿墙,不能咬到自己");SetPos(64, 15);wprintf(L"%ls", L"用 ↑. ↓ . ← . → 来控制蛇的移动");SetPos(64, 16);wprintf(L"%ls", L"按F3加速,F4减速");SetPos(64, 17);wprintf(L"%ls", L"按ESC退出游戏,按空格暂停游戏");}#define KEY_PRESS(vk) ((GetAsyncKeyState(vk)&1)?1:0)void Pause()
{while (1){Sleep(200);if (KEY_PRESS(VK_SPACE)){break;}}
}//int NextIsFood(pSnakeNode pn, pSnake ps)
//{
// if (ps->_pFood->x == pn->x && ps->_pFood->y == pn->y)
// return 1;
// else
// return 0;
//}int NextIsFood(pSnakeNode pn, pSnake ps)
{return (ps->_pFood->x == pn->x && ps->_pFood->y == pn->y);
}void EatFood(pSnakeNode pn, pSnake ps)
{//头插法ps->_pFood->next = ps->_pSnake;ps->_pSnake = ps->_pFood;//释放下一个位置的节点free(pn);pn = NULL;pSnakeNode cur = ps->_pSnake;//打印蛇while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}ps->_score += ps->_food_weight;//重新创建食物CreateFood(ps);
}void NoFood(pSnakeNode pn, pSnake ps)
{//头插法pn->next = ps->_pSnake;ps->_pSnake = pn;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);//把倒数第二个节点的地址置为NULLcur->next = NULL;
}void KillByWall(pSnake ps)
{if (ps->_pSnake->x == 0 || ps->_pSnake->x == 56 ||ps->_pSnake->y == 0 || ps->_pSnake->y == 26){ps->_status = KILL_BY_WALL;}
}void KillBySelf(pSnake ps)
{pSnakeNode cur = ps->_pSnake->next;while (cur){if (cur->x == ps->_pSnake->x && cur->y == ps->_pSnake->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()");return;}switch (ps->_dir){case UP:pNextNode->x = ps->_pSnake->x;pNextNode->y = ps->_pSnake->y - 1;break;case DOWN:pNextNode->x = ps->_pSnake->x;pNextNode->y = ps->_pSnake->y + 1;break;case LEFT:pNextNode->x = ps->_pSnake->x - 2;pNextNode->y = ps->_pSnake->y;break;case RIGHT:pNextNode->x = ps->_pSnake->x + 2;pNextNode->y = ps->_pSnake->y;break;}//检测下一个坐标处是否是食物if (NextIsFood(pNextNode, ps)){EatFood(pNextNode, ps);}else{NoFood(pNextNode, ps);}//检测蛇是否撞墙KillByWall(ps);//检测蛇是否撞到自己KillBySelf(ps);
}void GameRun(pSnake ps)
{//打印帮助信息PrintHelpInfo();do{//打印总分数和食物的分值SetPos(64, 10);printf("总分数:%d\n", ps->_score);SetPos(64, 11);printf("当前食物的分数:%2d\n", 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);
}void GameEnd(pSnake ps)
{SetPos(24, 12);switch (ps->_status){case END_NORMAL:wprintf(L"您主动结束游戏\n");break;case KILL_BY_WALL:wprintf(L"您撞到墙上,游戏结束\n");break;case KILL_BY_SELF:wprintf(L"您撞到了自己,游戏结束\n");break;}//释放蛇身的链表pSnakeNode cur = ps->_pSnake;while (cur){pSnakeNode del = cur;cur = cur->next;free(del);}
}test.c#include <locale.h>
#include "shack.h"
#define _CRT_SECURE_NO_WARNINGS 1
//完成的是游戏的测试逻辑
void test()
{int ch = 0;do{system("cls");//创建贪吃蛇Snake snake = { 0 };//初始化游戏//1. 打印环境界面//2. 功能介绍//3. 绘制地图//4. 创建蛇//5. 创建食物//6. 设置游戏的相关信息GameStart(&snake);//运行游戏GameRun(&snake);//结束游戏 - 善后工作GameEnd(&snake);SetPos(20, 15);printf("再来一局吗?(Y/N):");ch = getchar(); } while (ch == 'Y' || ch == 'y');SetPos(0, 27);
}int main()
{//设置适配本地环境setlocale(LC_ALL, "");srand((unsigned int)time(NULL));test();return 0;
}
相关文章:
贪吃蛇(下)游戏的实现
感谢大佬的光临各位,希望和大家一起进步,望得到你的三连,互三支持,一起进步 个人主页:LaNzikinh-CSDN博客 文章目录 前言一.蛇和食物的打印二.游戏的运行逻辑三.结束游戏 (善后工作)四.游戏的测…...
偏微分方程算法之椭圆型方程差分格式编程示例
目录 一、示例1-五点菱形格式 1.1 C代码 1.2 计算结果 二、示例2-九点紧差分格式 2.1 C代码 2.2 计算结果 三、示例3-二阶混合边值 3.1 C代码 3.2 计算结果 本专栏对椭圆型偏微分方程的三种主要差分方法进行了介绍,并给出相应格式的理论推导过程。为加深对…...
PCIe协议之-TLP路由基础
✨前言: 在PCI Express (PCIe) 技术中,数据包的路由方式对于确保信息能够高效、准确地传送至目标设备至关重要。PCIe定义了几种路由方式,主要有以下几种。 🌟地址路由(Address Based Routing) 这是最基本…...
inline内联函数-虚函数(virtual)可以是内联函数(inline)吗?
目录标题 inline内联函数特征:使用:编译器对inline函数的处理步骤优点:缺点: 虚函数(virtual)可以是内联函数(inline)吗?特征:使用: inline内联函…...
Spring Boot | Spring Boot 消息管理 ( 消息中间件 ) 、RabbitMQ“消息中间件“
目录: 一、"消息服务" 概述 :1.1 为什么要使用 "消息服务" ( 消息中间件 ) ?① 异步处理② 应用解耦③ 流量削峰④ 分布式事务管理 1.2 常用 "消息中间件" 介绍 :ActiveMQ ( 广泛应用于中小型企业 )RabbitMQ ( 没有特别要求的场景下…...
二层交换机与路由器连通上网实验
华为二层交换机与路由器连通上网实验 二层交换机是一种网络设备,用于在局域网(LAN)中转发数据帧。它工作在OSI模型的第二层,即数据链路层。二层交换机通过学习和维护MAC地址表,实现了数据的快速转发和广播域的隔离。 实…...
AJAX知识点(前后端交互技术)
原生AJAX AJAX全称为Asynchronous JavaScript And XML,就是异步的JS和XML,通过AJAX可以在浏览器中向服务器发送异步请求,最大的优势:无需刷新就可获取数据。 AJAX不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式 …...
用wordpress为外贸进出口公司搭建多语言国际站
使用WordPress为外贸进出口公司搭建多语言国际站是一个很好的选择,因为WordPress不仅易于使用,而且具有丰富的插件和主题,可以支持多语言内容。以下是搭建多语言国际站的步骤和建议: 安装WordPress:首先,您…...
雷军-2022.8小米创业思考-6-互联网七字诀之口碑:口碑即定位,超预期才有口碑,品牌建设
第六章 互联网七字诀 专注、极致、口碑、快,这就是我总结的互联网七字诀,也是我对互联网思维的高度概括。 口碑 用户口碑是所有产品成功的关键因素,这是不言而喻的公理。 资源永远有限,对于创业公司尤其如此。只有专注…...
欧盟MDR法规对医疗器械网络安全都有哪些要求?
MDR,欧盟医疗器械法规(Medical Device REGULATION (EU) 2017/745,简称“MDR”),当医疗器械办理欧盟CE认证时,需满足新法规 MDR (EU) 2017/745要求。 M DR符合性评估 医械网络安全咨询与相关文件出具&#x…...
Linux —— 信号初识
Linux —— 信号初识 什么是信号测试几个信号signal函数函数原型参数说明返回值注意事项示例 后台程序前台转后台检测输入中断向量表 我们今天来继续学习Linux的内容,今天我们要了解的是Linux操作系统中的信号: 什么是信号 信号是操作系统内核与进程之…...
webpack进阶 -- 自定义Plugin,Loader封装打包优化
介绍 Webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。在 Webpack 处理应用程序时,它会在内部构建一个依赖图(dependency graph),这个依赖图对应映射到项目所需的每个模块,并生成一个或多个 bundle。在这个过程中…...
《Decoupled Optimisation for Long-Tailed Visual Recognition》阅读笔记
论文标题 《Decoupled Optimisation for Long-Tailed Visual Recognition》 长尾视觉识别的解耦优化 作者 Cong Cong、Shiyu Xuan、Sidong Liu、Shiliang Zhang、Maurice Pagnucco 和 Yang Song、 来自新南威尔士大学计算机科学与工程学院、北京大学计算机学院多媒体信息处…...
Springboot+Vue项目-基于Java+MySQL的毕业就业信息管理系统(附源码+演示视频+LW)
大家好!我是程序猿老A,感谢您阅读本文,欢迎一键三连哦。 💞当前专栏:Java毕业设计 精彩专栏推荐👇🏻👇🏻👇🏻 🎀 Python毕业设计 &…...
条件平差——以水准网平差为例 (python详细过程版)
目录 一、原理概述二、案例分析三、代码实现四、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、原理概述 条件平差的函数模型和随机模型为: A V + W = 0...
mysql -- WITH RECURSIVE 语法
引言 在 SQL 中,WITH RECURSIVE 是一个用于创建递归查询的语句。它允许你定义一个 Common Table Expression (CTE),该 CTE 可以引用自身的输出。递归 CTE 非常适合于查询具有层次结构或树状结构的数据,例如组织结构、文件系统或任何其他具有…...
洗地机什么品牌好?洗地机怎么选?618洗地机选购指南
随着科技的飞速发展,洗地机以其高效的清洁能力、稳定的性能和用户友好的设计而闻名,不仅可以高效吸尘、拖地,还不用手动洗滚布,已经逐渐成为现代家庭不可或缺的清洁助手。然而,在众多品牌和型号中,如何选择…...
nginx负载均衡配置
1.nginx负载均衡配置 upstream lbs {server 192.168.1.12:8080;server 192.168.1.12:8081; }server {listen 80;server_name localhost a.com;#charset koi8-r;#access_log logs/host.access.log main;location / {root html;index index.html index.htm;}locatio…...
HarmonyOS NEXT星河版之美团外卖点餐功能实战(中)
接上 一、UI布局 1.1 购物车Item Preview Component export struct MTCartItemView {build() {Row({ space: 6 }) {Image(https://bkimg.cdn.bcebos.com/pic/4d086e061d950a7bc94a331704d162d9f3d3c9e2).width(42).aspectRatio(1).borderRadius(5)Column({ space: 3 }) {Text…...
CTF-Web Exploitation(持续更新)
CTF-Web Exploitation 1. GET aHEAD Find the flag being held on this server to get ahead of the competition Hints Check out tools like Burpsuite to modify your requests and look at the responses 根据提示使用不同的请求方式得到response可能会得到结果 使用…...
图书管理系统c语言
创建一个图书管理系统是一个涉及数据结构和文件操作的项目。在C语言中,你可以使用结构体来表示图书信息,使用函数来实现系统的各项功能。以下是一个简单的图书管理系统的示例,包括基本的添加、显示、查找和删除图书的功能。 1. 定义图书结构…...
森林消防—高扬程水泵,高效、稳定、可靠!/恒峰智慧科技
森林,作为地球的“绿色肺叶”,不仅为我们提供了丰富的自然资源,更是维持生态平衡的重要一环。然而,随着全球气候的变化和人为活动的增加,森林火灾频发,给生态环境和人民生命财产安全带来了巨大威胁。在森林…...
光伏设备制造5G智能工厂数字孪生可视化平台,推进行业数字化转型
光伏设备制造5G智能工厂数字孪生可视化平台,推进行业数字化转型。光伏设备制造5G智能工厂数字孪生可视化平台是光伏行业数字化转型的重要一环。通过数字孪生平台,光伏设备制造企业可以实现对生产过程的全面监控和智能管理,提高生产效率&#…...
【论文阅读笔记】TS2Vec: Towards Universal Representation of Time Series
【论文阅读笔记】TS2Vec: Towards Universal Representation of Time Series 摘要 这段文字介绍了一个名为TS2Vec的通用框架,用于学习时间序列数据的表示,可以在任意语义层次上进行。与现有方法不同,TS2Vec通过对增强的上下文视图进行层次化…...
windows驱动开发-DMA技术(一)
DMA(Direct Memory Access)是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依于 CPU 的大量中断负载,否则CPU 需要从设备缓存中把每一页的数据复制到缓存中,然后把它们再次写入到新的地方,在这个过…...
实用的Chrome命令
以下是一些实用的Chrome命令及其用途: --allow-outdated-plugins:允许浏览器使用过期的插件,这在开发过程中可能会用到,以便测试兼容性。chrome://downloads:打开Chrome的下载页面,查看和管理你的下载文件…...
数据库(MySQL)基础:约束
一、概述 1.概念:约束是作用于表中字段上的规则,用于限制存储在表中的数据。 2.目的:保证数据库中数据的正确、有效性和完整性。 3.分类 约束描述关键字非空约束限制该字段的数据不能为nullnot null唯一约束保证该字段的所有数据都是唯一…...
ControlNet作者放大招!IC-Light:控制生成图片光照效果!
ControlNet作者张吕敏近日又开源了一项新的工作:IC-Light (Impose Constant Light),在不改变图片内容的条件下,可以控制生成图片的光照效果。 作者发布了两种类型的模型:文本条件重打光模型和背景条件重打光…...
【Java】Java中类的初始化顺序(静态方法,静态块,非静态块,最后有流程图)
📝个人主页:哈__ 期待您的关注 目录 一、无继承关系类的初始化 1、静态变量k被初始化 2、静态变量t1初始化 3、静态变量 t2初始化 4、静态变量i初始化 5、静态变量n初始化 6、静态块初始化 7、非静态块初始化 8、非静态属性初始化 9、执行构造…...
在RK3588开发板使用FFMpeg 结合云服务器加SRS实现摄像头数据推流到云端拱其他设备查看
今天测试了一把在开发板把摄像头数据推流到云端服务器,然后给其他电脑通过val软件拉取显示摄像头画面,浅浅记录一下大概步骤 1.开发板端先下载ffmpeg apt install ffmpeg2.云服务器先安装SRS的库 云服务器我使用ubuntu系统,SRS是个什么东西&…...
app大全/北京网站优化多少钱
好久都没搞这个了,都快忘了,我记得可以不用直接修改,可以直接查看的 1,下载一个pe 太多种类了,不一一介绍,随便搞一个,功能都一样...
没有备案的网站怎么访问不了/成人短期就业培训班
21日,以“向未来出发”为主题的秋季运动会在童心小学举行。现场,很多小朋友利用纸箱、报纸等废旧材料,每个人都制作了一身特别的时装,有的像机器人,有的像公主,有的像国王,引得全场观众热烈欢呼…...
不用js做网站/广州网站优化服务商
基本数据类型的包装类java.lang.Integer是我们频繁使用的一个系统类,那么通过一个示例反应出的几个问题来深入理解一下此类的源码。需求:实现Integer类型的两个数值交换。1 packagecn.integer;23 public classDemo {4 public static voidmain(String[] a…...
哈尔滨网站建设oeminc/关键词首页排名优化
我的首发平台是公众号【CodeAllen】,学习交流QQ群:736386324,转载请注明出处 我的观点是肯定可以 虽然汽车和手机外形差别巨大,大多数人都不会认为他们俩是一种东西,但是之后新能源时代汽车的发展路径肯定是个手机一模一样的 那…...
成都网站建设开发/广东网络seo推广公司
忘记过去,超越自己 ❤️ 博客主页 单片机菜鸟哥,一个野生非专业硬件IOT爱好者 ❤️❤️ 本篇创建记录 2022-05-20 ❤️❤️ 本篇更新记录 2022-05-20 ❤️🎉 欢迎关注 🔎点赞 👍收藏 ⭐️留言📝🙏 此博客均由博主单独编写,不存在任何商业团队运营,如发现错误,请…...
网站管理教程/今日国际新闻摘抄
孙广东:2015-2-6/2:28 转载请注明出处:http://blog.csdn.net/u010019717 更全的内容请看我的游戏蛮牛地址:http://www.unitymanual.com/space-uid-18602.html 先看一下效果:区别就是一个2d一个3d. 2d就…...