C语言实现贪吃蛇游戏教程及源码

C语言实现贪吃蛇游戏教程及源码

一、源码简介

这是一个可以进行贪吃蛇游戏的小程序,采用C语言进行编写。

上下左右控制运动方向,吃到食物得分,如果撞墙或者咬到自身,游戏结束。

编译环境:VC6.0(采取纯C语言写法)

第三方库:无

二、运行截图

游戏结束界面

三、源码解析

先看整个程序的逻辑:

开始界面

进行游戏

初始化

以下循环:

{

根据输入按键的不同,做出不同的反应。

每经过一段时间,蛇进行移动。

}

结束游戏

主函数以及游戏运行的Gamerun函数如下。

int main()

{

Gamestart();

Gamerun();

Gameend();

return 0;

}

void Gamerun()

{

Initsnake();//初始化蛇

Createfood();//创建食物

while(1)

{

Pos(64,10);

printf("得分:%d ",score);

if(GetAsyncKeyState(VK_UP)&&status!=D)status=U;//根据之前是否有按下某种按键,改变前进方向或者暂停

else if(GetAsyncKeyState(VK_DOWN)&&status!=U)status=D;

else if(GetAsyncKeyState(VK_LEFT)&&status!=R)status=L;

else if(GetAsyncKeyState(VK_RIGHT)&&status!=L)status=R;

else if(GetAsyncKeyState(VK_SPACE))Pause();

else if(GetAsyncKeyState(VK_ESCAPE))

{

exit(0);

break;

}

else;

Sleep(sleeptime);//经过一段时间继续前进

if(Snakemove());//如果行动成功(没有死)

else

break;//否则跳出循环

}

}

其中,接收输入按键可以用中的GetAsyncKeyState函数,它可以判断之前的一段时间内是否输入了某按键。

我们用U,D,L,R来表示蛇头朝向上下左右。经过定义之后,可以用这四个字母为status赋值。

#define U 1

#define D 2

#define L 3

#define R 4

int status;蛇并不能180˚转弯,所以要注意判定按键方向是否与目前前进方向相反。

另外我们在这里还用了一个Pos函数。这个函数的目的是将光标定位到(x,y)处,并且能在此进行写入。

void Pos(int x,int y)//定义一个设置光标位置的函数

{

COORD pos;

HANDLE hOutput;

pos.X=x;

pos.Y=y;

hOutput=GetStdHandle(STD_OUTPUT_HANDLE);

SetConsoleCursorPosition(hOutput,pos);

}用到的几个函数都可以在当中找到。

COORD是windows API中定义的一种结构,表示一个字符在控制台屏幕上的坐标;

GetStdHandle用于返回一个句柄,表明是输入,输出还是错误(参数分别是STD_INPUT_HANDLE,STD_OUTPUT_HANDLE,STD_ERROR_HANDLE),HANDLE是对应的句柄的结构体;

SetConsoleCursorPosition可在指定的控制台屏幕缓冲区中设置光标位置。

更多内容可以在控制台文档 - Windows Console | Microsoft Docs中搜索找到。

Pause是另外一个我们定义的函数。如果不按下空格,程序就会循环Sleep指令。

void Pause()//定义暂停函数

{

while(1)

{

Sleep(100);

if(GetAsyncKeyState(VK_ESCAPE))break;

else;

}

}

在进行具体游戏函数的编写之前,我们还需要确定游戏数据是如何存储及调用的,也就是如何保存蛇身的坐标。像蛇身这样的线性结构,非常适合用一个链表进行存储。将蛇身的一个点的坐标放入一个结构体当中,结构体中还有指向下一个结构体的指针。

struct SNAKE//定义蛇身上的一个点

{

int x,y;

SNAKE *next;//定义一个指针,指向蛇下一个点的地址

};

准备工作做完之后,接下来的是游戏主体部分。

接下来我们要写的函数包括:

void Creatmap()//定义创建地图的函数

void Initsnake()//初始化函数

int Hitwall()//检测是否撞墙

int Eatitself()//检测是否碰到自身

void Createfood()//定义创建食物的函数

int Snakemove()//定义蛇身行动的函数

void Gamestart()//开始页面以及初始化

void Gameend()//游戏结束其中Snakemove会用到Hitwall,Eatitself,Createfood。

1. 创建地图

void Creatmap()//定义创建地图的函数

{

int i;

for(i=0;i<58;i+=2)//打印上下边框

{

Pos(i,0);

printf("■");

Pos(i,26);

printf("■");

}

for(i=1;i<26;i++)//打印左右边框

{

Pos(0,i);

printf("■");

Pos(56,i);

printf("■");

}

}利用好之前定义的Pos函数就可以了。

2. 初始化蛇身以及游戏参数

void Initsnake()//初始化函数

{

sleeptime=300;

score=0;

status=D;

SNAKE *tail;

int i;

tail=(SNAKE*)malloc(sizeof(SNAKE));//从蛇尾开始,头插法,以x,y设定开始的位置//

tail->x=24;

tail->y=5;

tail->next=NULL;

for(i=1;i<=4;i++)//设定整个蛇身体各点的位置

{

head=(SNAKE*)malloc(sizeof(SNAKE));

head->next=tail;

head->x=24+2*i;

head->y=5;

tail=head;

}

while(tail!=NULL)//从头到尾,输出蛇身

{

Pos(tail->x,tail->y);

printf("■");

tail=tail->next;

}

}malloc函数用于动态为指针分配内存空间。其参数为分配空间的大小,返回值为该空间地址。注意这个地址对应void类型的指针,所以一定要用(SNAKE*)这样方式进行强制类型转化。

malloc函数的意义是初始化指针。如果指针不进行初始化,那么就会指向一个没有意义的地址,成为一个野指针,在对指针指向的位置进行读或写操作时,程序就会报错。类似的函数还有new,有兴趣的同学可以查查它们的区别。

3. 检测撞墙行为

int Hitwall()//检测是否撞墙

{

if(head->x==0||head->x==56||head->y==0||head->y==26)return 1;

else

return 0;

}

4. 检测是否碰到自身

int Eatitself()//检测是否碰到自身

{

SNAKE *s;

s=head->next;

while(s->next!=NULL)//利用循环对每个点进行判定

{

if(s->x==head->x&&s->y==head->y)return 1;

else

s=s->next;

}

return 0;

}

5. 创建食物

void Createfood()//定义创建食物的函数

{

SNAKE *food_1;

SNAKE *q;

srand((unsigned)time(NULL));//利用时间获取随机种子

food_1=(SNAKE*)malloc(sizeof(SNAKE));

food_1->x=2*(rand()%26)+2;//利用随机种子获取坐标

food_1->y=rand()%24+1;

q=head;

while(q->next!=NULL)//利用循环对每个点进行判定

{

if(q->x==food_1->x&&q->y==food_1->y) //判断蛇身是否与食物重合

{

free(food_1);

food_1=NULL;//不将地址置为NULL,也会让指针变为野指针

Createfood();

}

q=q->next;

}

Pos(food_1->x,food_1->y);

food=food_1;

printf("■");//打印食物

}对于食物位置的数据,我们同样用SNAKE结构体进行存储,这样可以便于与蛇身进行连接。

因为食物的位置要随机生成,所以我们需要一个随机种子来表征这种随机性。

srand函数在当中,是随机数发生器的初始化函数。其参数只有一个,为随机数产生器的初始值(种子值)。为了防止随机数出现重复,我们常用(unsigned)time(&t)来生成随机种子,原理是使用 time函数来获得系统时间,它的返回值为从 00:00:00 GMT, January 1, 1970 到现在所持续的秒数,然后将time_t型数据转化为(unsigned)型再传给srand函数。当然这还有另外一个用法,不用定义time_t型t变量,即: srand((unsigned) time(NULL)),直接传入一个空指针,因为程序中往往并不需要经过参数获得的数据。

6. 蛇身行动

int Snakemove()//定义蛇身行动的函数

{

SNAKE *nexthead;//蛇将要走到的位置

nexthead=(SNAKE*)malloc(sizeof(SNAKE));

SNAKE *n;

if(status==U)//根据移动方向,计算下一个点的坐标

{

nexthead->x=head->x;

nexthead->y=head->y-1;

nexthead->next=head;

}

else if(status==D)

{

nexthead->x=head->x;

nexthead->y=head->y+1;

nexthead->next=head;

}

else if(status==L)

{

nexthead->x=head->x-2;

nexthead->y=head->y;

nexthead->next=head;

}

else

{

nexthead->x=head->x+2;

nexthead->y=head->y;

nexthead->next=head;

}

head=nexthead;

if(Hitwall())//是否撞墙

{

typelose=1;

return 0;

}

else;

if(Eatitself())//是否咬到自身

{

typelose=2;

return 0;

}

else;

if(head->x==food->x&&head->y==food->y)//如果前方是食物

{

score++;

Createfood();

}

else

{

n=head;

while(n->next->next!=NULL)n=n->next;//将移动到的下一个点打印,同时去掉尾部的点

Pos(n->next->x,n->next->y);

printf(" ");

Pos(head->x,head->y);

printf("■");

free(n->next);

n->next=NULL;

}

return 1;

}

7. 游戏开始及终止

void Gamestart()//开始页面以及初始化

{

system("mode con cols=100 lines=30");

Startpage();//开始页面

Creatmap();//绘制地图

}

void Gameend()//游戏结束

{

system("cls");//清除屏幕

Pos(24,12);

if(typelose==1)

{

printf("对不起,您撞到墙了。游戏结束.");

}

else if(typelose==2)

{

printf("对不起,您咬到自己了。游戏结束.");

}

Pos(24,13);

printf("您的得分是%d\n",score);

}四、完整源码

C语言贪吃蛇源码下载

相关推荐

bt搜索软件
我和黑大佬的365天知乎

bt搜索软件

📅 08-31 👁️ 8457
伴奏音乐制作多少钱一首?除了原创伴奏我们还有另一种选择
我和黑大佬的365天知乎

伴奏音乐制作多少钱一首?除了原创伴奏我们还有另一种选择

📅 09-22 👁️ 9295
日本侵华14年,到底派来多少日军,又阵亡了多少人?
我和黑大佬的365天知乎

日本侵华14年,到底派来多少日军,又阵亡了多少人?

📅 09-29 👁️ 7673