❀❀❀ 文章由@不准备秃的大伟原创 ❀❀❀
♪♪♪ 若有转载,请联系博主哦~ ♪♪♪
❤❤❤ 致力学好编程的宝藏博主,代码兴国!❤❤❤
生命不停,学习不止。大家好,我是大伟,今天的话继续给大家实现我们的C语言小游戏:贪吃蛇的主要的代码的编写,喜欢的铁汁们请关注并支持大伟哦~
上篇博客我们谈论了贪吃蛇的游戏开发的环境和功能介绍,什么?你还没看过?那还不赶紧戳戳传送:——————> 贪吃蛇(游戏开发的环境和功能介绍)
效果展示:
贪吃蛇游戏
首先呢,在实现代码之前,我们先理清一下我们游戏要实现的功能:
- 众所周知,我们玩贪吃蛇的时候都有个建议的地图来限制蛇的行动,而蛇撞到墙的时候会直接结束游戏。所以,我们需要写个正方形的墙体,并实现蛇的头撞到墙(蛇头的坐标与墙的坐标相同)就结束游戏。
- 此外,我们还需要一条蛇,我们需要用键盘操作蛇的运动方向,还可以改变蛇的运动速度,而当蛇吃到食物的时候蛇身会变长,当蛇头撞到墙或自己的身体时会结束游戏。所以我们需要用一种方法维护这条蛇,至于是什么方法呢,那当然是我们的单链表啦(各位铁汁们可以思考一下为什么是使用单链表) (^▽^ ) 。
- 然后就是食物了,食物每次只会出现一个(当然可以一次出现多个,看你自己的需求),而且食物出现的坐标是在墙限制的范围内随机的,当食物被蛇吃掉时就会消失,然后重新生成一个食物
- 接着就是需要一个计分表,用来显示当前的分数和每个食物的分数(速度越快,食物的占比分越高,反之越少)
- 最后就是游戏状态,可以控制游戏的进行与停止
好的,以上就是要实现的功能,我们一个一个来吧!开码!
Snake.h:
不管怎么说,现在头文件中把我们需要的功能及前置条件先写出来,博主这里直接给大家了:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<windows.h>
#include<locale.h>
#include<time.h>
//头文件的包含#define KEY_PRESS(VK) ((GetAsyncKeyState(VK)&1) ? 1 : 0)
//检测按键是否按下#define WALL L'□'
#define BODY L'●'
#define FOOD L'☆'
//定义宽字符#define POS_X 24
#define POS_Y 15
//定义坐标enum GAME_STATUS
{OK = 1,ESC,KILL_BY_WALL,KILL_BY_SELF,END_NORMAL
};
//定义游戏状态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 GameStart(pSnake ps);//游戏运⾏过程
void GameRun(pSnake ps);//游戏结束
void GameEnd(pSnake ps);//设置光标的坐标
void SetPos(short x, short y);//欢迎界面
void WelcomeToGame();//打印帮助信息
void PrintHelpInfo();//创建地图
void CreateMap();//初始化蛇
void InitSnake(pSnake ps);//创建⻝物
void CreateFood(pSnake ps);//暂停响应
void pause();//下⼀个节点是食物
int NextIsFood(pSnakeNode psn, pSnake ps);//吃食物
void EatFood(pSnakeNode psn, pSnake ps);//不吃食物
void NoFood(pSnakeNode psn, pSnake ps);//撞墙检测
int KillByWall(pSnake ps);//撞自身检测
int KillBySelf(pSnake ps);//蛇的移动
void SnakeMove(pSnake ps);//游戏初始化
void GameStart(pSnake ps);//游戏运⾏
void GameRun(pSnake ps);//游戏结束
void GameEnd(pSnake ps);
Snake.c:
开始游戏:
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 SetPos(short x, short y)
{HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);//获得设备句柄COORD pos = { x , y };//根据句柄设置光标位置SetConsoleCursorPosition(handle, pos);
}
打印欢迎信息:
void WelcomeToGame()
{//欢迎信息SetPos(36, 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 <= 57; i+=2){wprintf(L"%c", WALL);}//下SetPos(0, 25);for (i = 0; i <= 57; i+=2){wprintf(L"%c", WALL);}//左for (i = 1; i <= 25; i++){SetPos(0, i);wprintf(L"%c", WALL);}//右for (i = 1; i <= 25; i++){SetPos(56, i);wprintf(L"%c", WALL);}}
初始化蛇:
void InitSnake(pSnake ps)
{pSnakeNode cur = NULL;int i = 0;for (int i = 0; i < 5; i++){cur = (pSnakeNode)malloc(sizeof(SnakeNode));if (cur == NULL){perror("InitSnake()::malloc fail");return;}cur->next = NULL;cur->x = POS_X + i * 2;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"%c", BODY);cur = cur->next;}ps->SleepTime = 200;ps->Score = 0;ps->Status = OK;ps->Dir = right;ps->FoodWeight = 10;}
创建食物:
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 (cur->x == x && cur->y == y){goto again;}cur = cur->next;}pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));if (pFood == NULL){perror("CreateFood()::malloc fail");return;}else{pFood->x = x;pFood->y = y;SetPos(pFood->x, pFood->y);wprintf(L"%c", FOOD);ps->pFood = pFood;}
}
游戏运行:
void GameRun(pSnake ps)
{//打印帮助信息PrintHelpInfo();do{SetPos(64, 10);printf("得分:%d ", ps->Score);printf("每个食物得分:%-2d分", ps->FoodWeight);if (KEY_PRESS(VK_UP) && ps->Dir != down){ps->Dir = up;}if (KEY_PRESS(VK_DOWN) && ps->Dir != up){ps->Dir = down;}if (KEY_PRESS(VK_LEFT) && ps->Dir != right){ps->Dir = left;}if (KEY_PRESS(VK_RIGHT) && ps->Dir != left){ps->Dir = right;}if (KEY_PRESS(VK_SPACE)){pause(ps);}else if (KEY_PRESS(VK_ESCAPE)){ps->Status = END_NORMAL;break;}else if (KEY_PRESS(VK_F1)){if (ps->SleepTime >= 50){ps->SleepTime -= 30;ps->FoodWeight += 2;}}else if (KEY_PRESS(VK_F2)){if (ps->SleepTime <= 350){ps->SleepTime += 30;ps->FoodWeight -= 2;if(ps->SleepTime == 350)ps->FoodWeight = 1;}}Sleep(ps->SleepTime);SnakeMove(ps);} while (ps->Status == OK);}
帮助信息:
void PrintHelpInfo()
{SetPos(64, 15);printf("不能穿墙,不能咬到自己\n");SetPos(64, 16);printf("用↑.↓.←.→分别控制蛇的移动.");SetPos(64, 17);printf("F1 为加速,F2 为减速\n");SetPos(64, 18);printf("ESC :退出游戏.space:暂停游戏.");SetPos(64, 20);printf("@不准备秃的大伟");
}
游戏暂停:
void pause()
{while (1){Sleep(300);if (KEY_PRESS(VK_SPACE)){break;}}
}
蛇的运动:
void SnakeMove(pSnake ps)
{pSnakeNode pNextNode = (pSnakeNode)malloc(sizeof(SnakeNode));if (pNextNode == NULL){perror("SnakeMove():: malloc fail");return;}switch (ps->Dir){case up:{pNextNode->y = ps->_pSnake->y-1;pNextNode->x = ps->_pSnake->x;}break;case down:{pNextNode->y = ps->_pSnake->y + 1;pNextNode->x = ps->_pSnake->x;}break;case left:{pNextNode->y = ps->_pSnake->y;pNextNode->x = ps->_pSnake->x - 2;}break;case right:{pNextNode->y = ps->_pSnake->y;pNextNode->x = ps->_pSnake->x + 2;}break;}if (NextIsFood(pNextNode, ps)){EatFood(pNextNode,ps);}elseNoFood(pNextNode,ps);KillByWall(ps);KillBySelf(ps);
}
下一个位置是食物:
int NextIsFood(pSnakeNode pfood, pSnake ps)
{return (pfood->x == ps->pFood->x) && (pfood->y == ps->pFood->y);
}
吃食物:
void EatFood(pSnakeNode pfood, pSnake ps)
{//头插pfood->next = ps->_pSnake;ps->_pSnake = pfood;pSnakeNode cur = ps->_pSnake;while (cur){SetPos(cur->x, cur->y);wprintf(L"%c", BODY);cur = cur->next;}ps->Score += ps->FoodWeight;free(ps->pFood);CreateFood(ps);
}
下一个位置不是食物:
void NoFood(pSnakeNode pfood, pSnake ps)
{//头插pfood->next = ps->_pSnake;ps->_pSnake = pfood;pSnakeNode cur = ps->_pSnake;while (cur->next->next){SetPos(cur->x, cur->y);wprintf(L"%c", BODY);cur = cur->next;}SetPos(cur->next->x, cur->next->y);printf(" ");free(cur->next);cur->next = NULL;}
撞墙了:
int KillByWall(pSnake ps)
{if ( (ps->_pSnake->x == 0)|| (ps->_pSnake->x == 56)|| (ps->_pSnake->y == 0)|| (ps->_pSnake->y == 25)){ps->Status = KILL_BY_WALL;return 1;}return 0;
}
撞到自己了:
int KillBySelf(pSnake ps)
{pSnakeNode cur = ps->_pSnake->next;while (cur){if((ps->_pSnake ->x == cur->x)&& (ps->_pSnake->y == cur->y)){ps->Status = KILL_BY_SELF;return 1;}cur = cur->next;}return 0;
}
游戏结束:
void GameEnd(pSnake ps)
{pSnakeNode cur = ps->_pSnake;SetPos(10, 12);switch (ps->Status){case KILL_BY_SELF:printf("呆毛,撞上自己了,笑死啦哈哈!");break;case KILL_BY_WALL:printf("这么简单的游戏都能撞上墙,啧啧啧,啥实力?");break;case END_NORMAL:printf("玩不起就退游戏,我只能说菜,就多练 ");break;}while (cur){pSnakeNode del = cur;cur = cur->next;free(del);}
}
test.c:
#include"Snake.h"
void test1()
{int ch = 0;srand((unsigned int)time(NULL));do{//创建贪食蛇Snake snake = { 0 };GameStart(&snake);//游戏开始前的初始化GameRun(&snake);//玩游戏的过程GameEnd(&snake);//善后的工作SetPos(20, 15);printf("再来一局吗?(Y/N):");ch = getchar();getchar();} while (ch == 'Y');SetPos(0, 26);
}
int main()
{setlocale(LC_ALL, "");test1();return 0;
}
到此为止我们的贪吃蛇游戏已经写完啦!给自己鼓个掌把,啪叽啪叽~ 游戏运行视频已经放在文章开头,大家敬请观看哦~
A bird in the hand is worth two in the bush. 双鸟在林不如一鸟在手
本篇博客也就到此为止了,送大家一碗鸡汤,勉励自己以及这世界上所有追逐梦想的赤子趁年华尚好努力提升自己,莫欺少年穷!