成品展示
贪吃蛇
代码分享
test.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include "snake.h"
void test()
{
int ch;
do
{
//创建贪吃蛇
Snake snake = { 0 };
GameStart(&snake);//游戏开始前的初始化
GameRun(&snake);//玩游戏的过程
GameEnd(&snake);//善后的工作
SetPos(25,17);
printf("再来一局吗?(1/0):");
scanf("%d", &ch);
getchar();//清理\n
} while (ch == 1);
}
int main()
{
//修改适配本地中文环境
setlocale(LC_ALL, "");
test();//贪吃蛇游戏测试
SetPos(0, 36);
return 0;
}
snake.h:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <windows.h>
#include <stdbool.h>
#define WALL L'¤'
#define BODY L'●'
#define POS_X 24
#define POS_Y 6
#define Food L'☆'
#define KEY_PAESS(VK) ((GetAsyncKeyState(VK) & 0X1) ? 1:0)
enum GAME_STATUS//游戏状态
{
OK = 1,
ESC,
KILL_BY_WALL,
KILL_BY_SELF
};
enum DIRECTION//方向
{
UP=1,
DOWN,
LEFT,
RIGHT
};
//蛇身节点定义
typedef struct SnakeNode
{
int x;
int y;
struct SnakeNode* next;
}SnakeNode,* pSnakeNode;
//蛇身维护
typedef struct Snake
{
pSnakeNode pSnake;//维护整条蛇的指针
pSnakeNode pFood;//指向食物的指针
int Score;//当前累计的分数
int FoodWeight;//一个食物的分数
int SleepTime;//蛇休眠的时间,休眠的时间越短,蛇的速度越快,越长,越慢
enum GAME_STATUS status;//游戏当前状态
enum DIRECTION dir;//蛇当前走的方向
}Snake,* pSnake;
//获取光标位置
void SetPos(int x, int y);
//游戏开始前的初始化
void GameStart(pSnake ps);
//游戏开始欢迎界面的打印
void WelcomeToGame();
//打印地图
void CreateMap();
//初始化蛇身
void InitSnake(pSnake ps);
//创建食物
void CreateFood(pSnake ps);
//玩游戏的过程
void GameRun(pSnake ps);
//打印帮助信息
void PrintHelpInfo();
//蛇的移动
void SnakeMove(pSnake ps);
//判断下一点是否是食物
int NextIsFood(pSnake ps,pSnakeNode pNext);
//是食物吃掉
void EatFood(pSnake ps, pSnakeNode pNext);
//不是食物不吃
void NotEatFood(pSnake ps, pSnakeNode pNext);
//检测是否撞墙
void KillByWall(pSnake ps);
//检测是否撞到自己
void KillBySelf(pSnake ps);
//游戏结束
void GameEnd(pSnake ps);
snake.c:
#define _CRT_SECURE_NO_WARNINGS 1
#include "snake.h"
//获取光标位置
void SetPos(int x,int y)
{
//获得设置句柄
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
//根据句柄设置光标的位置
COORD pos = { x,y };
SetConsoleCursorPosition(handle, pos);
}
void WelcomeToGame()
{
//欢迎信息
SetPos(49, 15);
printf("Welcome to gluttonous Snake Mini Game");
SetPos(57, 24);
system("pause");
system("cls");
//功能介绍信息
SetPos(45, 13);
printf("用 ↑.↓.←.→ 来控制蛇的移动,F3是加速,F4是减速\n");
SetPos(55, 17);
printf("加速将能得到更高的分数");
SetPos(57, 24);
system("pause");
system("cls");
}
void InitSnake(pSnake ps)
{
//创建四个蛇身
pSnakeNode cur = NULL;
for (int i = 0; i < 4; i++)
{
cur = (pSnakeNode)malloc(sizeof(SnakeNode));
if (cur == NULL)
{
perror("InitSnake malloc:");
return 1;
}
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;
}
}
//打印蛇身
//cur = ps->pSnake;
while (cur)
{
SetPos(cur->x, cur->y);
wprintf(L"%lc", BODY);
cur = cur->next;
}
//贪吃蛇其他信息初始化
ps->dir = RIGHT;
ps->FoodWeight = 10;
ps->pFood = NULL;
ps->Score = 0;
ps->SleepTime = 200;
ps->status = OK;
}
void CreateMap()
{
//上
SetPos(0, 0);
for (int i = 0; i < 70; i += 2)
{
wprintf(L"%lc",WALL);
}
//下
SetPos(0, 35);
for (int i = 0; i < 70; i += 2)
{
wprintf(L"%lc", WALL);
}
//左
SetPos(0, 1);
for (int i = 0; i < 34; i++)
{
wprintf(L"%lc\n", WALL);
}
//右
for (int i = 1; i < 35; i++)
{
SetPos(68, i);
wprintf(L"%lc\n", WALL);
}
}
void CreateFood(pSnake ps)
{
pSnakeNode cur = ps->pSnake;
//生成随机位置
int x = 0;
int y = 0;
again:
do
{
x = rand() % 65 + 2;
y = rand() % 34 + 1;
} while (x % 2 != 0);
//判断是否与蛇身重复
while (cur)
{
if (cur->x == x && cur->y == y)
{
goto again;
}
cur = cur->next;
}
//创建食物
pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));
if (pFood == NULL)
{
perror("CreateFood()::malloc:");
return 1;
}
pFood->x = x;
pFood->y = y;
ps->pFood = pFood;
SetPos(x, y);
wprintf(L"%lc", Food);
}
void GameStart(pSnake ps)
{
//设置控制台信息,窗口大小,窗口名
system("mode con cols=140 lines=40");
system("title 贪吃蛇");
//光标隐藏
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(handle, &CursorInfo);//获取控制光标的信息
CursorInfo.bVisible = false;
SetConsoleCursorInfo(handle, &CursorInfo);
//打印欢迎信息
WelcomeToGame();
//绘制地图
CreateMap();
//初始化蛇
InitSnake(ps);
//创建食物
CreateFood(ps);
}
void PrintHelpInfo()
{
SetPos(80, 16);
printf("温馨提示:");
SetPos(80, 18);
printf("1、按空格开始游戏");
SetPos(80, 19);
printf("2、不能穿墙,不能咬到自己");
SetPos(80, 20);
printf("3、用 ↑.↓.←.→ 来控制蛇的移动");
SetPos(80, 21);
printf("4、F3是加速,F4是减速");
SetPos(80, 22);
printf("5、速度越快食物分值越高,速度越慢食物分值越低");
SetPos(80, 23);
printf("6、退出游戏按ESC,暂停按空格");
/*SetPos(88, 27);
printf("版权@宋东京先生");*/
}
void pause()
{
while (1)
{
Sleep(200);
if (KEY_PAESS(VK_SPACE))
{
break;
}
}
}
int NextIsFood(pSnake ps, pSnakeNode pNext)
{
if (ps->pFood->x == pNext->x && ps->pFood->y == pNext->y)
{
return 1;
}
else
{
return 0;
}
}
void EatFood(pSnake ps, pSnakeNode pNext)
{
//吃掉头插
pNext->next = ps->pSnake;
ps->pSnake = pNext;
//打印蛇身
pSnakeNode pcur = ps->pSnake;
while (pcur)
{
SetPos(pcur->x, pcur->y);
wprintf(L"%lc", BODY);
pcur = pcur->next;
}
//总分变化
ps->Score += ps->FoodWeight;
//释放旧的食物,产生新的食物
free(ps->pFood);
CreateFood(ps);
}
void NotEatFood(pSnake ps, pSnakeNode pNext)
{
//头插
pNext->next = ps->pSnake;
ps->pSnake = pNext;
//释放尾节点
pSnakeNode cur = ps->pSnake;
while (cur->next->next)
{
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->x == 68 ||
ps->pSnake->y == 0 ||
ps->pSnake->y == 35)
{
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;
}
cur = cur->next;
}
}
void SnakeMove(pSnake ps)
{
pSnakeNode pNext = (pSnakeNode)malloc(sizeof(SnakeNode));
if (pNext == NULL)
{
perror("SnakeMove()::malloc()");
return;
}
pNext->next = NULL;
//判断移动方向
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
{
//不是食物就正常走一步
NotEatFood(ps,pNext);
}
//检测是否撞墙
KillByWall(ps);
//检测撞自己
KillBySelf(ps);
}
void GameRun(pSnake ps)
{
//提示信息
PrintHelpInfo();
do
{
//当前分数情况
SetPos(80, 10);
printf("当前得分:%5d", ps->Score);
SetPos(80, 12);
printf("当前每个食物de分值:%02d", ps->FoodWeight);
//检测按键
//↑↓←→ ESC 空格 F3 F4
if (KEY_PAESS(VK_UP) && ps->dir != DOWN)
{
ps->dir = UP;
}
else if (KEY_PAESS(VK_DOWN) && ps->dir != UP)
{
ps->dir = DOWN;
}
else if (KEY_PAESS(VK_LEFT) && ps->dir != RIGHT)
{
ps->dir = LEFT;
}
else if (KEY_PAESS(VK_RIGHT) && ps->dir != LEFT)
{
ps->dir = RIGHT;
}
else if (KEY_PAESS(VK_ESCAPE))
{
ps->status = ESC;
break;
}
else if (KEY_PAESS(VK_SPACE))
{
pause();
}
else if (KEY_PAESS(VK_F3))
{
if (ps->SleepTime > 20)
{
ps->SleepTime -= 30;
ps->FoodWeight += 2;
}
}
else if (KEY_PAESS(VK_F4))
{
if (ps->FoodWeight > 2)
{
ps->SleepTime += 30;
ps->FoodWeight -= 2;
}
}
//走一步
SnakeMove(ps);
//睡眠时间
Sleep(ps->SleepTime);
} while (ps->status == OK);
}
void GameEnd(pSnake ps)
{
SetPos(70, 20);
switch (ps->status)
{
case ESC:
SetPos(30, 15);
printf("已退出游戏");
break;
case KILL_BY_WALL:
SetPos(25, 15);
printf("很遗憾,撞墙游戏结束");
break;
case KILL_BY_SELF:
SetPos(23, 15);
printf("很遗憾,撞到自己游戏结束");
break;
}
//释放空间
pSnakeNode cur = ps->pSnake;
pSnakeNode del = NULL;
while (cur)
{
del = cur;
cur = cur->next;
free(del);
}
free(ps->pFood);
ps = NULL;
}
如果有用的话可以点赞支持一下,拜托了🙏