|
贪食蛇和俄罗斯方块的单片机制作
- //12864并行接口参考程序,控制器st7920
- #include "reg52.h"
- #include "Lcd12864.h"
- #include "Key.h"
- #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)
- /************************************
- 伪随机数发生器
- *************************************/
- 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;
- }
- //延时子程序
- void Delay(unsigned int t)
- {
- unsigned int i,j;
- for(i=0;i<t;i++)
- for(j=0;j<10;j++);
- }
- #define LGOU 0
- #define RGOU 1
- #define RZ 2
- #define LZ 3
- #define T 4
- #define GUN 5
- #define BOX 6
- unsigned int idata num[19+2]={
- 0xfff,//第1行,最下面
- 0x801,0x801,0x801,0x801,0x801,0x801,0x801,0x801,0x801,0x801,
- 0x801,0x801,0x801,0x801,0x801,0x801,0x801,0x801,0x801,//第2行到第20行共19行
- 0xfff//第21行,最上面
- };//定义共21行,其中num[0]为下墙壁行,num[20]为上墙壁行,每行12格,最左一格为左墙壁列,最右一格为右墙壁列
- unsigned char code Block[28][2]={
- /*
- * 口 口口口 口口
- * 口 口 口 口
- * 口口 口 口口口
- */
- {0x88,0xc0},{0xe8,0x00},{0x62,0x20},{0x02,0xe0},
- /*
- * 口 口口 口口口
- * 口 口 口 口
- * 口口 口口口 口
- */
- {0x22,0x60},{0x08,0xe0},{0xc8,0x80},{0xe2,0x00},
- /*
- * 口
- * 口口 口口
- * 口 口口
- */
- {0x8c,0x40},{0x6c,0x00},{0x8c,0x40},{0x6c,0x00},
- /*
- * 口 口口
- * 口口 口口
- * 口
- */
- {0x4c,0x80},{0xc6,0x00},{0x4c,0x80},{0xc6,0x00},
- /*
- * 口 口
- * 口 口口 口口口 口口
- * 口口口 口 口 口
- */
- {0x04,0xe0},{0x8c,0x80},{0xe4,0x00},{0x26,0x20},
- /*口
- * 口
- * 口 口口口口
- * 口
- */
- {0x44,0x44},{0x0f,0x00},{0x44,0x44},{0x0f,0x00},
- /*
- * 口口
- * 口口
- */
- {0x06,0x60},{0x06,0x60},{0x06,0x60},{0x06,0x60}
- };
- #define PASSSCORE 20
- struct Jimu
- {
- unsigned int dat;
- char x;
- unsigned char y;
- unsigned char type;
- unsigned char change;
- }Sign[3];//积木结构体
- unsigned char SysFlag=0;
- #define NEWSIGNFLAG 0
- #define DEADFLAG 1
- #define PAUSEFLAG 2
- unsigned char Score=0;
- unsigned char Level=1;
- unsigned char DelayCnt=5;
- unsigned char KeyBuffer=0;
- #define RESEVER 1
- #define CHANGE 2
- #define DOWN 3
- #define LEFT 4
- #define RIGHT 5
- #define PAUSE 6
- /*********************************
- 初始化MPU
- **********************************/
- void InitCpu(void)
- {
- TMOD=0x0;
- TH0=0;
- TL0=0;
- TR0=1;
- ET0=1;
- EA=1;
- }
- /*****************************
- 定时中断服务子程序
- ******************************/
- void Timer0Int(void) interrupt 1
- {
- switch(OSReadKey())
- {
- case 9:
- KeyBuffer=PAUSE;
- break;
- case 13:
- KeyBuffer=CHANGE;
- break;
- case 17:
- KeyBuffer=DOWN;
- break;
- case 21:
- KeyBuffer=RIGHT;
- break;
- case 25:
- KeyBuffer=LEFT;
- break;
- default:
- break;
- }
- }
- /******************************
- 画墙壁,初始化界面
- *******************************/
- void DrawBoard(void)
- {
- unsigned char n;
- for(n=0;n<12;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<20;n++)
- {
- Lcd_Rectangle(0,3*n,2,3*n+2,1);
- Lcd_Rectangle(33,3*n,35,3*n+2,1);
- }
- Lcd_WriteStr(4,0,"TOTO原创");
- Lcd_WriteStr(3,2,"Score:");
- Lcd_WriteStr(3,3,"Level:");
- }
- /***********************************
- 游戏结束处理
- ************************************/
- void GameOver(void)
- {
- if((SysFlag&(1<<deadflag))!=0)
- Lcd_WriteStr(3,1,"You Fail");
- else
- Lcd_WriteStr(3,1,"You Pass");
- }
- unsigned int code MaskTab[16]={
- 0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,
- 0x0100,0x0200,0x0400,0x0800,0x1000,0x2000,0x4000,0x8000
- };
- /**********************************
- 根据积木图标左下坐标X,Y来画出积木图标
- ***********************************/
- void DrawSign(struct Jimu Temp,unsigned char DrawMode)
- {
- unsigned char m,n;
- for(m=0;m<4;m++)
- for(n=0;n<4;n++)
- {
- if((Temp.dat&MaskTab[4*m+n])!=0)
- Lcd_Rectangle(Temp.x+n*3,Temp.y-2-3*m,Temp.x+n*3+2,Temp.y-3*m,DrawMode);
- }
- }
- /********************************
- 将积木图标值融入num数据中
- 也即把积木图标固定,无法再下降
- *********************************/
- FixSign(void)
- {
- unsigned char m,n;
- for(m=0;m<4;m++)//行循环
- for(n=0;n<4;n++)//列循环
- {
- if((Sign[0].dat&MaskTab[4*m+n])!=0)
- {
- num[20-(Sign[0].y-2)/3+m]|=MaskTab[11-Sign[0].x/3-n];
- }
- }
- }
- /********************************
- 判断积木图标中方块是否与障碍方块重合
- *********************************/
- unsigned char CheckIf(void)
- {
- unsigned char m,n;
- for(m=0;m<4;m++)//行循环
- for(n=0;n<4;n++)//列循环
- {
- if((Sign[1].dat&MaskTab[4*m+n])!=0)
- {
- if((num[20-(Sign[1].y-2)/3+m]&MaskTab[11-Sign[1].x/3-n])!=0)
- return 0;
- }
- }
- return 1;
- }
- /********************************
- 判断积木图标是否可以继续下降一格
- ********************************/
- unsigned char CheckIfDown(void)
- {
- Sign[1]=Sign[0];//
- Sign[1].y+=3;//假设下降一格
- return CheckIf();
-
- }
- /********************************
- 判断积木图标是否可以向左移动
- *********************************/
- unsigned char CheckIfLeft(void)
- {
- Sign[1]=Sign[0];
- Sign[1].x-=3;
- return CheckIf();
- }
- /********************************
- 判断积木图标是否可以向右移动
- *********************************/
- unsigned char CheckIfRight(void)
- {
- Sign[1]=Sign[0];
- Sign[1].x+=3;
- return CheckIf();
- }
- /********************************
- 判断是否可以旋转
- *********************************/
- unsigned char CheckIfRoll(void)
- {
- unsigned char i;
- unsigned int Temp;
- Sign[1]=Sign[0];
- if(++Sign[1].change>3)
- Sign[1].change=0;
- i=Sign[1].type*4+Sign[1].change;
- Temp=(unsigned int)Block[i][0]<<8;
- Temp=Temp|Block[i][1];
- Sign[1].dat=Temp;
-
- return CheckIf();
- }
- /********************************
- 寻找满格的行并做消除处理
- 最多寻找4个满行并做消除
- *********************************/
- void DelFull(void)
- {
- unsigned char m,n;
- unsigned char Temp;
- unsigned char Flag=0;
- Temp=(Sign[0].y-2)/3;
- if(Temp>=20)//防止越过了下边界
- Temp=1;
- else
- Temp=20-Temp;
- for(n=Temp+3;n>=Temp;n--)//积木图标的最顶行开始寻找满行比较有利于运算
- {
- if(num[n]==0xfff)
- {
- Flag=1;
- for(m=n+1;m<=19;m++)
- {
- num[m-1]=num[m];
- }
- num[m]=0x801;
- Score++;//每找到一个满行,则分数加1
- }
- }
- if(Flag)//为加速而设置并判断的标志,有已固定的积木有满格消行变化则重画积木界面
- {
- for(m=Temp;m<=19;m++)//为加速,不必要重第一行重画起,只需要从积木图标最下行开始往上的重画
- for(n=1;n<=10;n++)
- {
- if((num[m]&MaskTab[n])==0)
- {
- if(Lcd_ReadPixel(30-(n-1)*3,57-(m-1)*3)!=0)//为加速而做的读象素操作
- {
- Lcd_Rectangle(30-(n-1)*3,57-(m-1)*3,30-(n-1)*3+2,57-(m-1)*3+2,0);
- }
- }
- else
- {
- if(Lcd_ReadPixel(30-(n-1)*3,57-(m-1)*3)==0)//为加速而做的读象素操作
- {
- Lcd_Rectangle(30-(n-1)*3,57-(m-1)*3,30-(n-1)*3+2,57-(m-1)*3+2,1);
- }
- }
- }
- }
- }
- /*******************************
- 随机产生一个积木图标放到预产生区域并显示出来
- ********************************/
- void CreatSign(void)
- {
- unsigned char n;
- unsigned int Temp;
- DrawSign(Sign[2],0);//先清除
- n=Random()*28;
- Temp=(unsigned int)Block[n][0]<<8;
- Temp=Temp|Block[n][1];
- Sign[2].dat=Temp;
- Sign[2].x=45;
- Sign[2].y=4*3+2;
- Sign[2].type=n/4;
- Sign[2].change=n%4;
- DrawSign(Sign[2],1);//后画出
- }
- void PrintScore(void)
- {
- unsigned char Str[3];
- Str[0]=(Score/10)|0x30;
- Str[1]=(Score%10)|0x30;
- Str[2]=0;
- Lcd_WriteStr(6,2,Str);
- }
- void PrintLevel(void)
- {
- unsigned char Str[3];
- Str[0]=(Level/10)|0x30;
- Str[1]=(Level%10)|0x30;
- Str[2]=0;
- Lcd_WriteStr(6,3,Str);
- }
- /********************************
- 游戏的具体过程,也是贪吃蛇算法的关键部分
- *********************************/
- void GamePlay(void)
- {
- unsigned char m,n;
- unsigned int Temp;
- SysFlag|=1<<newsignflag; 刚开始初始化为需要产生新的积木图标
- InitRandom(TL0);
- Lcd_WriteStr(3,1,"Playing");
- PrintScore();
- PrintLevel();
- CreatSign();
- while(1)
- {
- if((SysFlag&(1<<newsignflag))==1) 判是否需要产生新的积木图标
- {
- SysFlag&=~(1<<newsignflag);
- Sign[0]=Sign[2];
- CreatSign();
- Sign[0].x=12;
- Sign[0].y=14;
- for(m=0;m<4;m++)//行循环
- {
- for(n=0;n<4;n++)//列循环
- {
- if((Sign[0].dat&MaskTab[15-m*4-n])==0)
- break;
- }
- if(n==4)
- Sign[0].y-=3;
- }//将积木图标出现置顶
-
- for(m=0;m<4;m++)//行循环
- for(n=0;n<4;n++)//列循环
- {
- if((Sign[0].dat&MaskTab[4*m+n])!=0)
- {
- if((num[20-(Sign[0].y-2)/3+m]&MaskTab[11-Sign[0].x/3-n])!=0)
- SysFlag|=1<<deadflag;
- }
- }
- if((SysFlag&(1<<deadflag))!=0)
- break;//如果产生新的积木图标中的方块与已固定好的方块重合,则死亡。游戏结束
- DrawSign(Sign[0],1);
- }
- switch(KeyBuffer)
- {
- case LEFT:
- KeyBuffer=0;
- if((SysFlag&(1<<pauseflag))==0)
- {
- if(CheckIfLeft())
- {
- DrawSign(Sign[0],0);
- Sign[0].x-=3;
- DrawSign(Sign[0],1);
- }
- }
- else
- {
- if(++Level>=10)
- Level=1;
- PrintLevel();
- }
- break;
- case RIGHT:
- KeyBuffer=0;
- if((SysFlag&(1<<pauseflag))==0)
- {
- if(CheckIfRight())
- {
- DrawSign(Sign[0],0);
- Sign[0].x+=3;
- DrawSign(Sign[0],1);
- }
- }
- else
- {
- if(++Level>=10)
- Level=1;
- PrintLevel();
- }
- break;
- case DOWN:
- KeyBuffer=0;
- if((SysFlag&(1<<pauseflag))==0)
- {
- if(CheckIfDown())//判断是否能继续下降一格
- {
- DrawSign(Sign[0],0);
- Sign[0].y+=3;
- DrawSign(Sign[0],1);
- }
- }
- break;
- case CHANGE:
- KeyBuffer=0;
- if((SysFlag&(1<<pauseflag))==0)
- {
- if(CheckIfRoll())
- {
- DrawSign(Sign[0],0);
- if(++Sign[0].change>3)
- Sign[0].change=0;
- m=Sign[0].type*4+Sign[0].change;
- Temp=(unsigned int)Block[m][0]<<8;
- Temp=Temp|Block[m][1];
- Sign[0].dat=Temp;
- DrawSign(Sign[0],1);
- }
- }
- break;
- case PAUSE:
- KeyBuffer=0;
- SysFlag^=1<<pauseflag;
- if((SysFlag&(1<<pauseflag))==0)
- {
- Lcd_WriteStr(3,1," ");
- Lcd_WriteStr(3,1,"Playing");
- }
- else
- {
- Lcd_WriteStr(3,1," ");
- Lcd_WriteStr(3,1,"Pause");
- }
- break;
- default:
- break;
- }
- if((SysFlag&(1<<pauseflag))!=0)
- continue;
- Delay(500);
- if(++DelayCnt>=2*(11-Level))
- {
- DelayCnt=0;
- if(CheckIfDown())//判断是否能继续下降一格
- {
- DrawSign(Sign[0],0);
- Sign[0].y+=3;
- DrawSign(Sign[0],1);
- }
- else
- {
- FixSign();
- DelFull();
- PrintScore();
- if(Score>=PASSSCORE)
- {
- SysFlag&=~(1<<deadflag);
- break;//跳出玩游戏过程
- }
- SysFlag|=1<<newsignflag; 新的积木图标产生标志置1
- }
- }
- }
- }
- void Main()
- {
- InitCpu();//初始化CPU
- Lcd_Reset(); //初始化LCD屏
- Lcd_Clear(0);//清屏
- DrawBoard();//画界面
- GamePlay();//玩游戏
- GameOver();//游戏结束
- while(1);//要想重玩,只能重启,可继续完善该游戏
- }
复制代码
- #include "REG52.H"
- #include "Key.h"
- #define OS_LONG_KEY_EN 1//如果应用中需要处理长按键动作,则定义为1,否则定义为0(如果应用中不需要处理长按动作,则建议定义为0,以节省代码空间)
- /***********************************************
- 功能说明:按键驱动扫描
- 入口参数:无
- 出口参数:扫描一次键盘以获得按键句柄
- 注:交OSReadKey()函数调用
- 需要根据实际硬件的键盘接口修改
- ***********************************************/
- unsigned char OSScanKey(void)
- {
- unsigned char Temp;
- unsigned char i;
- P2=0xff;
- Temp=P1;
- for(i=0;i<8;i++)
- {
- if((Temp&(1<<i))==0)
- break;
- }
- if(i<8)
- return i+1;
- else
- return 0;
- }
- /**********************************************
- 功能说明:读取按键动作
- 入口参数:无
- 出口参数:返回按键动作
- 注:没有按键动作,则返回0,1号按键动作,返回1-4
- 2号按键动作,返回5-8,如此类推
- 返回1、5、..:确认短按按下
- 返回2、6、..:确认长按按下
- 返回3、7、..:确认短按松开
- 返回4、8、..:确认长按松开
- ***********************************************/
- 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=OSScanKey();
- 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;
- }
- /***************************************************************/
复制代码
|
-
-
er.rar
63.09 KB, 下载次数: 420, 下载积分: 黑币 -5
-
-
蛇.rar
86 KB, 下载次数: 440, 下载积分: 黑币 -5
评分
-
查看全部评分
|