|
本帖最后由 lynn710 于 2018-8-13 20:01 编辑
急用,多谢指正
#include"reg52.h"
#include "intrins.h"
sbit RS=P2^6; //并行的指令/数据选择信号, H数据, L命令
sbit RW=P2^5; //并行读写选择信号, H读, L写
sbit E=P2^7; //并行使能端, H有效, L无效
sbit PSB=P3^2; //并/串接口选择, H并,L串
sbit RET=P3^4; //复位, L有效
#define LcdData P0
unsigned char Check_Busy(void);
void Lcd_WriteData(unsigned char);
unsigned char Lcd_ReadData(void);
void Lcd_WriteCmd(unsigned char);
void Lcd_PutPixel(unsigned char,unsigned char,unsigned char);
unsigned char Lcd_ReadPixel(unsigned char,unsigned char);
void Lcd_HoriLine(unsigned char,unsigned char,unsigned char Length,unsigned char Color);
void Lcd_VertLine(unsigned char x,unsigned char y,unsigned char Length,unsigned char Color);
void Lcd_Line(unsigned char x1,unsigned char y1,unsigned char x2,unsigned char y2,unsigned char Color);
void Lcd_Rectangle(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char Color);
void Lcd_Circle(unsigned char x,unsigned char y,unsigned char r,unsigned char Color);
void Lcd_Clear(unsigned char);
void Lcd_WriteStr(unsigned char,unsigned char,unsigned char *);
void Lcd_Reset(void);
unsigned char OSReadKey(void);
unsigned char KeyDown(); //检测按键函数
void Delay10ms(void); //延时10ms
double Random(void);
void InitRandom(unsigned long InitVal);
void InitCpu(void);
void DrawBoardf(void);
void Drawboardt(void);
void PrintScore(void);
void PrintSpeed(void);
void GameOver(void);
void GamePlayo(void);
void GamePlayt(void);
void delay(unsigned int t);
//void Timer0Int(void) interrupt 1 ;
sbit kxuanze=P3^1;
sbit kenter=P3^3;
void delayus(unsigned int j);
void delayms(unsigned int x);
void init(void);
void lcd_wcd(unsigned char com_dat,unsigned char date);
void lcd_st(unsigned char *st);
void scankey(void);
void menu(void);
void jiemian(void);
void moshi(void);
void moshi1(void);
void moshi2(void);
void speed(void);
void Speed1(void);
void Speed2(void);
void Speed3(void);
void Speed4(void);
void game(void);
/*************
测试LCD是否处于忙状态
如果忙则返回0x80,否则返回0
**************/
unsigned char Lcd_CheckBusy(void)
{
unsigned char Busy;
LcdData=0xff;
RS=0;
RW=1;
E=1;
_nop_();
Busy=LcdData&0x80;
E=0;
return Busy;
}
/*********************************
向LCD写入字节数据
**********************************/
void Lcd_WriteData(unsigned char Data)
{
while(Lcd_CheckBusy());
RS=1;
RW=0;
E=0;
_nop_();
_nop_();
LcdData=Data;
E=1;
_nop_();
_nop_();
E=0;
}
/***********************************
从LCD中读出数据
************************************/
unsigned char Lcd_ReadData(void)
{
unsigned char Temp;
while(Lcd_CheckBusy());
LcdData=0xff;
RS=1;
RW=1;
E=1;
_nop_();
Temp=LcdData;
E=0;
return Temp;
}
/*************************************
向LCD中写入指令代码
**************************************/
void Lcd_WriteCmd(unsigned char CmdCode)
{
while(Lcd_CheckBusy());
RS=0;
RW=0;
E=0;
_nop_();
_nop_();
LcdData=CmdCode;
_nop_();
_nop_();
E=1;
_nop_();
_nop_();
E=0;
}
void set_postion(unsigned char x,unsigned char y)
{
unsigned char postion;
switch(x)
{
case 0:x=0x80;break;
case 1:x=0x90;break;
case 2:x=0x88;break;
case 3:x=0x98;break;
default:break;
}
postion=x+y;
Lcd_WriteCmd(postion);
}
/*************************************
向LCD指定起始位置写入一个字符串
*************************************/
void Lcd_WriteStr(unsigned char x,unsigned char y,unsigned char *Str)
{
if((y>3)||(x>7))
return;//如果指定位置不在显示区域内,则不做任何写入直接返回
EA=0;
switch(y)
{
case 0:
Lcd_WriteCmd(0x80+x);
break;
case 1:
Lcd_WriteCmd(0x90+x);
break;
case 2:
Lcd_WriteCmd(0x88+x);
break;
case 3:
Lcd_WriteCmd(0x98+x);
break;
}
while(*Str>0)
{
Lcd_WriteData(*Str);
Str++;
}
EA=1;
}
/**************************************
为加速逻辑运算而设置的掩码表,这是以牺牲空间而换取时间的办法
***************************************/
code unsigned int MaskTab[]={0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,
0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000};
/***************************************
向LCD指定坐标写入一个象素,象素颜色有两种,0代表白(无显示),1代表黑(有显示)
****************************************/
void Lcd_PutPixel(unsigned char x,unsigned char y,unsigned char Color)
{
unsigned char z,w;
unsigned int 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_WriteCmd(0x36);
Lcd_WriteCmd(y+0x80); //行地址
Lcd_WriteCmd(x+z); //列地址
Temp=Lcd_ReadData();//先空读一次
Temp=(unsigned int)Lcd_ReadData()<<8;//再读出高8位
Temp|=(unsigned int)Lcd_ReadData();//再读出低8位
EA=1;
if(Color==1) //如果写入颜色为1
Temp|=MaskTab[w];//在此处查表实现加速
else //如果写入颜色为0
Temp&=~MaskTab[w];//在此处查表实现加速
EA=0;
Lcd_WriteCmd(y+0x80); //行地址
Lcd_WriteCmd(x+z); //列地址
Lcd_WriteData(Temp>>8);//先写入高8位,再写入低8位
Lcd_WriteData(Temp&0x00ff);
Lcd_WriteCmd(0x30);
EA=1;
}
/******************************************
从LCD指定坐标读取象素颜色值
*******************************************/
unsigned char Lcd_ReadPixel(unsigned char x,unsigned char y)
{
unsigned char z,w;
unsigned int Temp;
x=x%128;
y=y%64;
w=15-x%16;//确定对这个字的第多少位进行操作
x=x/16;//确定为一行上的第几字
if(y<32) //如果为上页
z=0x80;
else //否则如果为下页
z=0x88;
y=y%32;
Lcd_WriteCmd(0x36);
Lcd_WriteCmd(y+0x80); //行地址
Lcd_WriteCmd(x+z); //列地址
Temp=Lcd_ReadData();//先空读一次
Temp=(unsigned int)Lcd_ReadData()<<8;//再读出高8位
Temp|=(unsigned int)Lcd_ReadData();//再读出低8位
if((Temp&&MaskTab[w])==0)
return 0;
else
return 1;
}
/***************************************
向LCD指定位置画一条长度为Length的指定颜色的水平线
****************************************/
void Lcd_HoriLine(unsigned char x,unsigned char y,unsigned char Length,unsigned char Color)
{
unsigned char i;
if(Length==0)
return;
for(i=0;i<Length;i++)
{
Lcd_PutPixel(x+i,y,Color);
}
}
/***************************************
向LCD指定位置画一条长度为Length的指定颜色的垂直线
****************************************/
void Lcd_VertLine(unsigned char x,unsigned char y,unsigned char Length,unsigned char Color)
{
unsigned char i;
if(Length==0)
return;
for(i=0;i<Length;i++)
{
Lcd_PutPixel(x,y+i,Color);
}
}
/*******************************************
向LCD指定起始坐标和结束坐标之间画一条指定颜色的直线
********************************************/
void Lcd_Line(unsigned char x1,unsigned char y1,unsigned char x2,unsigned char y2,unsigned char Color)
{
unsigned int x,y;
unsigned int d_x,d_y;//d_x=x2-x1;d_y=y2-y1;
int err=0;
unsigned char temp=0;
if(y2<y1)
{
x=x1;
y=y1;
x1=x2;
y1=y2;
x2=x;
y2=y;
}
d_y=y2-y1;
if (d_y==0)
{
if (x1>x2)
{
x=x1;
x1=x2;
x2=x;
}
for (x=x1;x<=x2;x++)
Lcd_PutPixel(x,y1,Color);
}
else
{
if(x2>=x1)
{
temp=1;
d_x=x2-x1;
}
else
d_x=x1-x2;
x=x1;
y=y1;
Lcd_PutPixel(x,y,1);
if(temp&&(d_y<=d_x))
while(x!=x2)
{
if(err<0)
{
x=x+1;
err=err+(y2-y);
}
else
{
x=x+1;
y=y+1;
err=err+(y2-y)-(x2-x);
}
Lcd_PutPixel(x,y,Color);
}
else if(temp&&(d_y>d_x))
while(y!=y2)
{
d_x=x2-x;
d_y=y2-y;
if(err<0)
{
x=x+1;
y=y+1;
err=err+d_y-d_x;
}
else
{
y=y+1;
err=err-d_x;
}
Lcd_PutPixel(x,y,Color);
}
else if(!temp&&(d_y<=d_x))
while(x!=x2)
{
d_x=x-x2;
d_y=y2-y;
if(err<0)
{
x=x-1;
err=err+d_y;
}
else
{
x=x-1;
y=y+1;
err=err+d_y-d_x;
}
Lcd_PutPixel(x,y,Color);
}
else if(!temp &&(d_y>d_x))
while(y!=y2)
{
d_x=x-x2;
d_y=y2-y;
if(err<0)
{
x=x-1;
y=y+1;
err=err+d_y-d_x;
}
else
{
y=y+1;
err=err-d_x;
}
Lcd_PutPixel(x,y,Color);
}
}
}
/*******************************************
向LCD指定左上角坐标和右下角坐标画一个指定颜色的矩形
********************************************/
void Lcd_Rectangle(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char Color)
{
unsigned char 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);
}
/****************************************
对称法画圆的8个镜像点
*****************************************/
void CircleDot(unsigned char x,unsigned char y,char xx,char yy,unsigned char Color)//内部函数,对称法画圆的8个镜像点
{
Lcd_PutPixel((x+yy),(y+xx),Color);//第 1 个 8 分圆
Lcd_PutPixel((x+xx),(y+yy),Color);//第 2 个 8 分圆
Lcd_PutPixel((x-xx),(y+yy),Color);//第 3 个 8 分圆
Lcd_PutPixel((x-yy),(y+xx),Color);//第 4 个 8 分圆
Lcd_PutPixel((x-yy),(y-xx),Color);//第 5 个 8 分圆
Lcd_PutPixel((x-xx),(y-yy),Color);//第 6 个 8 分圆
Lcd_PutPixel((x+xx),(y-yy),Color);//第 7 个 8 分圆
Lcd_PutPixel((x+yy),(y-xx),Color);//第 8 个 8 分圆
}
/******************************************
向LCD指定圆心坐标画一个半径为r的指定颜色的圆
*******************************************/
void Lcd_Circle(unsigned char x,unsigned char y,unsigned char r,unsigned char Color)//中点法画圆
{//中点法画圆
unsigned char xx,yy;
char deltax,deltay,d;
xx=0;
yy=r;
deltax=3;
deltay=2-r-r;
d=1-r;
CircleDot(x,y,xx,yy,Color);//对称法画圆的8个镜像点
while (xx<yy)
{
if (d<0)
{
d+=deltax;
deltax+=2;
xx++;
}
else
{
d+=deltax+deltay;
deltax+=2;
deltay+=2;
xx++;
yy--;
}
CircleDot(x,y,xx,yy,Color);//对称法画圆的8个镜像点
}
}
/*****************************************
清除Lcd全屏,如果清除模式Mode为0,则为全屏清除为颜色0(无任何显示)
否则为全屏清除为颜色1(全屏填充显示)
******************************************/
void Lcd_Clear(unsigned char Mode)
{
unsigned char x,y,ii;
unsigned char Temp;
if(Mode%2==0)
Temp=0x00;
else
Temp=0xff;
Lcd_WriteCmd(0x36);//扩充指令 绘图显示
for(ii=0;ii<9;ii+=8)
for(y=0;y<0x20;y++)
for(x=0;x<8;x++)
{
EA=0;
Lcd_WriteCmd(y+0x80); //行地址
Lcd_WriteCmd(x+0x80+ii); //列地址
Lcd_WriteData(Temp); //写数据 D15-D8
Lcd_WriteData(Temp); //写数据 D7-D0
EA=1;
}
Lcd_WriteCmd(0x30);
}
/****************************************
LCD初始化
*****************************************/
void Lcd_Reset(void)
{
PSB=1;
Lcd_WriteCmd(0x30); //选择基本指令集
Lcd_WriteCmd(0x0c); //开显示(无游标、不反白)
Lcd_WriteCmd(0x01); //清除显示,并且设定地址指针为00H
Lcd_WriteCmd(0x06); //指定在资料的读取及写入时,设定游标的移动方向及指定显示的移位
}
#define OS_LONG_EYK_EN 1//如果应用中需要处理长按键动作,则定义为1,否则定义为0(如果应用中不需要处理长按动作,则建议定义为0,以节省代码空间)
#define GPIO_KEY P1
unsigned char KeyValue;//用来存放读取到的键值
unsigned char code DIG_CODE[17]={
0,0,0,0,0,5,0,0,6,0,4,0,0,3,0,0,0};
void Delay10ms(void) //误差 0us
{
unsigned char a,b,c;
for(c=1;c>0;c--)
for(b=38;b>0;b--)
for(a=130;a>0;a--);
}
/***********************************************
功能说明:按键驱动扫描
入口参数:无
出口参数:扫描一次键盘以获得按键句柄
注:交OSReadKey()函数调用
***********************************************/
unsigned char KeyDown(void)
{
char a=0;
GPIO_KEY=0x0f;
if(GPIO_KEY!=0x0f)//读取按键是否按下
{
Delay10ms();//延时10ms进行消抖
if(GPIO_KEY!=0x0f)//再次检测键盘是否按下
{
//测试列
GPIO_KEY=0X0F;
switch(GPIO_KEY)
{
case(0X07): KeyValue=0;break;
case(0X0b): KeyValue=1;break;
case(0X0d): KeyValue=2;break;
case(0X0e): KeyValue=3;break;
}
//测试行
GPIO_KEY=0XF0;
switch(GPIO_KEY)
{
case(0X70): KeyValue=KeyValue;break;
case(0Xb0): KeyValue=KeyValue+4;break;
case(0Xd0): KeyValue=KeyValue+8;break;
case(0Xe0): KeyValue=KeyValue+12;break;
}
while((a<50)&&(GPIO_KEY!=0xf0)) //检测按键松手检测
{
Delay10ms();
a++;
}
}
}
return KeyValue;
}
/**********************************************
功能说明:读取按键动作
入口参数:无
出口参数:返回按键动作
注意:
没有按键动作,则返回0,
使用矩阵按键:向上S12;向下S6;向左S12;向右S9;
***********************************************/
unsigned char OSReadKey(void)
{
static unsigned char KeyEventCnt=0;
static unsigned char KeySampleCnt=0;
static unsigned char KeyBuffer=0;
#define SHORT_ON_DITHERING_COUNTER 3//定义短按按下去抖时间
#define SHORT_OFF_DITHERING_COUNTER 3//定义短按松开去抖时间,一般与短按按下去抖时间相同
#if OS_LONG_KEY_EN>0
static unsigned int LongKeySampleCnt=0;
#define LONG_ON_DITHERING_COUNTER 250//定义长按按下确认需要的时间,如果是每1MS调用一次OSReadKey(),则1000意味着这个时间为1S
#define LONG_OFF_DITHERING_COUNTER 3//定义长按松开去抖时间,一般和短按去抖时间相同
#endif
unsigned char KeyTemp;
KeyTemp=DIG_CODE[KeyDown()];
switch(KeyEventCnt)
{
case 0:
if(KeyTemp!=0)
{
KeySampleCnt=0;
KeyBuffer=KeyTemp;
KeyEventCnt=1;
}
return 0;//no key on,return 0
break;
#if OS_LONG_KEY_EN>0
case 1:
if(KeyTemp!=KeyBuffer)
{
KeyEventCnt=0;
return 0;//is dithering,return 0
}
else
{
if(++KeySampleCnt>SHORT_ON_DITHERING_COUNTER)
{
KeySampleCnt=0;
KeyEventCnt=2;
LongKeySampleCnt=0;
return ((KeyBuffer-1)<<2)+1;//sure that key on,return (KeyBuffer-1)<<2+1
}
else
return 0;//not sure that key on,return 0
}
break;
case 2:
if(++LongKeySampleCnt>LONG_ON_DITHERING_COUNTER)
{
KeySampleCnt=0;
KeyEventCnt=3;
return ((KeyBuffer-1)<<2)+2; //sure that key long on,return (KeyBuffer-1)<<2+2
}
else
{
if(KeyTemp!=KeyBuffer)
{
if(++KeySampleCnt>SHORT_OFF_DITHERING_COUNTER)
{
KeyEventCnt=0;
return ((KeyBuffer-1)<<2)+3;//after short on to off,(KeyBuffer-1)<<2+3
}
else
return 0;
}
else
{
KeySampleCnt=0;
return 0;
}
}
break;
case 3:
if(KeyTemp!=KeyBuffer)
{
if(++KeySampleCnt>LONG_OFF_DITHERING_COUNTER)
{
KeyEventCnt=0;
return ((KeyBuffer-1)<<2)+4; //after long key on turn to off,(KeyBuffer-1)<<2+4
}
else
return 0;
}
else
{
KeySampleCnt=0;
return 0;
}
break;
#else
case 1:
if(KeyTemp!=KeyBuffer)
{
KeyEventCnt=0;
return 0;//is dithering,return 0
}
else
{
if(++KeySampleCnt>=SHORT_ON_DITHERING_COUNTER)
{
KeySampleCnt=0;
KeyEventCnt=2;
return ((KeyBuffer-1)<<2)+1;//sure that key on,return (KeyBuffer-1)<<2+1
}
else
return 0;//not sure that key on,return 0
}
break;
case 2:
if(KeyTemp!=KeyBuffer)
{
if(++KeySampleCnt>=SHORT_OFF_DITHERING_COUNTER)
{
KeyEventCnt=0;
return ((KeyBuffer-1)<<2)+3;//after short on to off,(KeyBuffer-1)<<2+3
}
else
return 0;
}
else
{
KeySampleCnt=0;
return 0;
}
break;
#endif
default:break;
}
return 0;
}
#define uchar unsigned char
#define uint unsigned int
static unsigned long Seed = 1;
#define A 48271L
#define M 2147483647L
#define Q (M / A)
#define R (M % A)
void delay(unsigned int t)
{
unsigned int i,j;
for(i=0;i<t;i++)
for(j=0;j<10;j++);
}
/************************************
伪随机数发生器
*************************************/
double Random(void)
{
long TmpSeed;
TmpSeed=A*(Seed%Q)-R*(Seed/Q);
if(TmpSeed>=0)
Seed=TmpSeed;
else
Seed=TmpSeed+M;
return (double)Seed/M;
}
/**************************************
为伪随机数发生器播种
***************************************/
void InitRandom(unsigned long InitVal)
{
Seed=InitVal;
}
/*********************************
初始化MPU
**********************************/
void InitCpu(void)
{
TMOD=0x01;
TH0=0;
TL0=0;
TR0=1;
ET0=1;
EA=1;
}
#define N 25
struct Food
{
unsigned char x;
unsigned char y;
unsigned char yes;
}food;//食物结构体
struct Snake
{
unsigned char x[N];
unsigned char y[N];
unsigned char node;
unsigned char direction;
unsigned char life;
}snake;//蛇结构体
unsigned char Flag=0;
unsigned char Score=0;
unsigned char Speed; //speed越大,速度越慢
unsigned char KeyBuffer=0;
#define FUNC 1 //(P3^1)表示级别
#define UP 2 //(P3^3)表示左
#define DOWN 3 //(P3^5)表示右
#define LEFT 4 //(P3^4)表示下
#define RIGHT 5 //(P3^2)表示上
#define PASSSCORE 20 //预定义过关成绩
void Timer0Int(void) interrupt 1
{
switch(OSReadKey())
{
case 5:
KeyBuffer=FUNC; //表示级别
/*if(++Speed>=10)
Speed=1;
Flag|=1<<1;//速度变化标志置1*/
break;
case 21:
KeyBuffer=DOWN; //表示右
/*if(snake.direction!=2)
snake.direction=1;*/
break;
case 13:
KeyBuffer=UP; //表示左
/*if(snake.direction!=1)
snake.direction=2;*/
break;
case 9:
KeyBuffer=RIGHT; //表示上
/*if(snake.direction!=4)
snake.direction=3;*/
break;
case 17:
KeyBuffer=LEFT; //表示下
/*if(snake.direction!=3)
snake.direction=4;*/
break;
default:
break;
}
}
/******************************
画墙壁,初始化界面
*******************************/
void DrawBoardf(void)
{
unsigned char 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);
}
Lcd_HoriLine(93,31,35,1);
Lcd_HoriLine(93,63,35,1);
}
void Drawboardt(void)
{
unsigned char n;
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);
}
Lcd_HoriLine(93,31,35,1);
Lcd_HoriLine(93,63,35,1);
}
/***************************
打印成绩
****************************/
void PrintScore(void)
{
unsigned char Str[3];
Lcd_WriteStr(6,0,"成绩");
Str[0]=(Score/10)|0x30;//十位
Str[1]=(Score%10)|0x30;//个位
Str[2]=0;
Lcd_WriteStr(7,1,Str);
}
/********************************
打印速度级别
*********************************/
void PrintSpeed(void)
{
unsigned char Str[2];
Lcd_WriteStr(6,2,"级别");
Str[0]=Speed|0x30;
Str[1]=0;
Lcd_WriteStr(7,3,Str);
}
/***********************************
游戏结束处理
************************************/
void GameOver(void)
{
unsigned char 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_WriteStr(2,1,"过关");
else //如果蛇死了
Lcd_WriteStr(2,1,"输了");
Lcd_WriteStr(1,2,"游戏结束");
}
/********************************
游戏的具体过程,也是贪吃蛇算法的关键部分
*********************************/
void GamePlayo(void)
{
unsigned char 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;
PrintScore();
PrintSpeed();
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);
}
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])
{
GameOver();
snake.life=1;
break;
}
}
if(snake.x[0]<3||snake.x[0]>=90||snake.y[0]<3||snake.y[0]>=60)//判蛇头是否撞到墙壁
{
GameOver();
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++;//蛇节数加1
food.yes=1;//食物标志置1
if(++Score>=PASSSCORE)
{
PrintScore();
GameOver();
break;
}
PrintScore();
}
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); //调速
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;
PrintSpeed();
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;
}
}//结束while(1)
}
void GamePlayt(void)
{
unsigned char 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;
PrintScore();
PrintSpeed();
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);
}
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])
{
GameOver();
snake.life=1;
break;
}
}
if(snake.x[0]<3||snake.x[0]>=90)//判蛇头是否撞到墙壁
{
GameOver();
snake.life=1;
}
if(snake.life==1)
break;//蛇死,则跳出while(1)循环
if(snake.y[0]<3||snake.y[0]>=60)
{ if(snake.y[0]<3)
snake.y[0]=59;
// for(n=0;n<snake.node;n++)
// {
// Lcd_Rectangle(snake.x[n],snake.y[n],snake.x[n]+2,snake.y[n]+2,1);
// }//根据蛇的节数画出蛇
if(snake.y[0]>=60)
snake.y[0]=3;
// for(n=0;n<snake.node;n++)
// {
// Lcd_Rectangle(snake.x[n],snake.y[n],snake.x[n]+2,snake.y[n]+2,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++;//蛇节数加1
food.yes=1;//食物标志置1
if(++Score>=PASSSCORE)
{
PrintScore();
GameOver();
break;
}
PrintScore();
}
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); //调速
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;
PrintSpeed();
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;
}
}//结束while(1)
}
unsigned char flag,flag1,s1num;
void delayus(unsigned int j)
{
unsigned char i;
for(i=j;i>0;i--);
}
void delayms(unsigned int x)
{
unsigned char i,j;
for(i=x;i>0;i--)
for(j=110;j>0;j--);
}
void init(void)
{
PSB=1;
Lcd_WriteCmd(0x01);
delayms(5);
Lcd_WriteCmd(0x30);
delayms(5);
Lcd_WriteCmd(0x0c);
delayms(5);
}
void scankey(void)
{
if(kxuanze==0) //选择键
{
delayms(10);
if(kxuanze==0) //如果S1确定按下
{s1num++; //变量加一
while(!kxuanze); //等待按键松开
if(s1num==1) //等待按键松开
{
set_postion(0,4); //一行三列(第一菜单的界面)
Lcd_WriteCmd(0x0f); //光标闪烁
}
}
if(s1num==2) //变量为2
{
set_postion(1,2); //二行三列
Lcd_WriteCmd(0x0f); //光标闪烁
}
if(s1num==3) //变量为3
{
set_postion(2,2);
Lcd_WriteCmd(0x0f);
}
if(s1num==4)
{
s1num=0;
}
}
if(s1num!=0) //如果slnum不等于0,目的是为了让S1键起作用后S2键才发挥相应的作用
{
if(kenter==0) //如果S2按下(确定键)
{
delayms(10); //延时消抖
if(kenter==0) //如果S2(确定键)确实按下
{
++flag; //flag自加1,设置变量的目的是为了方便设置子菜单中的下一级菜单
while(!kenter); //等待按键松开
if((s1num==1)&&(flag==1)) //与选择键中选中的相应栏目对应
{
flag1=1;
s1num=0;
Lcd_WriteCmd(0x01); //清屏
delayms(5);
Lcd_WriteCmd(0x0f);
delayms(5); //目的为了当进入父菜单后的子菜单,S1键能发挥作用
game ();
}
}
if((s1num==2)&&(flag==1))
{ flag1=1;
s1num=0;
Lcd_WriteCmd(0x01); //清屏
delayms(5);
Lcd_WriteCmd(0x0f);
delayms(5);
speed(); //目的为了当进入父菜单后的子菜单,S1键能发挥作用
}
if((s1num==1)&&(flag==2)) //如果变量为2.,进入子菜单的下一级菜单,下s1num==1,否则会进入误操作
{
Lcd_WriteCmd(0x0C);
delayms(5);
Lcd_WriteCmd(0x01);
delayms(5);
Speed1();
}
if((s1num==2)&&(flag==2)) //if((s1num==2)&&(flag==2)&&(flag==1))
{
Lcd_WriteCmd(0x0C);
delayms(5);
Lcd_WriteCmd(0x01);
delayms(5);
Speed2();
}
if((s1num==3)&&(flag==2))
{
Lcd_WriteCmd(0x0C);
delayms(5);
Lcd_WriteCmd(0x01);
delayms(5);
Speed3();
}
if((s1num==4)&&(flag==2))
{
Lcd_WriteCmd(0x0C);
delayms(5);
Lcd_WriteCmd(0x01);
delayms(5);
Speed4();
}
if((s1num==3)&&(flag==1))
{
flag1=1;
s1num=0; //目的为了当进入父菜单后的子菜单,S1键能发挥作用
Lcd_WriteCmd(0x01); //清屏
delayms(5);
Lcd_WriteCmd(0x0f);
delayms(5);
moshi();
}
if((s1num==1)&&(flag==2))
{
Lcd_WriteCmd(0x0C);
delayms(5);
Lcd_WriteCmd(0x01);
delayms(5);
moshi1();
}
if((s1num==2)&&(flag==2))
{
Lcd_WriteCmd(0x0C);
delayms(5);
Lcd_WriteCmd(0x01);
delayms(5);
moshi2();
}
if(s1num==4)
{
s1num=0;
}
if(flag==3)
{
flag=0;
}
}
}
}
void jiemian(void)
{
Lcd_WriteStr(0,1,"Welcome to");
Lcd_WriteStr(2,2,"贪吃蛇");
delayms(20000);
Lcd_WriteCmd(0x01);
}
void menu(void)
{
Lcd_WriteStr(0,1,"开始游戏");
Lcd_WriteStr(1,1,"速度选择");
Lcd_WriteStr(2,1,"模式设置");
}
void speed(void)
{
Lcd_WriteStr(0,1,"Speed1");
Lcd_WriteStr(1,1,"Speed2");
Lcd_WriteStr(2,1,"Speed3");
Lcd_WriteStr(3,1,"Speed4");
}
void moshi(void)
{
Lcd_WriteStr(0,1,"mosho1");
Lcd_WriteStr(1,1,"moshi2");
}
void moshi1(void)
{
unsigned char moshi;
moshi=1;
void Drawboardo();
void GamePlayf();
}
void moshi2(void)
{
unsigned char moshi;
moshi=2;
void Drawboardt();
void GamePlayt();
}
void Speed1(void)
{
unsigned char Speed=1;
}
void Speed2(void)
{
unsigned char Speed=2;
}
void Speed3(void)
{
unsigned char Speed=3;
}
void Speed4(void)
{
unsigned char Speed=4;
}
void game(void)
{
InitCpu();//初始化CPU
Lcd_Reset(); //初始化LCD屏
//Lcd_WriteStr(2,1,"Welcome");
delay(5000);
Lcd_WriteCmd(0x01); //清除显示,并且设定地址指针为00H
Lcd_Clear(0);//清屏
switch(Speed)
{
case '1':
Speed1();
break;
case '2':
Speed2();
break;
case '3':
Speed3();
break;
case '4':
Speed4();
break;
default:
Speed4();
}
switch(moshi)
{
case '1':
moshi1();
break;
case '2':
moshi2;
break;
default:
moshi2();
}
GameOver();//游戏结束
}
|
|