前几天闲得无聊,依然决定写个这个贪吃蛇小游戏练练手。经过几天夜战,调试了n次(终于体会到了程序员的崩溃)。特地感谢几位师兄学长的帮助,很幸运地完成了这个人生首作。
应用知识:c语言,easyx,数据结构中的链表
游戏界面展示
界面一
界面二
源代码:(一共在一个文件中,共四百多行)
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <memory.h>
#include <string.h>
#include<graphics.h>
#include<conio.h>
#include<easyx.h>
#include<time.h>
#define WALL "■"
#define FOOD "█"
#define INIT_X 20
#define INIT_Y 18
typedef struct node {
int x;
int y;
struct node* next;//储存每一个结点下一个结点的地址,构成一条链表
}SnakeNode, * pSnakeNode;
// 蛇的行走方向
enum DIRECTION
{
UP = 1, DOWN, LEFT, RIGHT
};
//蛇的状态
enum GameState
{
OK,
NORMAL_END,
KILL_BY_WALL,
KILL_BY_SELF
};
// 蛇本身
typedef struct Snake
{
pSnakeNode _psnake;//维护蛇身的指针
pSnakeNode _pFood;//维护食物的位置
int _TotalScore;//总分数
int _AddScore;//增加的分数
int _SleepTime;//休眠时间
DIRECTION _Dir;
GameState _Status;
}Snake, * pSnake;
void Welcome()
{
initgraph(840, 800, EW_SHOWCONSOLE);
setbkcolor(RED);
cleardevice();
//要在设置的字体前面加L
settextstyle(15, 0, "楷体");//设置文字样式,大小,字体
fillrectangle(200, 100, 600, 200);
settextcolor(RGB(173, 0, 13));
setbkmode(TRANSPARENT);
char arr[] = "欢迎来到贪吃蛇游戏,按q开始游戏哦";
int width = 400 / 2 - textwidth(arr) / 2;
int height = 100 / 2 - textheight(arr) / 2;
outtextxy(width + 200, height + 100, arr);
settextstyle(15, 0, "楷体");//设置文字样式,大小,字体
fillrectangle(200, 400, 600, 600);
settextcolor(RGB(173, 0, 13));
setbkmode(TRANSPARENT);
char arr1[] = "方向盘移动,F1加速,F2减速";
int width1 = 50 / 2 - textwidth(arr1) / 2;
int height1 = 200 / 2 - textheight(arr1) / 2;
outtextxy(width1 + 400, height1 + 400, arr1);
}
void SetPos(int x, int y)
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);//把标准输出的句柄得到,并交给变量handle,
COORD pos = { 0 };
pos.X = x;
pos.Y = y;
SetConsoleCursorPosition(handle, pos);//设置handle的输出位置,
}
void DrawMap(void)
{
int i;
for (i = 0; i < 58; i += 2)//画出地图的上边界,在控制界面每一个汉字,占两位,所以每次i+2
{
SetPos(i, 0);
printf(WALL);
}
for (i = 0; i < 58; i += 2)//画出地图的下边界
{
SetPos(i, 26);
printf(WALL);
}
for (i = 0; i < 26; i++)//画出地图的左边界
{
SetPos(0, i);
printf(WALL);
}
for (i = 0; i <= 26; i++)//画出地图的右边界
{
SetPos(58, i);
printf(WALL);
}
}
pSnakeNode BuyNode()
{
pSnakeNode pRet = (pSnakeNode)malloc(sizeof(SnakeNode));
if (pRet == NULL)
{
perror("BuyNode::malloc()");
exit(EXIT_FAILURE);
}
pRet->x = 0;
pRet->y = 0;
pRet->next = NULL;
return pRet;
}
void InitSnake(pSnake ps)
{
pSnakeNode first = BuyNode();//创建蛇头
pSnakeNode cur = NULL;
first->x = INIT_X;
first->y = INIT_Y;
int i = 0;
for (i = 1; i <= 4; i++)
{
cur = BuyNode();//创建蛇身
cur->x = first->x + 2;
cur->y = first->y;
cur->next = first;
first = cur;
}
//打印蛇
while (cur)
{
SetPos(cur->x, cur->y);
printf(FOOD);
cur = cur->next;
}
ps->_psnake = first;
}
void CreateFood(pSnake ps)
{
pSnakeNode pfood = BuyNode();
pSnakeNode cur = ps->_psnake;
pfood->y = rand() % 26 + 1;
do
{
pfood->x = rand() % 55 + 2;//0-54,+2产生2-56
} while (pfood->x % 2 != 0);
while (cur)
{
if (cur->x == pfood->x && cur->y == pfood->y)
{
CreateFood(ps);
}
cur = cur->next;
}
ps->_pFood = pfood;
SetPos(pfood->x, pfood->y);
printf(FOOD);
}
void KillBYWALL(pSnake ps)
{
if ((ps->_psnake->x == 0) || (ps->_psnake->x == 58) || (ps->_psnake->y == 0) || (ps->_psnake->y == 27))
{
ps->_Status == KILL_BY_WALL;
}
}
void KillBySelf(pSnake ps)
{
pSnakeNode tnext = ps->_psnake->next;
while (tnext)
{
if ((tnext->x == ps->_psnake->x) && (tnext->y == ps->_psnake->y))
{
ps->_Status == KILL_BY_SELF;
return;
}
tnext = tnext->next;
}
}
int NextHasFood(pSnakeNode pn, pSnakeNode pf)
{
return (pn->x == pf->x) && (pn->y == pf->y);
}
void EatFood(pSnake ps, pSnakeNode pn)//吃食物
{
pSnakeNode cur = NULL;
pn->next = ps->_psnake;//头插
ps->_psnake = pn;
cur = ps->_psnake;
ps->_TotalScore += ps->_AddScore;
while (cur)
{
SetPos(cur->x, cur->y);
printf(FOOD);
cur = cur->next;
}
CreateFood(ps);
}
void NoFood(pSnake ps, pSnakeNode pn)//没有食物
{
pSnakeNode cur = NULL;
pn->next = ps->_psnake;//头插
ps->_psnake = pn;
cur = ps->_psnake;
while (cur->next->next)
{
SetPos(cur->x, cur->y);
printf(FOOD);
cur = cur->next;
}
SetPos(cur->x, cur->y);
printf(FOOD);
SetPos(cur->next->x, cur->next->y);
printf(" ");
free(cur->next);
cur->next = NULL;
}
void RUN(pSnake ps)
{
InitSnake(ps);
CreateFood(ps);
ps->_AddScore = 10;//每次增加的分数
ps->_TotalScore = 0;//总分
ps->_Dir == RIGHT;//方向
ps->_SleepTime = 200;//0.2秒
ps->_Status == OK;//状态
}
void snakmove(pSnake ps)//蛇的移动
{
pSnakeNode pNextNode = BuyNode();
SetPos(65, 8);
printf("总分:%d", ps->_TotalScore);
SetPos(65, 9);
printf("每个食物的得分:%d ", ps->_AddScore);
//上
switch (ps->_Dir)
{
case UP:
{
pNextNode->x = ps->_psnake->x;
pNextNode->y = ps->_psnake->y - 1;
if (NextHasFood(pNextNode, ps->_pFood))
{
//下一个节点是食物
EatFood(ps, pNextNode);
}
else
{
NoFood(ps, pNextNode);
}
break;
}
case DOWN:
{
pNextNode->x = ps->_psnake->x;
pNextNode->y = ps->_psnake->y + 1;
if (NextHasFood(pNextNode, ps->_pFood))
{
//下一个节点是食物
EatFood(ps, pNextNode);
}
else
{
NoFood(ps, pNextNode);
}
break;
}
case LEFT:
{
pNextNode->x = ps->_psnake->x - 2;
pNextNode->y = ps->_psnake->y;
if (NextHasFood(pNextNode, ps->_pFood))
{
//下一个节点是食物
EatFood(ps, pNextNode);
}
else
{
NoFood(ps, pNextNode);
}
break;
}
case RIGHT:
{
pNextNode->x = ps->_psnake->x + 2;
pNextNode->y = ps->_psnake->y;
if (NextHasFood(pNextNode, ps->_pFood))
{
//下一个节点是食物
EatFood(ps, pNextNode);
}
else
{
NoFood(ps, pNextNode);
}
break;
}
default:
{
break;
}
}
}
void PrintHelpInfo()
{
SetPos(65, 11);
printf("用↑,↓,←,→来控制蛇的移动");
SetPos(65, 12);
printf("F1为加速,F2为减速\n");
SetPos(65, 13);
printf("加速获得分数更多\n");
SetPos(65, 14);
printf("按空格暂停游戏\n");
}
void GameRun(pSnake ps)
{
PrintHelpInfo();
do {
//确定方向
if (GetAsyncKeyState(VK_UP) && (ps->_Dir != DOWN))
{
ps->_Dir = UP;
}
else if (GetAsyncKeyState(VK_DOWN) && ps->_Dir != UP)
{
ps->_Dir = DOWN;
}
else if (GetAsyncKeyState(VK_LEFT) && ps->_Dir != RIGHT)
{
ps->_Dir = LEFT;
}
else if (GetAsyncKeyState(VK_RIGHT) && ps->_Dir != LEFT)
{
ps->_Dir = RIGHT;
}
else if (GetAsyncKeyState(VK_SPACE))
{
//暂停游戏
system("pause");//令目前的进程暂停(进入睡眠状态), 直到被信号(signal)所中断.
}
else if (GetAsyncKeyState(VK_ESCAPE))
{
//结束游戏
ps->_Status == NORMAL_END;
break;
}
else if (GetAsyncKeyState(VK_F1))
{
//加速
if (ps->_SleepTime >= 40)
{
ps->_SleepTime -= 20;
ps->_AddScore += 2;
}
}
else if (GetAsyncKeyState(VK_F2))
{
//减速
if (ps->_SleepTime <= 300)
{
ps->_SleepTime += 20;
ps->_AddScore -= 2;
}
if (ps->_SleepTime > 300)
{
ps->_AddScore = 1;//不能一直减
}
}
Sleep(ps->_SleepTime);//睡眠
//蛇的移动
snakmove(ps);
KillBYWALL(ps);
KillBySelf(ps);
} while (ps->_Status == OK);
}
void GameEnd(pSnake ps)
{
pSnakeNode cur = ps->_psnake;
SetPos(25, 14);
if (ps->_Status == NORMAL_END)
{
SetPos(70, 20);
printf("游戏正常接结束\n");
SetPos(70, 21);
}
else if (ps->_Status == KILL_BY_SELF)
{
SetPos(70, 20);
printf("蛇撞到自己了\n");
SetPos(70, 21);
}
else if (ps->_Status == KILL_BY_WALL)
{
SetPos(70, 20);
printf("撞到墙了\n");
SetPos(70, 21);
}
while (cur)
{
pSnakeNode del = cur;
cur = cur->next;
free(del);
del = NULL;
}
ps->_psnake = NULL;
free(ps->_pFood);
ps->_pFood = NULL;
}
int main()
{
srand((unsigned)time(NULL));
Snake snake = { 0 };//创建贪吃蛇
Welcome();
char key = _getch();
if (key == 'q')
{
closegraph();
}
DrawMap();
RUN(&snake);
GameRun(&snake);
GameEnd(&snake);
system("pause");
return 0;
}
本贴为博主亲手整理。如有错误,请评论区指出,一起进步。谢谢大家的浏览。