c语言实现贪吃蛇教程

c语言实现贪吃蛇教程效果图如图 nbsp 首先发现组成元素是 实心方块 我们可以百度也可以在我这里直接复制 进编译环境 这个方块是两个字节这个很重要 完成这个小程序基本上我们分以下几步 1 完成所有静态的元素 四周的方块界线 2 绘制蛇 3 使蛇吃东西 nbsp 下面分布进行实现首先完成第一步

效果图如图 

c语言实现贪吃蛇教程

首先发现组成元素是“实心方块”我们可以百度 也可以在我这里直接复制 ▇ 进编译环境 (这个方块是两个字节这个很重要)

完成这个小程序基本上我们分以下几步

1.完成所有静态的元素(四周的方块界线)

2.绘制蛇

3.使蛇吃东西

 

下面分布进行实现

首先完成第一步

/*头文件/ #include<stdio.h> #include<stdlib.h> #include<windows.h> #include<time.h> /*函数声明*/ void muban(); void Pos(int x, int y); /*自定义函数*/ void Pos(int x, int y)//设置光标位置,从哪里开始输出 { COORD pos;//表示一个字符在控制台屏幕上的坐标,左上角(0,0) HANDLE hOutput; pos.X = x; pos.Y = y; hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//返回标准的输入、输出或错误的设备的句柄,也就是获得输入、输出/错误的屏幕缓冲区的句柄 SetConsoleCursorPosition(hOutput, pos); } void muban() { int i; for(i=0;i<=60;i+=2)//方块水平方向占两个字节 { Pos(i,0); printf("▇");//上行 Pos(i,26); printf("▇");//下行 } for(i=0;i<=25;i+=1)//方块竖直方向占1个字节 { Pos(0,i);//左列 printf("▇"); Pos(60,i);//右列 printf("▇"); } } /*主函数/ int main() { muban(); return 0; }

c语言实现贪吃蛇教程

下面我们来描绘蛇,这里要用到结构体指针和链表

主要思想是 一个▇是蛇的一段 然后用链表将它们链接起来

具体的链表和结构体指针可以看下面的文章:(只用掌握最基本的用法即可)

结构体https://blog.csdn.net/zhanghow/article/details/

链表https://blog.csdn.net/govshell/article/details/

指针https://blog.csdn.net/cyh/article/details/(这篇文章讲的很棒,配合结构体食用)

接下来继续撸代码

void initSnake() { snake *tail;//尾指针 snake *head;//头指针 tail = (snake*)malloc(sizeof(snake));//以snake结构体的形式开辟一块新的内存,内存中的数据是新的,用tail指向这个结构体 tail ->x=30;//因为实心方块宽度为2个单位长度,所以必须为偶数 tail ->y=10; tail ->next=NULL; for(i = 0;i<4;i++) { head=(snake*)malloc(sizeof(snake));//以snake结构体的形式开辟一块新的内存,内存中的数据是新的,用head指向这个结构体 head->next=tail;//将 tail=head;//将尾指针传向下一个头指针 } }

比较难理解的是这段尾插法,如果不会的可以去看这篇https://blog.csdn.net/viafcccy/article/details/

这里下面的代码

typedef struct Snake//相当于蛇一个节点 { int x;//横坐标 int y;//纵坐标 struct Snake *next; }snake;

等价于

struct Snake { int x;//横坐标 int y;//纵坐标 struct Snake *next; }; struct Snake snake;

关于typedef看这篇https://blog.csdn.net/viafcccy/article/details/

下面完成蛇身的打印

其中第一遍的代码是这样

void initSnake() { int i; snake *tail;//尾指针 snake *head;//头指针 tail = (snake*)malloc(sizeof(snake));//以snake结构体的形式开辟一块新的内存,内存中的数据是新的,用tail指向这个结构体 tail ->x=30;//因为实心方块宽度为2个单位长度,所以必须为偶数 tail ->y=10; tail ->next=NULL; for(i = 0;i<4;i++) { head=(snake*)malloc(sizeof(snake));//以snake结构体的形式开辟一块新的内存,内存中的数据是新的,用head指向这个结构体 head->next=tail;//链接成链 head->x=30+2*i;//下一节点的位置 head->y=10; tail=head;//将尾指针传向下一个头指针 }

 

结果是

c语言实现贪吃蛇教程

我们错在原来蛇是从右向左打印了8个单位 但是应为固定输出press any keyt continues将三个实心方块挡住了,于是将代码修改

/*头文件/ #include<stdio.h> #include<stdlib.h> #include<windows.h> #include<time.h> /*函数声明*/ void muban();//打印四周的边界 void Pos(int x, int y);//设置光标输出位置 void initSnake();//初始化蛇身,将结构体中的坐标读取打印实心方块 /*结构体*/ typedef struct Snake//将蛇身的位置存入结构体,相当于蛇身上的一个实心方块 { int x;//横坐标 int y;//纵坐标 struct Snake *next; }snake; /*自定义函数*/ void Pos(int x, int y)//设置光标位置,从哪里开始输出 { COORD pos;//表示一个字符在控制台屏幕上的坐标,左上角(0,0) HANDLE hOutput; pos.X = x; pos.Y = y; hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//返回标准的输入、输出或错误的设备的句柄,也就是获得输入、输出/错误的屏幕缓冲区的句柄 SetConsoleCursorPosition(hOutput, pos); } void muban() { int i; for(i=0;i<=60;i+=2)//方块水平方向占两个单位 { Pos(i,0); printf("▇");//上行 Pos(i,26); printf("▇");//下行 } for(i=0;i<=25;i+=1)//方块垂直方向占1个单位 { Pos(0,i);//左列 printf("▇"); Pos(60,i);//右列 printf("▇"); } } void initSnake() { int i; snake *tail;//尾指针 snake *head;//头指针 tail = (snake*)malloc(sizeof(snake));//以snake结构体的形式开辟一块新的内存,内存中的数据是新的,用tail指向这个结构体 tail ->x=30;//因为实心方块宽度为2个单位长度,所以必须为偶数 tail ->y=10; tail ->next=NULL; for(i = 1;i<=4;i++) { head=(snake*)malloc(sizeof(snake));//以snake结构体的形式开辟一块新的内存,内存中的数据是新的,用head指向这个结构体 head->next=tail;//链接成链 head->x=30-2*i;//下一节点的位置 head->y=10; tail=head;//将尾指针传向下一个头指针 } //遍历打印出来 while(tail->next!=NULL) { Pos(tail->x,tail->y); printf("▇"); tail = tail->next; } } /*主函数/ int main() { muban(); initSnake(); return 0; }

c语言实现贪吃蛇教程

这样我用四个永远紧紧相连的方块构成了蛇的身体,下面我们来生成食物

思路是随机生成两个随机数使x,y分别满足在边界内,但是x有一个要求就是要是偶数这个和实心方块两个字节有关,我们要避免下图的情况产生

c语言实现贪吃蛇教程

void creatFood()//创建食物 { snake *food;//创造一个食物 food=(snake*)malloc(sizeof(snake)); srand((unsigned int)time(NULL));//随着时间变化,产生不一样种子,就会得到没规律的食物 while(food->x%2!=0) { food->x=rand()%56+2; } food->y=rand()%23+1; //上面虽然解决了食物不会出现在城墙里,没有考虑食物出现在蛇本身里面 p=head;//用p来遍历 while(p!=NULL)//解决食物出现在蛇本身 { if(food->x==p->x&&food->y==p->y) { free(food); creatFood(); } p=p->next; } Pos(food->x,food->y); food1=food;//food1用来标记的作用 printf("▇"); }

关于产生随机数可以看这篇文章https://blog.csdn.net/viafcccy/article/details/

于是我们下一步就是要做到我们按键蛇会动我们使用头文件windows.h,具体看这篇https://blog.csdn.net/viafcccy/article/details/

这里介绍一下遍历 就是将所有链表中的数据访问一遍 通常是打印出来

蛇的移动主要通过获取键值,然后如下操作

c语言实现贪吃蛇教程

c语言实现贪吃蛇教程

c语言实现贪吃蛇教程

但是我们要将1的位置打印空格 否则实心方块不会消失 但是这样打印时会有光标始终跟着蛇尾 因此需要在外面打印一个东西让光标绝大部分时间在外面 只有一个瞬间在蛇尾我们就不会看到了 

 void snakeMove() { snake *nexthead; nexthead=(snake*)malloc(sizeof(snake)); if(status=='R') { nexthead->x=head->x+2; nexthead->y=head->y; if(nexthead->x==food1->x&&nexthead->y==food->y) { nexthead->next=head; head=nexthead; p=head;//遍历 while(p!=NULL) { Pos(p->x,p->y); printf("▇"); p=p->next; } } else { nexthead->next=head; head=nexthead; p=head;//遍历 while(p->next->next!=NULL) { Pos(p->x,p->y); printf("▇"); p=p->next; } Pos(p->next->x,p->next->y); printf(" ");//会带来一个光标闪烁 Pos(70,20); printf("您的分数是:%d",score); free(p->next); p->next=NULL; } if(status=='L')//向左走 { nexthead->x=head->x-2; nexthead->y=head->y; if(nexthead->x==food1->x&&nexthead->y==food1->y)//吃掉了食物 { nexthead->next=head; head=nexthead; p=head;//p用来从头遍历,打印方块 while(p!=NULL) { Pos(p->x,p->y); printf("▇"); p=p->next; }//吃掉了食物得创造 score=score+add; creatFood(); } else//没有食物 { nexthead->next=head; head=nexthead; p=head;//p用来从头遍历,打印方块 while(p->next->next!=NULL) { Pos(p->x,p->y); printf("▇"); p=p->next; } Pos(p->next->x,p->next->y); printf(" "); Pos(70,20);//解决办法 printf("您的分数是:%d",score); free(p->next); p->next=NULL; } } if(status=='U')//向上走 { nexthead->x=head->x; nexthead->y=head->y-1; if(nexthead->x==food1->x&&nexthead->y==food1->y)//吃掉了食物 { nexthead->next=head; head=nexthead; p=head;//p用来从头遍历,打印方块 while(p!=NULL) { Pos(p->x,p->y); printf("▇"); p=p->next; }//吃掉了食物得创造 score=score+add; creatFood(); } else//没有食物 { nexthead->next=head; head=nexthead; p=head;//p用来从头遍历,打印方块 while(p->next->next!=NULL) { Pos(p->x,p->y); printf("▇"); p=p->next; } Pos(p->next->x,p->next->y); printf(" "); Pos(70,20);//解决办法 printf("您的分数是:%d",score); free(p->next); p->next=NULL; } } if(status=='D')//向下走 { nexthead->x=head->x; nexthead->y=head->y+1; if(nexthead->x==food1->x&&nexthead->y==food1->y)//吃掉了食物 { nexthead->next=head; head=nexthead; p=head;//p用来从头遍历,打印方块 while(p!=NULL) { Pos(p->x,p->y); printf("▇"); p=p->next; }//吃掉了食物得创造 score=score+add; creatFood(); } else//没有食物 { nexthead->next=head; head=nexthead; p=head;//p用来从头遍历,打印方块 while(p->next->next!=NULL) { Pos(p->x,p->y); printf("▇"); p=p->next; } Pos(p->next->x,p->next->y); printf(" "); Pos(70,20);//解决办法 printf("您的分数是:%d",score); free(p->next); p->next=NULL; } } Sleep(sleepTime);//蛇移动的速度,里面是毫秒,越大速度越慢 status=reDirection();//判别下方向先 if(crossWall()==1||eatSelf()==1) //exit(0);//直接把程序关闭了 endleap=1; return endleap; } int crossWall()//判断蛇有没穿透墙 { if(head->x==0||head->y==0||head->x==60||head->y==25) leap=1; return leap; } int eatSelf()//判断是否咬到了自己 { snake *q;//遍历的 q=head->next; while(q!=NULL) { if(q->x==head->x&&head->y==q->y) leap=1; q=q->next; } return leap; }

下面我们要解决gameover的判断

贪吃蛇结束就两种情况

1)撞到墙壁

2)咬到自己

int crossWall()//判断蛇有没撞墙 { if(head->x==0||head->y==0||head->x==60||head->y==25) leap=1; return leap; }
int eatSelf()//判断是否咬到了自己 { snake *q;//遍历的 q=head->next; while(q!=NULL) { if(q->x==head->x&&head->y==q->y) leap=1; q=q->next; } return leap; }

最后经过优化的源代码在这里

/*头文件/ #include<stdio.h> #include<stdlib.h> #include<windows.h> #include<time.h> /*函数声明/ void Pos(int x, int y);//光标位置设定 void muban();//打印模板 void initSnake();//蛇身的初始化 void creatFood();//创建食物 char reDirection();//识别方向 int snakeMove();//蛇移动 int crossWall();//不能穿墙 int eatSelf();//不能吃自己 /结构体*/ typedef struct Snake//相当于蛇一个节点 { int x;//横坐标 int y;//纵坐标 struct Snake *next; }snake; /*全局变量/ snake *head;//头指针 snake *p;//用来遍历 snake *food1;//用来标记的 char status='L';//初始方向的状态,解决开始会动的问题 int score=0;//分数 int add=10;//一个食物的分 int leap=0;//用来标志是否结束,0没有,1代表蛇死了代表结束了 int endleap=0;//结束标志 1就是结束 int sleepTime=500; /*自定义函数/ void initSnake()//蛇身初始化,给定一个长度,用结构体表示是蛇的骨架,真正要显示出来是打印▇ { int i; snake *tail;//尾指针 tail=(snake*)malloc(sizeof(snake));//第一个节点/头结点 tail->x=30;//2的倍数,因为方块的长是两个单位 tail->y=10;//1个单位 tail->next=NULL; for(i=1;i<=4;i++)//尾插法 { head=(snake*)malloc(sizeof(snake));//申请一个节点 head->next=tail;//连接成链 head->x=30-2*i;//下一个节点的位置 head->y=10; tail=head; } //遍历打印出来 while(tail!=NULL) { Pos(tail->x,tail->y); printf("▇"); tail=tail->next; } } char reDirection()//识别用户按下的键值 保留方向值 { if(GetAsyncKeyState(VK_F7))//热键 { if(sleepTime>300)//最多减到300 { sleepTime-=50;//每次减50 add++;//每次食物加1分 } } if(GetAsyncKeyState(VK_F8)) { if(sleepTime<800)//最多加到800 { sleepTime+=50;//每次加50 add--;//每次食物减1分 } } if(GetAsyncKeyState(VK_UP)&&status!='D') status='U'; if(GetAsyncKeyState(VK_DOWN)&&status!='U') status='D'; if(GetAsyncKeyState(VK_LEFT)&&status!='R') status='L'; if(GetAsyncKeyState(VK_RIGHT)&&status!='L') status='R'; return status; } void Pos(int x, int y)//设置光标位置,从哪里开始输出 { COORD pos;//表示一个字符在控制台屏幕上的坐标,左上角(0,0) HANDLE hOutput; pos.X = x; pos.Y = y; hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//返回标准的输入、输出或错误的设备的句柄,也就是获得输入、输出/错误的屏幕缓冲区的句柄 SetConsoleCursorPosition(hOutput, pos); } void creatFood()//创建食物 { snake *food;//创造一个食物 food=(snake*)malloc(sizeof(snake)); srand((unsigned int)time(NULL));//随着时间变化,产生不一样种子,就会得到没规律的食物 while(food->x%2!=0) { food->x=rand()%56+2; } food->y=rand()%23+1; //上面虽然解决了食物不会出现在城墙里,没有考虑食物出现在蛇本身里面 p=head;//用p来遍历 while(p!=NULL)//解决食物出现在蛇本身 { if(food->x==p->x&&food->y==p->y) { free(food); creatFood(); } p=p->next; } Pos(food->x,food->y); food1=food;//food1用来标记的作用 printf("▇"); Pos(70,20);//解决有光标闪烁的办法 printf("您的分数是:%d",score); } void muban() { int i; for(i=0;i<=60;i+=2)//方块水平方向占两个单位 { Pos(i,0); printf("▇");//上行 Pos(i,26); printf("▇");//下行 } for(i=0;i<=25;i+=1)//方块垂直方向占1个单位 { Pos(0,i);//左列 printf("▇"); Pos(60,i);//右列 printf("▇"); } } int snakeMove() { snake *nexthead; nexthead=(snake*)malloc(sizeof(snake)); if(status=='R')//向右走 { nexthead->x=head->x+2; nexthead->y=head->y; if(nexthead->x==food1->x&&nexthead->y==food1->y)//吃掉了食物 { nexthead->next=head; head=nexthead; p=head;//p用来从头遍历,打印方块 while(p!=NULL) { Pos(p->x,p->y); printf("▇"); p=p->next; }//吃掉了食物得创造 score=score+add; creatFood(); } else//没有食物 { nexthead->next=head; head=nexthead; p=head;//p用来从头遍历,打印方块 while(p->next->next!=NULL) { Pos(p->x,p->y); printf("▇"); p=p->next; } Pos(p->next->x,p->next->y); printf(" ");//会带来一个光标闪烁 Pos(70,20);//解决办法 printf("您的分数是:%d",score); free(p->next); p->next=NULL; } } if(status=='L')//向左走 { nexthead->x=head->x-2; nexthead->y=head->y; if(nexthead->x==food1->x&&nexthead->y==food1->y)//吃掉了食物 { nexthead->next=head; head=nexthead; p=head;//p用来从头遍历,打印方块 while(p!=NULL) { Pos(p->x,p->y); printf("▇"); p=p->next; }//吃掉了食物得创造 score=score+add; creatFood(); } else//没有食物 { nexthead->next=head; head=nexthead; p=head;//p用来从头遍历,打印方块 while(p->next->next!=NULL) { Pos(p->x,p->y); printf("▇"); p=p->next; } Pos(p->next->x,p->next->y); printf(" "); Pos(70,20);//解决办法 printf("您的分数是:%d",score); free(p->next); p->next=NULL; } } if(status=='U')//向上走 { nexthead->x=head->x; nexthead->y=head->y-1; if(nexthead->x==food1->x&&nexthead->y==food1->y)//吃掉了食物 { nexthead->next=head; head=nexthead; p=head;//p用来从头遍历,打印方块 while(p!=NULL) { Pos(p->x,p->y); printf("▇"); p=p->next; }//吃掉了食物得创造 score=score+add; creatFood(); } else//没有食物 { nexthead->next=head; head=nexthead; p=head;//p用来从头遍历,打印方块 while(p->next->next!=NULL) { Pos(p->x,p->y); printf("▇"); p=p->next; } Pos(p->next->x,p->next->y); printf(" "); Pos(70,20);//解决办法 printf("您的分数是:%d",score); free(p->next); p->next=NULL; } } if(status=='D')//向下走 { nexthead->x=head->x; nexthead->y=head->y+1; if(nexthead->x==food1->x&&nexthead->y==food1->y)//吃掉了食物 { nexthead->next=head; head=nexthead; p=head;//p用来从头遍历,打印方块 while(p!=NULL) { Pos(p->x,p->y); printf("▇"); p=p->next; }//吃掉了食物得创造 score=score+add; creatFood(); } else//没有食物 { nexthead->next=head; head=nexthead; p=head;//p用来从头遍历,打印方块 while(p->next->next!=NULL) { Pos(p->x,p->y); printf("▇"); p=p->next; } Pos(p->next->x,p->next->y); printf(" "); Pos(70,20);//解决办法 printf("您的分数是:%d",score); free(p->next); p->next=NULL; } } Sleep(sleepTime);//蛇移动的速度,里面是毫秒,越大速度越慢 status=reDirection();//判别下方向先 if(crossWall()==1||eatSelf()==1) //exit(0);//直接把程序关闭了 endleap=1; return endleap; } int crossWall()//判断蛇有没穿透墙 { if(head->x==0||head->y==0||head->x==60||head->y==25) leap=1; return leap; } int eatSelf()//判断是否咬到了自己 { snake *q;//遍历的 q=head->next; while(q!=NULL) { if(q->x==head->x&&head->y==q->y) leap=1; q=q->next; } return leap; } //打印食物的时候会出现光标,解决办法就是引开它 /*主函数*/ int main() { muban();//打印模板 initSnake();//初始化蛇 creatFood();//创建食物 while(1)//死循环,让蛇一直动起来,直到蛇死了 { if(snakeMove()==1)//判断是否结束 { Pos(70,23); printf("蛇死了"); system("pause");//用来暂停 Pos(70,24);//解决press any key to continue 在该地点打印 大家试下 break; } } printf("是否继续游戏,y or n:");//y 继续 if(getch()=='y')//重新游戏 { //蛇一开始就死了,因为全局变量没有恢复原值,仍然保留上一局的值 status='L';//初始方向的状态,解决开始会动的问题 score=0;//分数 add=10;//一个食物的分 leap=0;//用来标志是否结束,0没有,1代表蛇死了代表结束了 endleap=0;//结束标志 1就是结束 sleepTime=500; system("cls");//清理屏幕 main();//自己调用自己 看不一样的编译器,vc6.0允许调用自己 } if(getch()=='n') { Pos(70,25);//定一个位置,再打印press exit(0);//退出程序 } return 0; } //蛇的速度变化,每个食物的分数增加 //是否继续游戏 //按键的作用

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/231639.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 【5G学习】小区搜索——SSB[通俗易懂]

    【5G学习】小区搜索——SSB[通俗易懂]文章目录前言一、SSB突发集(SSBBurstSet)二、SSB构成2.2SSB结构2.2PSSSSS2.3PBCH三、SSB突发集图样四、流程总结前言NR同步块(SSB)包括PSS、SSS和PBCH。PBCH中包含解调参考信号(DM-RS)。UE在接入NR系统时,首先要检测PSS和SSS以获得下行时频同步以及PCID,然后对PBCH进行解码。PBCH中包括主信息块(MIB)和其他与SSB传输时间有关的信息(additionaltimingrelatedPBCHpayload.

    2022年6月16日
    44
  • matlab做图像_matlab语言基础

    matlab做图像_matlab语言基础注:读取图像的路径自己设置。图像文件的查询%imfinfo()用于获取一张图片的具体信息info=imfinfo(‘E:\a_matlab_file\picture\longmao.jpg’);disp(info);图像的读取img_route=’E:\a_matlab_file\picture\***.jpg’;A=imread(img_route);set(0,’de…

    2022年9月26日
    5
  • Oracle19c安装教程及PLSQL配置常见错误解决办法

    Oracle19c安装教程及PLSQL配置常见错误解决办法本人电脑上也装了不少比较难以安装的程序,而且也亲身破解了一些软件,自己以前也安装过MySQL和DB2,原以为Oracle也差不多,直到我亲身经历了,我才知道什么是痛苦。帅帅本人在经历了长时间的折磨之后终于把Oracle安装完毕,可谓被折磨得一塌糊涂,暗无天日。或许这也是程序员的快乐之一吧(ง•_•)ง目录&下面是Oracle的一些安装步骤及安装过程中常见错误的修正…

    2022年5月20日
    477
  • 高光谱图像分类综述_高光谱图像样本进行扩增

    高光谱图像分类综述_高光谱图像样本进行扩增PCA-PrincipleComponentAnalysis主成分分析ICA-IndependentComponentAnalysis独立成分分析NWFE-Nonparametric

    2022年8月5日
    5
  • js 数组转json和json转数组

    js 数组转json和json转数组js数组转json和json转数组数组转json串json字符串转数组数组转json串vararr=[1,2,3,{a:1}];JSON.stringify(arr);json字符串转数组varjsonStr='[1,2,3,{“a”:1}]’;JSON.parse(jsonStr);

    2022年6月21日
    29
  • JavaBean的作用「建议收藏」

    JavaBean的作用「建议收藏」javaBean 编辑JavaBean是一种JAVA语言写成的可重用组件。为写成JavaBean,类必须是具体的和公共的,并且具有无参数的构造器。JavaBean通过提供符合一致性设计模式的公共方法将内部域暴露成员属性,long和class方法获取。众所周知,属性名称符合这种模式,其他Java类可以通过自省机制发现和操作这些JavaBean的属性。javaBean在MVC设计…

    2022年7月17日
    11

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号