|
- #ifndef _MAIN_H
- #define _MAIN_H
- #include <reg52.h>
- #define LcdDataPort P2 //數據端口
- #ifndef UCHAR_DEF
- #define UCHAR_DEF
- typedef unsigned char uchar;
- #endif
- sbit Reset = P3^0; //復位
- sbit RS = P3^1; //指令數據選擇
- sbit E = P3^2; //指令數據控制
- sbit CS1 = P3^4; //左屏幕選擇,低電平有效
- sbit CS2 = P3^5; //右屏幕選擇
- sbit RW = P3^3; //讀寫控制
- sbit busy = P2^7; //忙標志
- void SetOnOff(uchar onoff); //開關顯示
- void SelectScreen(uchar screen);//選擇屏幕
- void ClearScreen(uchar screen); //清屏
- void Show1616(uchar lin,uchar colum,uchar *address);//顯示一個漢字
- void CheckState(); //判斷狀態
- void LcdDelay(unsigned int time); //延時
- void WriteData(uchar dat); //寫數據
- void SendCommand(uchar command); //寫指令
- void SetLine(uchar line); //置行地址
- void SetColum(uchar colum);//置列地址
- void SetStartLine(uchar startline);//置顯示起始行
- void InitLcd(); //初始化
- void ResetLcd(); //復位
- #endif
- /*********************************************************************/
- /***********************************lcd.c****************************************/
- void CheckState()
- {
- E = 1;
- RS = 0;
- RW = 1;
- LcdDataPort = 0xff;
- while(!busy);
- }
- void LcdDelay(unsigned int time)
- {
- while(time --);
- }
- void WriteData(uchar dat)
- {
- CheckState();
- E = 1;
- RS = 1;
- RW = 0;
- LcdDataPort = dat;
- E = 0;
- }
- void SendCommand(uchar command)
- {
- CheckState();
- E = 1;
- RW = 0;
- RS = 0;
- LcdDataPort = command;
- E = 0;
- }
- void SelectScreen(uchar screen) //0-全屏,1-左屏,2-右屏
- {
- switch(screen)
- {
- case 0 :
- CS1 = 0;
- LcdDelay(2);
- CS2 = 1;
- LcdDelay(2);
- break;
- case 1 :
- CS1 = 1;
- LcdDelay(2);
- CS2 = 0;
- LcdDelay(2);
- break;
- case 2 :
- CS1 = 0;
- LcdDelay(2);
- CS2 = 0;
- LcdDelay(2);
- break;
- }
- }
- void ClearScreen(uchar screen) // screen 0-全屏,1-左屏,2-右屏
- {
- uchar i,j;
- SelectScreen(screen);
- for(i = 0;i < 8;i ++)
- {
- SetLine(i);
- SetColum(0);
- for(j = 0;j < 64; j ++)
- WriteData(0);
- }
- }
- void SetLine(uchar line) //line -> 0 : 7
- {
- line = line & 0x07;
- line = line | 0xb8; //1011 1xxx
- SendCommand(line);
- }
- void SetColum(uchar colum) //colum -> 0 :63
- {
- colum = colum & 0x3f;
- colum = colum | 0x40; //01xx xxxx
- SendCommand(colum);
- }
- void SetStartLine(uchar startline) //startline -> 0 : 63
- {
- startline = startline & 0x3f;
- startline = startline | 0xc0; //11xxxxxx
- SendCommand(startline);
- }
- void SetOnOff(uchar onoff) //1-開顯示 0-關
- {
- if(onoff == 1)
- SendCommand(0x3f); //0011 111x
- else
- SendCommand(0x3e);
- }
- void ResetLcd()
- {
- Reset = 0;
- LcdDelay(2);
- Reset = 1;
- LcdDelay(2);
- RS0 = 0;
- LcdDelay(2);
- RS1 = 0;
- LcdDelay(2);
- SetOnOff(1);
- }
- void InitLcd()
- {
- ResetLcd();
- SetOnOff(0);
- ClearScreen(2);
- SetLine(0);
- SetColum(0);
- SetStartLine(0);
- SetOnOff(1);
- }
- void Show1616(uchar lin,uchar colum,uchar *address)
- {
- uchar i;
- SetLine(lin);
- SetColum(colum);
- for(i = 0;i < 16;i ++)
- WriteData(*(address ++));
- SetLine(lin + 1);
- SetColum(colum);
- for(i = 0;i < 16;i ++)
- WriteData(*(address ++));
- }
- /*******************************************************************************/
- /********************************main.c***********************************************/
- #include <reg52.h>
- const uchar code HZ_tab[] = {44
- };
- void main()
- {
- uchar i,line,colum ;
- uchar *address ;
- InitLcd();
- while(1)
- {
- colum = 16;
- line = 1;
- address = HZ_tab;
- SetOnOff(0); //關顯示
- for(i = 1;i < 7;i ++)
- {
- if(i < 4)
- SelectScreen(0);
- else
- SelectScreen(1);
- Show1616(line,colum ,address);
- colum += 16;
- if(colum >63)
- colum = 0;
- address += 32; //向DDRAM中寫入數據
- }
- line = 5;
- colum = 0;
- for(i = 0;i <8; i ++)
- {
- if(i < 4)
- SelectScreen(0);
- else
- SelectScreen(1);
- Show1616(line,colum ,address);
- colum += 16;
- if(colum >63)
- colum = 0;
- address += 32;
- }
- SelectScreen(2);
- SetOnOff(1); // 開顯示
- for(i = 0;i < 50;i ++) //延時
- LcdDelay(30000);
- }
- }
-
-
-
- /************說明******************************
- 此程序包含一個俄羅斯方塊.c 文件和一個12864.h 文件
- ********************俄羅斯方塊.c文件**************************/
- #include "reg51.h"
- #include "12864.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)
- sbit K1=P3^4;
- sbit K2=P3^5;
- sbit K3=P3^6;
- sbit K4=P3^7;
- 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;
- /*********************************************************/
- #define N 25
- /************************************
- 偽隨機數發生器
- *************************************/
- 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++);
- }
- /*********************************
- 初始化MPU
- **********************************/
- void InitCpu(void)
- {
- TMOD=0x0;
- TH0=0;
- TL0=0;
- TR0=1;
- ET0=1;
- EX1=1;
- EA=1;
- TCON|=0x04;
- }
- /****************************
- welcome 游戲選擇界面
- /**********************/
- void welcome()
- {
- Lcd_WriteStr(0,0,"歡迎來玩");
- Lcd_WriteStr(0,1,"俄羅斯方塊");
- Lcd_WriteStr(0,2,"設置按K1");
- Lcd_WriteStr(0,2,"開玩按K2");
- }
- /*************俄羅斯方塊部分
- /******************************
- 畫墻壁,初始化界面
- *******************************/
- void DrawBoard(void)
- {
- unsigned char n;
- for(n=0;n<12;n++) ////畫上下兩邊的墻壁
- {
- Lcd_Rectangle(3*n,0,3*n+2,2,1);////在最上面一行畫個2*2的方塊
- Lcd_Rectangle(3*n,60,3*n+2,62,1);////在最下面一行畫個2*2的方塊
- }
- for(n=0;n<20;n++) ////畫左右兩邊的墻壁
- {
- Lcd_Rectangle(0,3*n,2,3*n+2,1); ////在左面畫2*2的方塊
- Lcd_Rectangle(33,3*n,35,3*n+2,1);////在右面畫2*2的方塊
- }
- Lcd_WriteStr(4,0,"經典游戲");
- Lcd_WriteStr(3,2,"Score:");
- Lcd_WriteStr(3,3,"Level:");
- }
- /***********************************
- 游戲結束處理
- ************************************/
- void GameOver(void)
- {
- if((SysFlag&(1<<DEADFLAG))!=0)
- Lcd_WriteStr(3,1,"You Fail");////SysFlag=2
- else
- Lcd_WriteStr(3,1,"You Pass");////SysFlag=1或=0
- }
- 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數據中
- 也即把積木圖標固定,無法再下降
- *********************************/
- void 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;
- ////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)
- //為加速而做的讀象素操作
- ////如果該像素為1,即為黑點
- {
- Lcd_Rectangle(30-(n-1)*3,57-(m-1)*3,30-(n-1)*3+2,57-(m-1)*3+2,0);
- }////將給像素設置為0,即為空白
- }
- else
- {
- if(Lcd_ReadPixel(30-(n-1)*3,57-(m-1)*3)==0)//為加速而做的讀象素操作
- { ////如果該像素為0
- Lcd_Rectangle(30-(n-1)*3,57-(m-1)*3,30-(n-1)*3+2,57-(m-1)*3+2,1);
- } ////將給像素設置為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;//剛開始初始化為需要產生新的積木圖標 ////SysFlag=1
- InitRandom(TL0); ////用以產生隨即數
- Lcd_WriteStr(3,1,"Playing");
- PrintScore();
- PrintLevel();
- CreatSign();////先清空積木顯示區域,在隨即產生一個類型的積木
- while(1)
- {
- if((SysFlag&(1<<NEWSIGNFLAG))==1)//判是否需要產生新的積木圖標
- {////SysFlag=1時產生新積木
- SysFlag&=~(1<<NEWSIGNFLAG); ////SysFlag=0
- 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;////測試Sign[0].dat的每一位,如果為該位為1,則繼續測試下一位
- ////若為0,則直接測試下半字節
- }
- if(n==4) ////如果在半個字節里面每一位數據都是1,則將縱坐標-3,即向上移動一個小方格
- 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)
- ////2為上墻壁,(Sign[0].y-2)/3為積木的總高度
- ////num[20-(Sign[0].y-2)/3+m] 從下往上變化
- ////MaskTab[11-Sign[0].x/3-n]為從4*4積木的最右邊往積木的最左邊變化
- SysFlag|=1<<DEADFLAG; ////SysFlag=2;
- }
- }
- if((SysFlag&(1<<DEADFLAG))!=0)
- break;//如果產生新的積木圖標中的方塊與已固定好的方塊重合,則死亡。游戲結束
- DrawSign(Sign[0],1);
- }
- if((CheckIfLeft())&&(K3==0)) //左
- {
- DrawSign(Sign[0],0);
- Sign[0].x-=3;
- DrawSign(Sign[0],1);
- }
- if((CheckIfRight())&&(K4==0)) //右
- {
- DrawSign(Sign[0],0);
- Sign[0].x+=3;
- DrawSign(Sign[0],1);
- }
- if((CheckIfDown())&&(K2==0))//下
- {
- DrawSign(Sign[0],0);
- Sign[0].y+=3;
- DrawSign(Sign[0],1);
- }
- if((CheckIfRoll())&&(K1==0)) //翻轉
- {
- DrawSign(Sign[0],0);
- if(++Sign[0].change>3)
- Sign[0].change=0;
- m=Sign[0].type*4+Sign[0].change;
- ////將Block數組中的元素分為7類,type為該類型;該類型分為4種,change為種類
- ////所以,change加1之后就表示翻轉之后的積木形態
- Temp=(unsigned int)Block[m][0]<<8;
- Temp=Temp|Block[m][1]; ////讀取翻轉之后積木形態的dat數據
- Sign[0].dat=Temp; ////賦dat值給積木結構體的dat
- DrawSign(Sign[0],1); ////畫出翻轉后的積木
- }
- ////2
- 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(); ////將積木移入num數組中
- DelFull(); ////消行處理
- PrintScore();
- if(Score>=PASSSCORE)
- {
- SysFlag&=~(1<<DEADFLAG); ////SysFlag=1或=0
- break;//跳出玩游戲過程
- }
- SysFlag|=1<<NEWSIGNFLAG;//新的積木圖標產生標志置1
- }
- }
- }
- }
- void Main()
- {
- InitCpu();//初始化CPU
- Lcd_Reset(); //初始化LCD屏
- Lcd_Clear(0);//清屏
- Lcd_Reset(); //初始化LCD屏
- Lcd_Clear(0);//清屏
- DrawBoard();//畫界面
- GamePlay();//玩游戲
- GameOver();//游戲結束
- Lcd_Reset(); //初始化LCD屏
- Lcd_Clear(0);//清屏
- }
復制代碼
|
|