当前位置: 首页 > news >正文

基于51单片机的贪吃蛇游戏Protues仿真设计

目录

1 系统设计目的

2 系统实现功能

3 系统硬件设计

3.1系统设计框图

3.2 液晶显示模块LCD12864

3.3 按键输入模块

3.4 时钟电路和复位电路

4 系统软件设计

4.1系统软件流程

4.2 游戏引擎模块程序设计

4.3 显示模块程序设计

4.4 输入处理模块程序设计

5 系统仿真结果

5.1 游戏引擎模块的实现

5.2 显示模块功能的实现

5.3 输入处理模块的实现


1 系统设计目的

       设计一个基于51单片机的贪吃蛇游戏,可以帮助学习者掌握硬件控制相关知识、学习游戏开发和代码实现,提高编程能力和解决问题的能力,同时培养团队合作精神和创新意识。

    (1)掌握基于51单片机的硬件控制相关知识,包括输入输出口的操作、中断处理、定时器/计数器等模块的使用。

    (2)学习贪吃蛇游戏的实现方法,掌握游戏逻辑的设计和代码实现,加深对面向对象编程的理解。

    (3)提高编程能力和解决问题的能力,通过设计和编写程序,发现和解决软件和电路方面的问题。

    (4)培养团队合作精神和创新意识,多思考和尝试不同的解决方案,共同完成项目。

    (5)加深对嵌入式系统和游戏开发的了解,拓展相关领域的技能。

2 系统实现功能

       本项目旨在设计和实现一个基于51单片机的贪吃蛇游戏,使用LCD12864显示屏作为游戏界面,通过矩阵按键控制蛇的移动,并增加暂停/启动游戏、显示已吃的食物数量等功能。以下是该项目的详细内容和功能要求:

       (1)游戏界面设计:

       使用LCD12864显示屏作为游戏界面,具有较高的分辨率,能够显示游戏界面、蛇、食物等元素。游戏界面应具备良好的界面布局,清晰明了,易于辨认。

       (2)蛇的控制:

       运用矩阵按键的4个按键分别控制蛇的上、下、左、右移动。当蛇吃到食物时,长度增加并重新生成食物,结束时显示已吃的食物数量。蛇的移动速度可以逐渐加快,增加游戏难度。

       (3)暂停/启动游戏功能:

       设计一个特定的按键,用于暂停或启动游戏。当按下暂停按键时,游戏暂停,蛇停止移动,游戏界面保持静止。再次按下该按键时,游戏继续进行,恢复蛇的移动。

       (3)食物显示功能:

       在游戏界面中增加显示当前已吃的食物数量的功能。每次蛇吃到食物时,更新并显示已吃的食物数量。

3 系统硬件设计

3.1系统设计框图

       本设计由控制器、液晶显示模块、按键输入模块、时钟电路和复位电路等5部分组成。控制器是系统的核心,通过IO口控制液晶显示模块,实现游戏画面的显示和游戏状态的更新,同时也可以接收按键输入模块的信号,根据使用者的操作控制蛇的移动和游戏速度等参数;液晶显示模块LCD12864用于显示游戏界面和相关信息;按键输入模块用于接收用户的操作输入,通过按下不同的按钮,用户可以控制蛇的移动方向和游戏速度等。时钟电路是为主控芯片提供稳定的时钟信号,通过确定的振荡频率,主控芯片可以按照时序进行正常的工作和指令执行;复位电路可以使用复位按钮或者上电复位电路,通过将主控芯片的复位引脚拉低一段时间来实现复位操作。系统设计框图如图3.1所示。

3.2 液晶显示模块LCD12864

       液晶显示模块用于显示游戏界面和相关信息,一般采用16x2或128x64字符液晶显示屏。通过控制芯片的指令和数据,可以在屏幕上绘制游戏区域、分数以及游戏状态等内容,为用户提供良好的视觉体验。电路原理图如图3.2所示。   

3.3 按键输入模块

       按键输入模块用于接收用户的操作输入,通过使用矩阵式按键阵列,按下不同的按钮,用户可以控制蛇的移动方向和游戏速度等。在硬件设计中,需要考虑防抖处理,以避免因按键抖动产生误操作。电路原理图如图3.3所示。

3.4 时钟电路和复位电路

       时钟电路是为主控芯片提供稳定的时钟信号,常使用晶体振荡器。通过确定的振荡频率,主控芯片可以按照时序进行正常的工作和指令执行。根据系统需要,可以选择合适的晶体频率,通常使用10MHz或者12MHz晶体。

       复位电路用于在系统上电或者复位时将主控芯片初始化为一个已知的状态,以确保系统在启动时正常工作。复位电路可以使用复位按钮或者上电复位电路,通过将主控芯片的复位引脚拉低一段时间来实现复位操作。电路原理图如图3.4所示。

4 系统软件设计

4.1系统软件流程

        基于51单片机的贪吃蛇游戏系统的软件部分包括四个主要模块,分别是游戏引擎模块、显示模块、输入处理模块和计时模块。游戏引擎模块是贪吃蛇游戏的核心,它负责控制游戏的状态和逻辑;显示模块主要负责将游戏的状态和画面显示在液晶屏上;输入处理模块负责读取用户按键操作的输入,并将其传递给游戏引擎模块进行处理;计时模块主要负责控制游戏的速度和帧率,为游戏加入时间的概念。基于51单片机的贪吃蛇游戏系统的软件部分通过游戏引擎、显示、输入处理和计时等模块的协同工作,为用户提供了一个有趣、稳定和流畅的游戏体验。总体软件流程图如图4.1所示。

4.2 游戏引擎模块程序设计

       游戏引擎模块是贪吃蛇游戏的核心,它负责控制游戏的状态和逻辑。在每一个游戏循环中,它根据当前蛇的状态和用户的操作来更新蛇的位置、食物的位置,检测蛇是否撞墙或者咬到自己的身体,计算得分等等。游戏引擎模块也负责处理游戏的初始化和结束逻辑,使得游戏在启动和结束时能够正常的运行和退出。游戏引擎模块程序设计流程图如图4.2所示:

游戏引擎模块部分程序如下所示:

void Game_Play()					//游戏的具体过程,也是贪吃蛇算法的关键部分
{uchar n;InitRandom(TL0);food.yes=1;			//1表示需要出现新事物,0表示已经存在食物尚未吃掉snake.life=0;					//表示蛇还活着snake.direction=DOWN;snake.x[0]=6;snake.y[0]=6;snake.x[1]=3;snake.y[1]=6;snake.node=2;Lcd_Show_Score();				//显示分数Lcd_Show_Title();			   	//显示标题while(1){if(food.yes==1){while(1){food.x=Random()*85+3;food.y=Random()*55+3;		//获得随机数while(food.x%3!=0)food.x++;while(food.y%3!=0)food.y++;for(n=0;n<snake.node;n++)	//判断产生的食物坐标是否和蛇身重合{if((food.x==snake.x[n])&&(food.y==snake.y[n]))break;}if(n==snake.node){food.yes=0;break;			//产生有效的食物坐标}}}if(food.yes==0){Lcd_Rectangle(food.x,food.y,food.x+2,food.y+2,1);}	if(Run==0){for(n=snake.node-1;n>0;n--){snake.x[n]=snake.x[n-1];snake.y[n]=snake.y[n-1];}	switch(snake.direction){case DOWN:snake.x[0]+=3;break;case UP:snake.x[0]-=3;break;case RIGHT:snake.y[0]-=3;break;case LEFT:snake.y[0]+=3;break;default:break;}for(n=3;n<snake.node;n++)	//从第三节开始判断蛇头是否咬到自己{if(snake.x[n]==snake.x[0]&&snake.y[n]==snake.y[0]){Game_Over();snake.life=1;break;}}}if(snake.x[0]<3||snake.x[0]>=90||snake.y[0]<3||snake.y[0]>=60)//判蛇头是否撞到墙壁{Game_Over();snake.life=1;}if(snake.life==1)break;					//蛇死,则跳出while(1)循环if(snake.x[0]==food.x&&snake.y[0]==food.y)	//判蛇是否吃到食物{Lcd_Rectangle(food.x,food.y,food.x+2,food.y+2,0);	//消隐食物snake.x[snake.node]=200;snake.y[snake.node]=200;//产生蛇新的节坐标先放在看不见的位置snake.node++;			//蛇节数加1food.yes=1;				//食物标志置1if(++Score>=PASSSCORE){Lcd_Show_Score();Game_Over();break;}Lcd_Show_Score();}for(n=0;n<snake.node;n++){Lcd_Rectangle(snake.x[n],snake.y[n],snake.x[n]+2,snake.y[n]+2,1);}							//根据蛇的节数画出蛇Delay(Speed*1000);Lcd_Rectangle(snake.x[snake.node-1],snake.y[snake.node-1],snake.x[snake.node-1]+2,snake.y[snake.node-1]+2,0);switch(KeyBuffer){case FUNC:KeyBuffer=0;if(++Speed>=10)Speed=1;Lcd_Show_Title();break;case DOWN:				//下KeyBuffer=0;if(snake.direction!=UP)snake.direction=DOWN;break;case UP:	  			//上KeyBuffer=0;if(snake.direction!=DOWN)snake.direction=UP;break;case RIGHT:		  		//右KeyBuffer=0;if(snake.direction!=LEFT)snake.direction=RIGHT;break;case LEFT:				//左KeyBuffer=0;if(snake.direction!=RIGHT)snake.direction=LEFT;break;default:break;}			}
}

4.3 显示模块程序设计

       显示模块主要负责将游戏的状态和画面显示在液晶屏上。它通过调用液晶屏的相关API,绘制出游戏区域、蛇和食物等图形元素,根据游戏引擎模块返回的数据更新分数和其他游戏状态信息。液晶屏的分辨率和色彩深度等参数会影响显示效果,所以在开发时需要根据硬件选型和资源需求进行平衡。显示模块程序设计流程图如图4.3所示:

显示模块部分程序如下所示:

void Lcd_Show_Board()				//LCD显示墙壁函数
{uchar n;for(n=0;n<31;n++){Lcd_Rectangle(3*n,0,3*n+2,2,1);}for(n=0;n<21;n++){Lcd_Rectangle(0,3*n,2,3*n+2,1);Lcd_Rectangle(90,3*n,92,3*n+2,1);		}
}
void Lcd_Show_Title()				//液晶显示贪吃蛇汉字
{Lcd_Show_String(7,0,"贪"); 		//显示汉字Lcd_Show_String(7,1,"吃");Lcd_Show_String(7,2,"蛇");
}

4.4 输入处理模块程序设计

      输入处理模块负责读取用户按键操作的输入,并将其传递给游戏引擎模块进行处理。根据设计,它可以通过矩阵按键扫描,实现对四个方向的控制和其他额外的功能键,比如开始、暂停、调速等命令。输入处理模块需要防止按键的抖动和误操作,因此一般采用扫描或者中断的方式实现。显示模块程序设计流程图如图4.4所示,输入处理模块部分程序如下所示。

uchar KeyBoard()				/* 反转法键盘扫描 */
{uchar temp1,temp2,temp,a=0;P1=0xf0;						/* 输入行值(或列值) */Delay_MS(1) 	;				/* 延时 */temp1=P1;						/* 读列值(或行值) */P1=0xff;Delay_MS(1);				/* 延时 */P1=0x0f;						/* 输入列值(或行值) */Delay_MS(1) ;				/* 延时 */	temp2=P1;						/* 读行值(或列值) */P1=0xff;temp=(temp1&0xf0)|(temp2&0xf);	/* 将两次读入数据组合 */switch(temp)					/* 通过读入数据组合判断按键位置 */{		case 0xdd :a=20;break; // 	按键上case 0x7d :a=40;break;// 按键下case 0xbe :a=30;break;	//  按键左case 0xbb :a=10;break;	//  按键右default :a=0;}return a;						/* 返回按键值 */
}

5 系统仿真结果

5.1 游戏引擎模块的实现

       游戏引擎模块是贪吃蛇游戏的核心,它负责控制游戏的状态和逻辑。系统开始时,进入游戏运行界面。效果如图5.1所示:

5.2 显示模块功能的实现

       液晶显示模块用于显示游戏界面和相关信息,可以在屏幕上绘制游戏区域、分数以及游戏状态等内容,实现效果如图5.2所示。

5.3 输入处理模块的实现

输入处理模块负责读取用户按键操作的输入,可以通过矩阵按键扫描,实现对四个方向的控制和其他额外的功能键,比如开始、暂停等命令实现效果如图5.3所示。

演示视频:基于51单片机的贪吃蛇游戏设计演示视频-CSDN直播

 完整代码:

#include<reg51.h>					//加载头文件			
#include<intrins.h>
#define uchar unsigned char		 	//宏定义
#define uint unsigned int
#define ulong unsigned long
#define A 48271L					//参数宏定义  					
#define M 2147483647L
#define Q (M/A)
#define R (M%A)
#define N 25													
#define FUNC 1
#define UP 2
#define DOWN 3
#define LEFT 4
#define RIGHT 5
#define PASSSCORE 20				//预定义过关成绩
#define SHORT_ON_DITHERING_COUNTER 3//定义短按按下去抖时间
#define SHORT_OFF_DITHERING_COUNTER 3//定义短按松开去抖时间,一般与短按按下去抖时间相同
#define LCD_DATA P0					//液晶数据口定义
sbit LCD_RS=P2^0; 					//液晶并行的指令/数据选择信号, H数据, L命令
sbit LCD_RW=P2^1; 					//液晶并行读写选择信号, H读, L写
sbit LCD_EN=P2^2; 					//液晶并行使能端, H有效, L无效
sbit KEY_UP=P3^4;					//按键上
sbit KEY_RIGHT=P3^5;				//按键右
sbit KEY_LEFT=P3^6;	 				//按键左
sbit KEY_DOWN=P3^7;					//按键下
static ulong Seed=1;				//变量声明
bit Run=0;
uchar Flag=0;
uchar Score=0;
uchar Speed=5;
uchar KeyBuffer=0;
code uint MaskTab[]={				//为加速逻辑运算而设置的掩码表,这是以牺牲空间而换取时间的办法
0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,
0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000};
struct Food
{uchar x;uchar y;uchar yes;
}food;								//食物结构体
struct Snake
{uchar x[N];uchar y[N];uchar node;uchar direction;uchar life;
}snake;								//蛇结构体
double Random()						//伪随机数发生器
{long TmpSeed;TmpSeed=A*(Seed%Q)-R*(Seed/Q);if(TmpSeed>=0)Seed=TmpSeed;elseSeed=TmpSeed+M;return (double)Seed/M;
}
void InitRandom(ulong InitVal)		//为伪随机数发生器播种
{Seed=InitVal;
}
void Delay(uint t)					//延时子程序
{  uint i,j;for(i=0;i<t;i++)for(j=0;j<10;j++);    
}
void Delay_MS(uint z) 				//z*1MS延时函数
{uint x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);
}
void Timer_Init() 					//定时器初始化
{TMOD=0x00;						//定时器工作方式TH0=0;	 						//定时器赋初值TL0=0;ET0=1;	   						//允许定时器0中断EA=1;						   	//开总中断TR0=1;							//定时器0启动
}
void Lcd_W_Com(uchar com)			//液晶写指令函数
{  LCD_RS=0;LCD_RW=0;LCD_EN=0;_nop_();  _nop_();LCD_DATA=com;_nop_(); _nop_();LCD_EN=1;_nop_();  _nop_();LCD_EN=0;
}
void Lcd_W_Dat(uchar dat)			//液晶写数据函数
{  LCD_RS=1;LCD_RW=0;LCD_EN=0;_nop_();  _nop_(); LCD_DATA=dat;LCD_EN=1;_nop_();_nop_();LCD_EN=0;
}
uchar Lcd_R_Dat()					//液晶读数据函数
{uchar Temp;LCD_DATA=0xff;LCD_RS=1;LCD_RW=1;LCD_EN=1;_nop_();Temp=LCD_DATA;LCD_EN=0;return Temp;
}
void Lcd_Show_String(uchar x,uchar y,uchar *Str)	//液晶在某个位置显示字符串函数
{if((y>3)||(x>7))return;						//如果指定位置不在显示区域内,则不做任何写入直接返回EA=0;	 						//关总中断switch(y){case 0:				 		//第一行Lcd_W_Com(0x80+x);break;case 1:		 				//第二行Lcd_W_Com(0x90+x);break;				case 2:		  				//第三行Lcd_W_Com(0x88+x);break;case 3:				 		//第四行Lcd_W_Com(0x98+x);break;}while(*Str>0){  Lcd_W_Dat(*Str);			//写入字符串Str++;     }EA=1;							//开总中断
}
void Lcd_PutPixel(uchar x,uchar y,uchar Color)	//向LCD指定坐标写入一个象素,象素颜色有两种,0代表白(无显示),1代表黑(有显示)
{uchar z,w;uint Temp;if(x>=128||y>=64)return;Color=Color%2;w=15-x%16;						//确定对这个字的第多少位进行操作x=x/16;							//确定为一行上的第几字if(y<32) 						//如果为上页z=0x80;else     						//否则如果为下页z=0x88;y=y%32;EA=0;Lcd_W_Com(0x36);Lcd_W_Com(y+0x80);        		//行地址Lcd_W_Com(x+z);     			//列地址 Temp=Lcd_R_Dat();				//先空读一次Temp=(uint)Lcd_R_Dat()<<8;		//再读出高8位Temp|=(uint)Lcd_R_Dat();		//再读出低8位EA=1;if(Color==1) 					//如果写入颜色为1Temp|=MaskTab[w];			//在此处查表实现加速else         					//如果写入颜色为0Temp&=~MaskTab[w];			//在此处查表实现加速EA=0;Lcd_W_Com(y+0x80);        		//行地址Lcd_W_Com(x+z);     			//列地址Lcd_W_Dat(Temp>>8);				//先写入高8位,再写入低8位Lcd_W_Dat(Temp&0x00ff);Lcd_W_Com(0x30);EA=1;
}
void Lcd_HoriLine(uchar x,uchar y,uchar Length,uchar Color)	//向LCD指定位置画一条长度为Length的指定颜色的水平线
{uchar i;if(Length==0)return;for(i=0;i<Length;i++)Lcd_PutPixel(x+i,y,Color);
}
void Lcd_VertLine(uchar x,uchar y,uchar Length,uchar Color)	//向LCD指定位置画一条长度为Length的指定颜色的垂直线
{uchar i;if(Length==0)return;for(i=0;i<Length;i++)Lcd_PutPixel(x,y+i,Color);
}
void Lcd_Rectangle(uchar x0,uchar y0,uchar x1,uchar y1,uchar Color)	//向LCD指定左上角坐标和右下角坐标画一个指定颜色的矩形
{uchar Temp;if(x0>x1){Temp=x0;x0=x1;x1=Temp;}	if(y0>y1){Temp=y0;y0=y1;y1=Temp;}Lcd_VertLine(x0,y0,y1-y0+1,Color);Lcd_VertLine(x1,y0,y1-y0+1,Color);Lcd_HoriLine(x0,y0,x1-x0+1,Color);Lcd_HoriLine(x0,y1,x1-x0+1,Color);	
}
void Lcd_Clear(uchar Mode)			//清除Lcd全屏,如果清除模式Mode为0,则为全屏清除为颜色0(无任何显示)
{  									//否则为全屏清除为颜色1(全屏填充显示)uchar x,y,ii;uchar Temp;if(Mode%2==0)Temp=0x00;elseTemp=0xff;Lcd_W_Com(0x36);				//扩充指令 绘图显示for(ii=0;ii<9;ii+=8)   for(y=0;y<0x20;y++)     for(x=0;x<8;x++){ 	EA=0;	   			//关总中断Lcd_W_Com(y+0x80);  //行地址Lcd_W_Com(x+0x80+ii); 	//列地址     Lcd_W_Dat(Temp); 	//写数据 D15-D8 Lcd_W_Dat(Temp); 	//写数据 D7-D0 EA=1;		   		//开总中断}Lcd_W_Com(0x30);
}
void Lcd_Init()						//LCD液晶初始化
{  Lcd_W_Com(0x30);       			//选择基本指令集Lcd_W_Com(0x0c);       			//开显示(无游标、不反白)Lcd_W_Com(0x01);       			//清除显示,并且设定地址指针为00HLcd_W_Com(0x06);       			//指定在资料的读取及写入时,设定游标的移动方向及指定显示的移位
}//************************************************************************/
// 描述: 反转法键盘扫描 
//************************************************************************/
uchar KeyBoard()				/* 反转法键盘扫描 */
{uchar temp1,temp2,temp,a=0;P1=0xf0;						/* 输入行值(或列值) */Delay_MS(1) 	;				/* 延时 */temp1=P1;						/* 读列值(或行值) */P1=0xff;Delay_MS(1);				/* 延时 */P1=0x0f;						/* 输入列值(或行值) */Delay_MS(1) ;				/* 延时 */	temp2=P1;						/* 读行值(或列值) */P1=0xff;temp=(temp1&0xf0)|(temp2&0xf);	/* 将两次读入数据组合 */switch(temp)					/* 通过读入数据组合判断按键位置 */{		case 0xdd :a=20;break; // 	按键上case 0x7d :a=40;break;// 按键下case 0xbe :a=30;break;	//  按键左case 0xbb :a=10;break;	//  按键右default :a=0;}return a;						/* 返回按键值 */
}void Exint_Init()
{IT0 = 1;EX0 = 1;EA = 1;
}/*********外部中断0服务函数***********/
void Exint0_Service() interrupt 0
{Run=~Run;
}uchar Key_Read()					//读取按键动作函数
{									//没有按键动作,则返回0,static uchar KeyEventCnt=0;		//1号按键动作,返回1-4static uchar KeySampleCnt=0;	//2号按键动作,返回5-8,如此类推static uchar KeyBuffer=0;		//返回1、5、9、13:确认短按按下uchar KeyTemp;					//返回2、6、10、14:确认长按按下KeyTemp=KeyBoard();				//返回3、7、11、15:确认短按松开switch(KeyEventCnt)				//返回4、8、12、16:确认长按松开{case 0:if(KeyTemp!=0){KeySampleCnt=0;KeyBuffer=KeyTemp;KeyEventCnt=1;     }return 0;				//没有按下,return 0break;case 1:if(KeyTemp!=KeyBuffer){KeyEventCnt=0;return 0;			//抖动,return 0}else{if(++KeySampleCnt>=SHORT_ON_DITHERING_COUNTER){KeySampleCnt=0;KeyEventCnt=2;return KeyBuffer;}elsereturn 0;		//不确定按下,return 0                 }break;case 2:if(KeyTemp!=KeyBuffer){if(++KeySampleCnt>=SHORT_OFF_DITHERING_COUNTER){KeyEventCnt=0;return KeyBuffer+3;}elsereturn 0;}else{KeySampleCnt=0;return 0;}break;default:break;}return 0;
}
void Lcd_Show_Board()				//LCD显示墙壁函数
{uchar n;for(n=0;n<31;n++){Lcd_Rectangle(3*n,0,3*n+2,2,1);Lcd_Rectangle(3*n,60,3*n+2,62,1);}for(n=0;n<21;n++){Lcd_Rectangle(0,3*n,2,3*n+2,1);Lcd_Rectangle(90,3*n,92,3*n+2,1);		}
}
void Lcd_Show_Score()				//液晶显示分数函数
{uchar Str[3];Lcd_Show_String(6,1,"分");		//显示汉字Lcd_Show_String(6,2,"数");Str[0]=(Score/10)|0x30;			//十位Str[1]=(Score%10)|0x30;			//个位Str[2]=0;Lcd_Show_String(6,3,Str); 		//液晶显示分数
}
void Lcd_Show_Title()				//液晶显示贪吃蛇汉字
{Lcd_Show_String(7,0,"贪"); 		//显示汉字Lcd_Show_String(7,1,"吃");Lcd_Show_String(7,2,"蛇");
}
void Game_Over()					//游戏结束处理
{uchar n;Lcd_Rectangle(food.x,food.y,food.x+2,food.y+2,0);	//消隐出食物for(n=1;n<snake.node;n++)Lcd_Rectangle(snake.x[n],snake.y[n],snake.x[n]+2,snake.y[n]+2,0);//消隐食物,蛇头已到墙壁内,故不用消去		if(snake.life==0)				//如果蛇还活着Lcd_Show_String(2,1,"过关");else             				//如果蛇死了Lcd_Show_String(2,1,"输了");Lcd_Show_String(1,2,"游戏结束");
}
void Game_Play()					//游戏的具体过程,也是贪吃蛇算法的关键部分
{uchar n;InitRandom(TL0);food.yes=1;						//1表示需要出现新事物,0表示已经存在食物尚未吃掉snake.life=0;					//表示蛇还活着snake.direction=DOWN;snake.x[0]=6;snake.y[0]=6;snake.x[1]=3;snake.y[1]=6;snake.node=2;Lcd_Show_Score();				//显示分数Lcd_Show_Title();			   	//显示标题while(1){if(food.yes==1){while(1){food.x=Random()*85+3;food.y=Random()*55+3;		//获得随机数while(food.x%3!=0)food.x++;while(food.y%3!=0)food.y++;for(n=0;n<snake.node;n++)	//判断产生的食物坐标是否和蛇身重合{if((food.x==snake.x[n])&&(food.y==snake.y[n]))break;}if(n==snake.node){food.yes=0;break;			//产生有效的食物坐标}}}if(food.yes==0){Lcd_Rectangle(food.x,food.y,food.x+2,food.y+2,1);}	if(Run==0){for(n=snake.node-1;n>0;n--){snake.x[n]=snake.x[n-1];snake.y[n]=snake.y[n-1];}	switch(snake.direction){case DOWN:snake.x[0]+=3;break;case UP:snake.x[0]-=3;break;case RIGHT:snake.y[0]-=3;break;case LEFT:snake.y[0]+=3;break;default:break;}for(n=3;n<snake.node;n++)	//从第三节开始判断蛇头是否咬到自己{if(snake.x[n]==snake.x[0]&&snake.y[n]==snake.y[0]){Game_Over();snake.life=1;break;}}}if(snake.x[0]<3||snake.x[0]>=90||snake.y[0]<3||snake.y[0]>=60)//判蛇头是否撞到墙壁{Game_Over();snake.life=1;}if(snake.life==1)break;					//蛇死,则跳出while(1)循环if(snake.x[0]==food.x&&snake.y[0]==food.y)	//判蛇是否吃到食物{Lcd_Rectangle(food.x,food.y,food.x+2,food.y+2,0);	//消隐食物snake.x[snake.node]=200;snake.y[snake.node]=200;//产生蛇新的节坐标先放在看不见的位置snake.node++;			//蛇节数加1food.yes=1;				//食物标志置1if(++Score>=PASSSCORE){Lcd_Show_Score();Game_Over();break;}Lcd_Show_Score();}for(n=0;n<snake.node;n++){Lcd_Rectangle(snake.x[n],snake.y[n],snake.x[n]+2,snake.y[n]+2,1);}							//根据蛇的节数画出蛇Delay(Speed*1000);Lcd_Rectangle(snake.x[snake.node-1],snake.y[snake.node-1],snake.x[snake.node-1]+2,snake.y[snake.node-1]+2,0);switch(KeyBuffer){case FUNC:KeyBuffer=0;if(++Speed>=10)Speed=1;Lcd_Show_Title();break;case DOWN:				//下KeyBuffer=0;if(snake.direction!=UP)snake.direction=DOWN;break;case UP:	  			//上KeyBuffer=0;if(snake.direction!=DOWN)snake.direction=UP;break;case RIGHT:		  		//右KeyBuffer=0;if(snake.direction!=LEFT)snake.direction=RIGHT;break;case LEFT:				//左KeyBuffer=0;if(snake.direction!=RIGHT)snake.direction=LEFT;break;default:break;}			}
}
void Main()							//主函数
{  
start:Score=0;Timer_Init();					//定时器初始化Exint_Init();Lcd_Init(); 					//液晶初始化Lcd_Clear(0);					//液晶清屏Lcd_Show_Board();				//液晶显示墙壁Game_Play();					//玩游戏Game_Over();					//游戏结束	Delay_MS(4000);goto start;
}
void Timer0_ISR() interrupt 1		//定时器0中断处理函数
{switch(Key_Read()){case 90:KeyBuffer=FUNC;if(++Speed>=10)Speed=1;Flag|=1<<1;				//速度变化标志置1break;case 13:KeyBuffer=DOWN;break;case 33:KeyBuffer=UP;break;case 23:KeyBuffer=RIGHT;break;case 43:KeyBuffer=LEFT;break;default:break;}
}

仿真源文件、源程序及设计报告百度网盘链接:https://pan.baidu.com/s/1C4da0C0fJHio73F4eFVChg?pwd=q1ef   提取码: q1ef 

http://www.dtcms.com/a/278629.html

相关文章:

  • 图算法在前端的复杂交互
  • 网络编程(套接字)
  • AI数据分析仪设计原理图:RapidIO信号接入 平板AI数据分析仪
  • RPC vs RESTful架构选择背后的技术博弈
  • 从数据洞察到设计创新:UI前端如何利用数字孪生提升产品交互体验?
  • 数字孪生技术引领UI前端设计新潮流:智能交互界面的个性化定制
  • 【Linux网络编程】应用层自定义协议与序列化
  • React强大且灵活hooks库——ahooks入门实践之DOM类hook(dom)详解
  • Reactor 模式详解
  • 订单初版—6.生单链路实现的重构文档
  • Vue3 学习教程,从入门到精通,Vue 3 表单控件绑定详解与案例(7)
  • 设计模式--适配器模式
  • PHP password_get_info() 函数
  • 第一章 uniapp实现兼容多端的树状族谱关系图,创建可缩放移动区域
  • 商城系统的架构与功能模块
  • flink 中配置hadoop 遇到问题解决
  • 用Python向PDF添加文本:精确插入文本到PDF文档
  • vue3+uniapp 使用vue-plugin-hiprint中实现打印效果
  • Triton Inference Server 架构与前后处理方案梳理
  • 打破空间边界!Nas-Cab用模块化设计重构个人存储逻辑
  • JAVA进阶--JVM
  • 设备发出、接收数据帧的工作机制
  • 无人机迫降模式模块运行方式概述!
  • 掉线监测-tezos rpc不能用,改为残疾网页监测
  • .net winfrom 获取上传的Excel文件 单元格的背景色
  • 深入浅出Kafka Producer源码解析:架构设计与编码艺术
  • 创客匠人:创始人 IP 打造的破局点,藏在 “小而精” 的需求里
  • React源码3:update、fiber.updateQueue对象数据结构和updateContainer()中enqueueUpdate()阶段
  • 分布式系统中设计临时节点授权的自动化安全审计
  • postgreSQL的sql语句