
贪食蛇(也叫贪吃蛇)是一款经典的小游戏。
——————————————————————
本博客实现使用C语言在Windows环境的控制台中模拟实现贪吃蛇小游戏。
• 贪吃蛇地图的绘制
• 蛇吃食物的功能(上、下、左、右方向键来控制蛇的方向)
• 蛇撞墙死亡
• 蛇撞自身死亡
• 计算得分
• 蛇身加速、减速
• 暂停游戏
- GameStrat();//游戏开始前的初始化
- GameRun();//玩游戏的过程
- GameEnd();//善后工作(节点的释放)

- #pragma once
-
-
- #include
- #include
- #include
- #include
- #include
-
- #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 GAME_STATUS
- {
- OK=1,//正常运行
- ESC, //按了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);
- #define _CRT_SECURE_NO_WARNINGS 1
-
- #include "snake.h"
-
- void SetPos(int x,int y)
- {
- //获得设备句柄
- HANDLE hanlde = GetStdHandle(STD_OUTPUT_HANDLE);
- //根据句柄设置光标的位置
- COORD pos = { x, y };
- SetConsoleCursorPosition(hanlde, pos);
- }
-
- void WelcomeToGame()
- {
- //欢迎信息
- SetPos(35, 10);
- printf("欢迎来到贪吃蛇小游戏\n");
- SetPos(38, 20);
- system("pause");
- system("cls");
-
- //功能介绍信息
- SetPos(15, 10);
- printf("用 ↑ . ↓ . ← . → 来控制蛇的移动,F3是加速,F4是减速");
- SetPos(15, 11);
- printf("加速能得到更高的分数");
- SetPos(38, 20);
- system("pause");
- system("cls");
- }
-
- void CreateMap()
- {
- int i = 0;
- //上
- SetPos(0, 0);
- for (i = 0; i <= 56; i += 2)
- {
- wprintf(L"%lc", WALL);
- }
- //下
- SetPos(0, 26);
- for (i = 0; i <= 56; i += 2)
- {
- 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)
- {
- //创建5个蛇身的结点
- pSnakeNode cur = NULL;
- int i = 0;
- for (i = 0; i < 5; i++)
- {
- cur = (pSnakeNode)malloc(sizeof(SnakeNode));
- if (cur == NULL)
- {
- perror("InitSnake():malloc()");
- return;
- }
- cur->x = POS_X + 2 * i;
- 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 CreateFood(pSnake ps)
- {
- int x = 0;
- int y = 0;
-
- again:
- do
- {
- x = rand() % 53 + 2;
- y = rand() % 24 + 1;
- } while (x % 2 != 0);
-
- //坐标和蛇的身体的每个节点的做坐标比较
- 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;
- }
-
- pFood->x = x;
- pFood->y = y;
-
- ps->pFood = pFood;
- SetPos(x, y);
- wprintf(L"%lc", FOOD);
-
- }
-
-
-
- void GameStart(pSnake ps)
- {
- //设置控制台的信息,窗口大小,窗口名
- system("mode con cols=100 lines=30");
- 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(62, 15);
- printf("1.不能穿墙,不能咬到自己");
- SetPos(62, 16);
- printf("2.用 ↑.↓.←.→ 来控制蛇的移动");
- SetPos(62, 17);
- printf("3.F3是加速,F4是减速");
-
- SetPos(62, 19);
- printf("版权@比特就业课");
- }
-
-
- void pause()
- {
- while (1)
- {
- Sleep(100);
- 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;//下一个坐标处是食物
- else
- 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->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 == 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;
- return;
- }
- 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(62, 10);
- printf("总分:%5d\n", ps->Score);
- SetPos(62, 11);
- printf("食物的分值:%02d\n", ps->FoodWeight);
- //检测按键
- //上、下、左、右、ESC、空格、F3、F4
- 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 = ESC;
- break;
- }
- else if (KEY_PRESS(VK_SPACE))
- {
- //游戏要暂定
- pause();//暂定和回复暂定
- }
- else if(KEY_PRESS(VK_F3))
- {
- if (ps->SleepTime >= 80)
- {
- ps->SleepTime -= 30;
- ps->FoodWeight += 2;
- }
- }
- else if (KEY_PRESS(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(15, 12);
- switch (ps->status)
- {
- case ESC:
- printf("主动退出游戏,正常退出\n");
- break;
- case KILL_BY_WALL:
- printf("很遗憾,撞墙了,游戏结束\n");
- break;
- case KILL_BY_SELF:
- printf("很遗憾,咬到自己了,游戏结束\n");
- break;
- }
- //释放贪吃蛇的链表资源
- pSnakeNode cur = ps->pSnake;
- pSnakeNode del = NULL;
-
- while (cur)
- {
- del = cur;
- cur = cur->next;
- free(del);
- }
- free(ps->pFood);
- ps = NULL;
- }
- #define _CRT_SECURE_NO_WARNINGS 1
-
- #include "snake.h"
-
- void test()
- {
- //创建贪食蛇
- int ch = 0;
- do
- {
- Snake snake = { 0 };
- GameStart(&snake);//游戏开始前的初始化
- GameRun(&snake);//玩游戏的过程
- GameEnd(&snake);//善后的工作
- SetPos(20, 15);
- printf("再来一局吗?(Y/N):");
- ch = getchar();
- getchar();// 清理\n
- } while (ch == 'Y' || ch =='y');
- }
-
-
- int main()
- {
- //修改适配本地中文环境
- setlocale(LC_ALL, "");
-
- test();//贪吃蛇游戏的测试
- SetPos(0, 27);
- return 0;
- }

这个博客如果对你有帮助,给博主一个免费的点赞就是最大的帮助❤
欢迎各位点赞,收藏和关注哦❤
如果有疑问或有不同见解,欢迎在评论区留言哦❤
后续我会一直分享双一流211西北大学软件(C,数据结构,C++,Linux,MySQL)的学习干货以及重要代码的分享