C语言循环链表实现贪吃蛇游戏
本文实例为大家分享了C语言表实现贪吃蛇游戏的具体代码,供大家参考,具体内容如下
总体思想
利用循环链表将一条蛇的坐标进行存储,然后利用gotoxy()函数(可以将光标定位到指定的位置),此时根据蛇的坐标进行输出“@”,输出多几个既可以产生一条蛇。通过遍历循环链表进行蛇的移动,对循环链表的插入元素,产生蛇变长的效果。下面为各功能实现的函数
1.贪吃蛇地图函数map()
2.蛇的移动move(),up(),left()等函数
3.产生食物food()和吃到食物eat_food()
4.蛇吃到食物时产生的变长效果snake_link()函数
5.判断蛇的死亡,分别为撞墙hit_wall()和自杀suicide()
1.贪吃蛇地图函数map()
游戏地图采用的是应该封闭的区域,采用一个数组a[25][50],将此数组初始化为0,将游戏墙的边缘赋值为1,当数组为0,输出" ",数组为1,输出“#”,产生一个地图。
代码如下:
void map() //创建蛇的地图
{
int a[25][50] = {0};
int i,j;
for(i = 0; i < 50; i++)
{
a[0][i] = 1;
a[24][i] =1;
}
for(i = 0; i < 25; i++)
{
a[i][0] = 1;
a[i][49] =1;
}
for(i = 0; i < 25; i++)
for(j = 0; j < 50; j++)
{
if(j%50 == 0)
printf("\n");
if(a[i][j] == 0)
{
printf(" ");
}
else
{
printf("#");
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2.蛇的移动move(),up(),left()等函数
move()函数主要对蛇的上下左右进行更改在此采用switch函数进行解决(下面代码中ch为全局变量)
代码如下
void move(struct snake *p) //蛇的移动函数
{
while(1)
{
ch = getch();
switch(ch)
{
case 'W':p = up(p);break;
case 'A':p = left(p);break;
case 'D':p = right(p);break;
case 'S':p = down(p);break;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
让蛇动起来的即我们主要对蛇的坐标进行更改,此时蛇头移动一次我们就利用gotoxy()函数进行输出“@”,然后在蛇尾输出“ ”,循环往复就可以产生蛇移动的效果,蛇的上下左右则只需在移动一个方向的时候对单一的坐标x或y进行更改,然后对更改的坐标保存进循环链表即可。移动函数则主要有up(),left()等,因为做法差不多,在此只对up()函数进行展示
代码如下
struct snake *up(struct snake *p) //向上移动
{
int x;
int y;
x = p->pre->x; //将蛇头坐标赋值给x,y
y = p->pre->y;
while(p) //对循环链表的遍历,即蛇的遍历
{
Sleep(SNAKE_SPEED); //蛇移动的速度
y--; //向上移动则只需将纵坐标进行减,就可以实现蛇向上移动的效果
gotoxy(p->x,p->y); //定位到蛇尾,输出“ ”即蛇尾消失
printf(" ");
gotoxy(x, y); //定位到蛇头输出,"@",结合上面的蛇尾消失又进行蛇头打印,产生蛇移动的效果
printf("@");
suicide(p,x,y); //判断蛇头是否撞到蛇身
p = p->next; //将蛇头的坐标变为下一个
p->pre->x = x; //此时将前一个蛇头变成蛇尾,通过不断的遍历产生不断移动的效果
p->pre->y = y;
food(); //产生食物
eat_food(p,x,y); //判断是否吃到食物
hit_wall(y); //判断是否撞墙
if(kbhit()) break; //判断是否有按键输入,有就进行蛇移动方向的改变
}
return p;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
3.产生食物food()和吃到食物eat_food()
食物和吃到食物,产生食物则采用了产生随机数,产生一个食物的x,y坐标分别存放在全局变量food_xy[2]数组里面,最后利用gotoxy(food_xy[0],food_xy[1])随机产生食物
代码如下
void food() //产生食物
{
int i;
if(!flag) //根据flag的值来判断地图上是否有食物
{
srand( (unsigned)time( NULL ) );
for( i = 0; i < 2; i++ ) //对food_(x,y)来随机赋值
{
food_xy[i] = rand()%24+2;
while(food_xy[0] == 1 || food_xy[0] == 25) //这两个while为了防止食物
food_xy[0] = rand()%24+2; //的坐标与地图的边缘重叠
while(food_xy[1] >= 49 || food_xy[1] == 1)
food_xy[1] =rand()%24+2;
}
gotoxy(food_xy[0],food_xy[1]); //打印食物
printf("*");
flag = 1;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
吃到食物eat_food(),则我们只需判断蛇头是否和食物的坐标重叠,若重叠则表明蛇吃到了食物
代码如下
void eat_food(struct snake *p,int x, int y) //蛇吃到食物,即主要是对蛇头的x,y坐标和
{ //food_xy的坐标进行匹配对比,若相同即调
if(x == food_xy[0] && y == food_xy[1]) //snake_link函数即可
{
p = snake_link(p);
flag = 0; //表明食物被吃,准备重新产生食物
printSnake(p);
gotoxy(8,0);
score = score + 1; //得分
printf("%d",score);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
4.蛇吃到食物时产生的变长效果snake_link()函数
蛇的变长,当蛇吃到食物的时候,此时我们将食物的坐标变成蛇头,然后进行重新的打印蛇,即可以有蛇变成的效果产生,实质为对循环链表进行元素的插入。
在这里插入图片描述
即通过这样将食物的坐标插进去循环链表,达到蛇变成的效果
代码如下
struct snake *snake_link(struct snake *p) //蛇的连接
{
struct snake *q;
q = (struct snake *)malloc(sizeof(struct snake)); //即主要是实现了对循环链表的插入元素,再
q->x = food_xy[0]; //进行打印蛇,即可有吃到食物蛇变长的结果
q->y = food_xy[1];
q->pre = p->pre;
p->pre->next = q;
p->pre = q;
q->next = p;
return p;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
5.判断蛇的死亡,分别为撞墙hit_wall()和自杀suicide()
撞墙,则只需判断蛇头的单一坐标x轴或者y轴是否与墙壁的坐标是否相等,若相等则说明蛇撞墙了
代码如下
void hit_wall(int n) //判断蛇是否撞墙,即对蛇的单一坐标x或者y进行判断,若等于墙壁的值,即游戏结束
{
if(ch == 'W'|| ch == 'S' )
if(n == 1 || n == 25) //墙壁的坐标值
{
gotoxy(0,26);
printf("游戏结束!");
printf("你的得分:%d",score);
exit(0);
}
if(ch == 'A'|| ch == 'D' )
if(n == 0 || n == 49)
{
gotoxy(0,26);
printf("游戏结束!");
printf("你的得分:%d",score);
exit(0);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
自杀suicide()即蛇头是否有撞到了蛇身,做法是把蛇头的坐标拿出来,与蛇身的坐标进行对比如果相等,说明蛇头撞到了蛇身,本质上是循环链表的值进行匹配,遍历
代码如下
void suicide(struct snake *p, int x, int y) //自杀,即撞到自己本身的时候游戏结束
{
struct snake *q; //把蛇头坐标传递进来,然后与其自己身体坐标做对比若有相等则表明,蛇头撞到了蛇身
q = p;
while(q != p->next) //即对循环链表的遍历匹配
{
if(p->x == x && p->y == y)
{
gotoxy(0,26);
printf("游戏结束!");
printf("你的得分:%d",score);
exit(0);
}
else
p = p->next;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
到此蛇的基本功能已经讲完,以下是全部代码。
全部代码如下
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
#define SNAKE_SPEED 200 //蛇移动的速度
int score = 0; //成绩得分
int flag = 0; //用于判断地图上是否存在食物,0为不存在食物
int food_xy[2]; //定位食物的位置
char ch; //用来决定蛇的移动方向
struct snake //定义一条循环链表的蛇
{
int x;
int y;
struct snake *next;
struct snake *pre;
};
void HideCursor()//把蛇移动的时候产生的光标进行隐藏,隐藏光标函数
{
CONSOLE_CURSOR_INFO cursor;
cursor.bVisible = FALSE;
cursor.dwSize = sizeof(cursor);
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorInfo(handle, &cursor);
}
void gotoxy(int x, int y) //定位光标函数,用来实现蛇的移动,和食物的出现(传送x,y可以将光标定位到x,y)
{
HideCursor();
COORD coord = {x,y};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
void map() //创建蛇的地图
{
int a[25][50] = {0};
int i,j;
for(i = 0; i < 50; i++)
{
a[0][i] = 1;
a[24][i] =1;
}
for(i = 0; i < 25; i++)
{
a[i][0] = 1;
a[i][49] =1;
}
for(i = 0; i < 25; i++)
for(j = 0; j < 50; j++)
{
if(j%50 == 0)
printf("\n");
if(a[i][j] == 0)
{
printf(" ");
}
else
{
printf("#");
}
}
}
struct snake *createSnake() //给蛇进行初始化,构建一条蛇,本质为循环链表
{
int i;
struct snake *head,*p,*q;
p = q = (struct snake *)malloc(sizeof(struct snake));
head = NULL;
head = p;
head->pre = NULL;
for( i = 0; i < 5; i++)
{
p->x = 25 - i;
p->y = 13;
p->pre = head->pre;
head->pre = p;
q->next = p;
q = p;
p = (struct snake *)malloc(sizeof(struct snake));
}
q->next = head;
return head;
}
void printSnake(struct snake *p) //打印蛇,利用gotoxy()来对蛇进行打印,只需遍历一次循环链表即可将坐标可视化为一条蛇
{
struct snake *q;
q = p;
while(q != p->next) //循环链表的遍历
{
gotoxy(p->x,p->y); //根据坐标和定位光标函数来打@,实现输出蛇
printf("@");
p = p->next;
}
gotoxy(p->x,p->y);
printf("@");
gotoxy(0,0);
printf("你的得分:"); //初始化得分
}
void food() //产生食物
{
int i;
if(!flag) //根据flag的值来判断地图上是否有食物
{
srand( (unsigned)time( NULL ) );
for( i = 0; i < 2; i++ ) //对food_(x,y)来随机赋值
{
food_xy[i] = rand()%24+2;
while(food_xy[0] == 1 || food_xy[0] == 25) //这两个while为了防止食物的坐标与地图的边缘重叠
food_xy[0] = rand()%24+2;
while(food_xy[1] >= 49 || food_xy[1] == 1)
food_xy[1] =rand()%24+2;
}
gotoxy(food_xy[0],food_xy[1]); //打印食物
printf("*");
flag = 1;
}
}
struct snake *snake_link(struct snake *p) //蛇的连接
{
struct snake *q;
q = (struct snake *)malloc(sizeof(struct snake)); //即主要是实现了对循环链表的插入元素,再进行打印蛇,即可有吃到食物蛇变长的结果
q->x = food_xy[0];
q->y = food_xy[1];
q->pre = p->pre;
p->pre->next = q;
p->pre = q;
q->next = p;
return p;
}
void eat_food(struct snake *p,int x, int y) //蛇吃到食物,即主要是对蛇头的x,y坐标和food_xy的坐标进行匹配对比,若相同即调用snake_link函数即可
{
if(x == food_xy[0] && y == food_xy[1])
{
p = snake_link(p);
flag = 0;
printSnake(p);
gotoxy(8,0);
score = score + 1;
printf("%d",score);
}
}
void hit_wall(int n) //判断蛇是否撞墙,即对蛇的单一坐标x或者y进行判断,若等于墙壁的值,即游戏结束
{
if(ch == 'W'|| ch == 'S' )
if(n == 1 || n == 25)
{
gotoxy(0,26);
printf("游戏结束!");
printf("你的得分:%d",score);
exit(0);
}
if(ch == 'A'|| ch == 'D' )
if(n == 0 || n == 49)
{
gotoxy(0,26);
printf("游戏结束!");
printf("你的得分:%d",score);
exit(0);
}
}
void suicide(struct snake *p, int x, int y) //自杀,即撞到自己本身的时候游戏结束
{
struct snake *q; //把蛇头坐标传递进来,然后与其自己身体坐标做对比若有相等则表明,蛇头撞到了蛇身
q = p;
while(q != p->next) //即对循环链表的遍历匹配
{
if(p->x == x && p->y == y)
{
gotoxy(0,26);
printf("游戏结束!");
printf("你的得分:%d",score);
exit(0);
}
else
p = p->next;
}
}
struct snake *up(struct snake *p) //向上移动
{
int x;
int y;
x = p->pre->x; //将蛇头坐标赋值给x,y
y = p->pre->y;
while(p) //对循环链表的遍历,即蛇的遍历
{
Sleep(SNAKE_SPEED); //蛇移动的速度
y--; //向上移动则只需将纵坐标进行减,就可以实现蛇向上移动的效果
gotoxy(p->x,p->y); //定位到蛇尾,输出“ ”即蛇尾消失
printf(" ");
gotoxy(x, y); //定位到蛇头输出,"@",结合上面的蛇尾消失又进行蛇头打印,产生蛇移动的效果
printf("@");
suicide(p,x,y); //判断蛇头是否撞到蛇身
p = p->next; //将蛇头的坐标变为下一个
p->pre->x = x; //此时将前一个蛇头变成蛇尾,通过不断的遍历产生不断移动的效果
p->pre->y = y;
food(); //产生食物
eat_food(p,x,y); //判断是否吃到食物
hit_wall(y); //判断是否撞墙
if(kbhit()) break; //判断是否有按键输入,有就进行蛇移动方向的改变
}
return p;
}
struct snake *left(struct snake *p) //向左移动
{
int x;
int y;
x = p->pre->x;
y = p->pre->y;
while(p)
{
Sleep(SNAKE_SPEED);
x--;
gotoxy(p->x,p->y);
printf(" ");
gotoxy(x, y);
printf("@");
suicide(p,x,y);
p = p->next;
p->pre->x = x;
p->pre->y = y;
food();
eat_food(p,x,y);
hit_wall(x);
if(kbhit()) break;
}
return p;
}
struct snake *down(struct snake *p) //向下移动
{
int x;
int y;
x = p->pre->x;
y = p->pre->y;
while(p)
{
Sleep(SNAKE_SPEED);
y++;
gotoxy(p->x,p->y);
printf(" ");
gotoxy(x, y);
printf("@");
suicide(p,x,y);
p = p->next;
p->pre->x = x;
p->pre->y = y;
food();
eat_food(p,x,y);
hit_wall(y);
if(kbhit()) break;
}
return p;
}
struct snake *right(struct snake *p) //向右移动
{
int x;
int y;
x = p->pre->x;
y = p->pre->y;
while(p)
{
Sleep(SNAKE_SPEED);
x++;
gotoxy(p->x,p->y);
printf(" ");
gotoxy(x, y);
printf("@");
suicide(p,x,y);
p = p->next;
p->pre->x = x;
p->pre->y = y;
food();
eat_food(p,x,y);
hit_wall(x);
if(kbhit()) break;
}
return p;
}
void move(struct snake *p) //蛇的移动函数
{
while(1)
{
ch = getch();
switch(ch)
{
case 'W':p = up(p);break;
case 'A':p = left(p);break;
case 'D':p = right(p);break;
case 'S':p = down(p);break;
}
}
}
int main()
{
struct snake *p;
map(); //产生地图
p = createSnake(); // 初始化蛇
printSnake(p); // 打印蛇
move(p); //移动蛇
return 0;
}
相关文章
- 这篇文章主要为大家详细介绍了C语言实现放烟花的程序,有音乐播放,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-02-23
- 本篇文章主要介绍C语言中char的知识,并附有代码实例,以便大家在学习的时候更好的理解,有需要的可以看一下...2020-04-25
- 这篇文章主要介绍了详解如何将c语言文件打包成exe可执行程序,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-25
- free函数是释放之前某一次malloc函数申请的空间,而且只是释放空间,并不改变指针的值。下面我们就来详细探讨下...2020-04-25
- 这篇文章主要介绍了C语言中计算正弦的相关函数总结,包括正弦和双曲线正弦以及反正弦的函数,需要的朋友可以参考下...2020-04-25
详解C语言中的rename()函数和remove()函数的使用方法
这篇文章主要介绍了详解C语言中的rename()函数和remove()函数的使用方法,是C语言入门学习中的基础知识,需要的朋友可以参考下...2020-04-25- 这篇文章主要介绍了C语言中求和、计算平均值、方差和标准差的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-12-10
- 本篇文章主要讲解C语言 基本语法,这里提供简单的示例和代码来详细讲解C语言的基本语法,开始学习C语言的朋友可以看一下,希望能够给你带来帮助...2021-09-18
- 这篇文章主要介绍了C语言中send()函数和sendto()函数的使用方法,是C语言入门学习中的基础知识,需要的朋友可以参考下...2020-04-25
- 今天小编就为大家分享一篇C语言实现从文件读入一个3*3数组,并计算每行的平均值,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-04-25
- 这篇文章主要介绍了C语言中memcpy 函数的用法详解的相关资料,需要的朋友可以参考下...2020-04-25
- 这篇文章主要介绍了使用C语言操作文件的基本函数整理,包括创建和打开以及关闭文件的操作方法,需要的朋友可以参考下...2020-04-25
- 这篇文章主要介绍了C语言中查找字符在字符串中出现的位置的方法,分别是strchr()函数和strrchr()函数的使用,需要的朋友可以参考下...2020-04-25
- 很多同学在学习c语言的时候是不是会碰到a++和++a都有甚么作用啊。今天我们就来探讨下...2020-04-25
- 这篇文章主要对C语言中const关键字的用法进行了详细的分析介绍,需要的朋友可以参考下...2020-04-25
- 这篇文章主要为大家详细介绍了JavaScript实现网页贪吃蛇游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-07-28
- 下面小编就为大家带来一篇C语言实现时间戳转日期的算法(推荐)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-04-25
- 这篇文章主要介绍了C语言之整数划分问题(递归法)实例代码的相关资料,需要的朋友可以参考下...2020-04-25
C语言正则表达式详解 regcomp() regexec() regfree()用法详解
C语言处理正则表达式常用的函数有regcomp()、regexec()、regfree()和regerror(),这里就为大家介绍一下,需要的朋友可以参考一下啊...2020-04-25- 本文给大家简单介绍下c实现linux下的数据库备份的方法和具体的源码,十分的实用,有需要的小伙伴可以参考下。...2020-04-25