源程序:
- /*****************************************************************************************
- 名稱:《基于8052單片機和8X16點陣屏俄羅斯方塊游戲板》
- 時間:05月23日17時
- 單位:武漢理工大學信息學院電子1003班
- 作者:顏百千
- *****************************************************************************************/
- #include<reg52.h>
- #include<stdlib.h>
- #include<math.h>
- #define uchar unsigned char
- sbit slock=P2^7; //譯碼器輸出使能端
- sbit upkey=P2^3; //“旋轉圖形/向上”按鍵
- sbit leftkey=P2^1; //“左移/向左”按鍵
- sbit rightkey=P2^2; //“右移/向右”按鍵
- sbit downkey=P2^0; //“快速下移/向下”按鍵
- sbit duan=P2^5; //數碼管段選信號所用鎖存器的鎖存允許端
- sbit wei=P2^6; //數碼管位選信號所用鎖存器的鎖存允許端
- sbit startsuspendkey=P2^4; //“開始/暫停/繼續”多功能切換按鍵
- /***********************************圖形編碼機制介紹**************************************
- 1.由于俄羅斯方塊圖形的寬度和高度最多只有四位,所以要以4X4為基本單元。
- 2.硬件采用16行掃描、8位送顯示信號
- 3.各個圖形的寬度不一致,所以要人為給圖形設定居中位置。
- 若圖形寬度為偶數可直接將其居中,若為奇數則靠左居中。
- 4.由于圖形需要旋轉,所以由基本的圖形會衍生出另外3種圖形。
- 5.因此每個圖形應該給定4個8位的二進制碼,并放入一個二維數組里。
- 6.經典俄羅斯方塊游戲里有19種不同形狀的方塊,包括旋轉得到的。
- 7.數組的第一個下標為該圖形的編號
- *****************************************************************************************/
- uchar code allshape[19][4]={0x00,0x00,0x18,0x18,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x3c,
- 0x00,0x08,0x18,0x10,0x00,0x00,0x30,0x18,0x00,0x10,0x18,0x08,
- 0x00,0x00,0x18,0x30,0x00,0x08,0x08,0x18,0x00,0x00,0x38,0x08,
- 0x00,0x18,0x10,0x10,0x00,0x00,0x20,0x38,0x00,0x10,0x10,0x18,
- 0x00,0x00,0x08,0x38,0x00,0x18,0x08,0x08,0x00,0x00,0x38,0x20,
- 0x00,0x00,0x10,0x38,0x00,0x08,0x18,0x08,0x00,0x00,0x38,0x10,
- 0x00,0x10,0x18,0x10};
- /****************************************************************************************/
- uchar code number[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //數碼管數形顯示編碼
- uchar code weima[4]={0x01,0x02,0x04,0x08}; //位選信號編碼,方便寫循環使用
- char shapewidth[19]={2,1,4,2,3,2,3,2,3,2,3,2,3,2,3,3,2,3,2}; //各個圖形的寬度屬性,用于判斷左移和右移的步格數上限
- char shaperotate[19]={0,2,1,4,3,6,5,8,9,10,7,12,13,14,11,16,17,18,15}; //旋轉圖形時,用于改變圖形的編號以實現圖形的切換
- uchar staticdata[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xff}; //用于存儲方塊降落后固定顯示的圖形信息
- uchar rate[5]={0,1,3,6,10}; //規定一次性消掉的行數的分數獎勵機制
- /****************************************全局變量聲明************************************/
- char y; //方塊位置屬性:底部下落的高度,y=0時:剛剛出現,y=15時:下落到屏幕最底部
- char shapenum; //方塊形狀屬性:從0到18
- int left; //方塊位置屬性:方塊偏離居中位置的格數,不同的方塊left值的上限不同
- int mark; //玩家分數變量
- int speed; //方塊下落速度變量
- int initialspeed; //方塊下落的初始速度
- int systemspeed; //系統下落速度,此值會隨著玩家分數的增加而減小,相應的下落速度會增大
- int fastspeed; //當用戶按下down鍵時,方塊下落速度為此值
- int k; //一個全局循環變量,“幀數”變量
- int startcontrol=1; //開始畫面狀態指示變量,為1時說明程序進入開機歡迎界面
- int suspendcontrol=0; //游戲暫停與游戲繼續畫面狀態指示變量,為1說明處在暫停界面,為0說明處在繼續畫面
- int randnum; //隨機數變量,用于產生隨機方塊
- /****************************************************************************************/
- /****************************************函數聲明****************************************/
- void delayms(int); //粗略延時函數
- uchar move(uchar,int); //對二進制碼實行移位,可為負值
- void shapedisplay(); //對點陣掃描一場,對數碼管掃描一場,用于顯示圖形和數字
- void keyscan(); //對所有鍵盤掃描一次,并執行相應運算和操作
- uchar check(char,int); //用于檢查方塊將要下落的位置或是將要旋轉的位置是否有障礙
- uchar shapedisappear(); //用于消行,返回一次性消掉的行數
- numberdisplay(int amark); //用于四位數字顯示
- void startimage(); //游戲等待開始畫面函數
- void overimage(); //游戲結束后的畫面
- void dataset(); //對數據初始化,為游戲重新開始做準備
- /****************************************************************************************/
- /*****************************************主函數*****************************************/
- void main()
- {
- char j;
- startimage(); //進入開機,函數內有鍵盤掃描,只有按下“開始”鍵會退出函數,否則不退出
- dataset(); //對數據進行初始化
- while(1){ //進入大循環
- k=speed; //確定顯示的幀數
- while(k--){
- keyscan(); //掃描鍵盤,放入高速循環語句中提高鍵盤的響應速度,并檢測此時用戶是否有相應請求
- shapedisplay(); //顯示圖形和數字
- }
- y++; //圖形下落一格
- if(check(shapenum,left)){ //在沒有顯示之前判斷將要下落的位置是否有障礙物,如果有障礙就進入到if語句中
- if(y==1){ //如果y=1;說明方塊剛出現就遇到障礙物了,這時游戲需結束
- overimage(); //進入游戲結束畫面,此函數內沒有鍵盤掃描,運行一段時間會自動退出
- startimage(); //又進入開機畫面
- dataset(); //對數據進行初始化,將前一用戶數據清零
- }
- else{ //遇到障礙物,但還不至于圖形不能出現
- y--; //y回到原值
- for(j=0;j<4;j++){ //將下落形狀的值賦給固定圖形,形成停留顯示的效果
- staticdata[y+j]+=move(allshape[shapenum][j],left);
- }
- mark+=rate[shapedisappear()]; //消掉已拼滿的函數,并記錄所得分數
- y=0; //為下一個方塊賦屬性值:從第一行出現
- left=0; //為下一個方塊賦屬性值:居中顯示
- randnum=rand()%19;shapenum=randnum; //為下一個方塊賦屬性值:給定形狀
- systemspeed=initialspeed-10*(mark/40); //計算相應分數下的系統速度值,分數越高,速度越快
- speed=systemspeed; //將此值賦給速度控制量
- }
- }
- }
- }
- /****************************************************************************************/
- /***************************************自定義函數***************************************/
- void delayms(int xms) //粗略的延時函數
- {
- int i,j;
- for(i=xms;i>0;i--)
- for(j=110;j>0;j--);
- }
- /****************************************************************************************/
- uchar move(uchar aa,int anum) //移位函數
- {
- if(anum>=0)
- aa<<=anum;
- else
- aa>>=(-anum);
- return aa;
- }
- /****************************************************************************************/
- void shapedisplay() //顯示函數
- {
- uchar j;
- for(j=y<3?3-y:0;j<4;j++){ //顯示動態方塊
- slock=1;P1=j+y-3;P3=move(allshape[shapenum][j],left);
- slock=0;delayms(1);P3=0x00;
- }
- for(j=0;j<16;j++){ //顯示靜態方塊
- slock=1;P1=j;P3=staticdata[j+3];
- slock=0;delayms(1);P3=0x00;
- }
- numberdisplay(mark); //分數顯示
- }
- /****************************************************************************************/
- numberdisplay(int amark) //大數拆分并顯示,帶去無效零功能
- {
- char i;
- uchar num[4];
- num[0]=amark/1000%10;num[1]=amark/100%10;num[2]=amark/10%10;num[3]=amark%10;
- if(amark<10){ //顯示一位數
- for(i=3;i<4;i++){
- P0=0xff;
- duan=1;
- P0=number[num[i]];
- duan=0;
- P0=0x00;
- wei=1;
- P0=weima[i];
- wei=0;
- delayms(1);
- wei=1;
- P0=0x00;
- wei=0;
- }
- }
- else if(amark<100){ //顯示兩位數
- for(i=2;i<4;i++){
- P0=0xff;
- duan=1;
- P0=number[num[i]];
- duan=0;
- P0=0x00;
- wei=1;
- P0=weima[i];
- wei=0;
- delayms(1);
- wei=1;
- P0=0x00;
- wei=0;
- }
- }
- else if(amark<1000){ //顯示三位數
- for(i=1;i<4;i++){
- P0=0xff;
- duan=1;
- P0=number[num[i]];
- duan=0;
- P0=0x00;
- wei=1;
- P0=weima[i];
- wei=0;
- delayms(1);
- wei=1;
- P0=0x00;
- wei=0;
- }
- }
- else{ //顯示四位數
- for(i=0;i<4;i++){
- P0=0xff;
- duan=1;
- P0=number[num[i]];
- duan=0;
- P0=0x00;
- wei=1;
- P0=weima[i];
- wei=0;
- delayms(1);
- wei=1;
- P0=0x00;
- wei=0;
- }
- }
- return 0;
- }
- /****************************************************************************************/
- void keyscan() //鍵盤掃錨并執行用戶輸入的指令
- {
- if(leftkey==0&&(left<(shapewidth[shapenum]<3?3:2))&&!check(shapenum,left+1)&&
- startcontrol==0&&suspendcontrol==0){
- delayms(10); //按鍵無效條件:1.左移超邊緣;2.左移遇障礙;3.處在歡迎界面;4.處在暫停界面
- if(leftkey==0){
- left++; //按鍵命令:方塊左移一位
- speed=systemspeed;
- while(!leftkey){
- shapedisplay();
- }
- }
- }
- if(rightkey==0&&(left>(shapewidth[shapenum]<3?shapewidth[shapenum]-5:shapewidth[shapenum]-6))&&
- !check(shapenum,left-1)&&startcontrol==0&&suspendcontrol==0){
- delayms(10); //按鍵無效條件:1.右移超邊緣;2.右移遇障礙;3.處在歡迎界面;4.處在暫停界面
- if(rightkey==0){
- left--; //按鍵命令:方塊右移一位
- speed=systemspeed;
- while(!rightkey){
- shapedisplay();
- }
- }
- }
- if(upkey==0&&!check(shaperotate[shapenum],left)&&(left<(shapewidth[shaperotate[shapenum]]<3?4:3))
- &&(left>(shapewidth[shaperotate[shapenum]]<3?shapewidth[shaperotate[shapenum]]-6:shapewidth[shapenum]-7))
- &&startcontrol==0&&suspendcontrol==0){
- delayms(10); //按鍵無效條件:1.翻轉超左右邊緣;2.翻轉遇障礙;3.處在歡迎界面;4.進入暫停界面
- if(upkey==0){
- shapenum=shaperotate[shapenum]; //按鍵命令:將翻轉后的圖形編號賦給要顯示的圖形編號
- speed=systemspeed;
- while(!upkey){
- shapedisplay();
- }
- }
- }
- if(downkey==0&&speed!=fastspeed&&startcontrol==0&&suspendcontrol==0){
- delayms(10); //按鍵無效條件:1.已經進入快速下降狀態;2.處在歡迎界面;3.進入暫停界面
- if(downkey==0){
- speed=fastspeed; //按鍵命令:將方塊下落速度加快
- k=speed;
- while(!downkey){
- shapedisplay();
- }
- }
- }
- if(startsuspendkey==0&&startcontrol==1&&suspendcontrol==0){
- delayms(10); //按鍵有效條件:1.處在開始歡迎界面;2.處在暫停界面
- if(startsuspendkey==0){
- startcontrol=0;
- suspendcontrol=0; //按鍵命令:使進入繼續游戲狀態
- while(!startsuspendkey){
- }
- }
- }
- if(startsuspendkey==0&&startcontrol==0&&suspendcontrol==0){
- delayms(10); //按鍵無效條件:1.處在開始歡迎界面;2.處在暫停狀態
- if(startsuspendkey==0){
- suspendcontrol=1;
- startcontrol=0; //按鍵命令:狀態切換,使進入暫停狀態
- while(!startsuspendkey){
- shapedisplay();
- }
- while(suspendcontrol){
- shapedisplay();
- keyscan(); //等待結束暫停狀態的命令
- }
- }
- }
- if(startsuspendkey==0&&startcontrol==0&&suspendcontrol==1){
- delayms(10); //按鍵有效條件:處在暫停界面
- if(startsuspendkey==0){
- suspendcontrol=0;
- startcontrol=0; //按鍵命令:狀態切換,使進入繼續游戲狀態
- while(!startsuspendkey){
- shapedisplay();
- }
- }
- }
- }
- /****************************************************************************************/
- uchar check(char ashapenum,int aleft) //判斷方塊是否會遇到障礙物
- {
- char i=3,j=0;
- while(!j&&i>=0){
- if((move(allshape[ashapenum][i],aleft)+staticdata[y+i])!=(move(allshape[ashapenum][i],aleft)|staticdata[y+i])){
- j++;
- }
- i--;
- }
- return j; //返回0,說明沒有障礙
- }
- /****************************************************************************************/
- uchar shapedisappear() //方塊落定后消掉拼滿的行,并使沒有拼滿的行整體下移填補空缺行
- {
- char i,j,r=4;
- for(i=0;i<r;i++){
- if(staticdata[y+3-i]==0xff){
- for(j=y+3-i;j>0;j--){
- staticdata[j]=staticdata[j-1];
- }
- i--,r--;
- }
- }
- return 4-r; //函數返回一次性消掉的行的數目
- }
- /****************************************************************************************/
- void startimage() //開機歡迎畫面,在沒有按鍵作用的時候會不斷執行
- {
- uchar i,j;
- startcontrol=1;
- while(startcontrol){
- for(i=10;i>0;i--){
- for(j=0;j<16;j+=2){
- slock=1;P1=j;P3=0xaa;
- slock=0;delayms(1);P3=0x00;
- }
- for(j=1;j<16;j+=2){
- slock=1;P1=j;P3=0x55;
- slock=0;delayms(1);P3=0x00;
- }
- keyscan(); //隨時響應用戶輸入
- }
- for(i=10;i>0;i--){
- for(j=1;j<16;j+=2){
- slock=1;P1=j;P3=0xaa;
- slock=0;delayms(1);P3=0x00;
- }
- for(j=0;j<16;j+=2){
- slock=1;P1=j;P3=0x55;
- slock=0;delayms(1);P3=0x00;
- }
- keyscan(); //隨時響應用戶輸入
- }
- }
- }
- /****************************************************************************************/
- void overimage() //游戲結束畫面,分數會強制閃爍8次,并自動結束
- {
- int i,j;
- for(j=0;j<8;j++){
- for(i=0;i<200;i++){
- numberdisplay(mark);
- }
- delayms(500);
- }
- }
- /****************************************************************************************/
- void dataset() //數據全部清零,重新開始游戲
- {
- char j;
- y=0;
- left=0;
- shapenum=0;
- initialspeed=100;
- speed=initialspeed;
- systemspeed=initialspeed;
- fastspeed=5;
- randnum=rand()%19;
- shapenum=randnum;
- mark=0;
- for(j=0;j<19;j++){ //清除點陣上的顯示數據
- staticdata[j]=0;
- }
- }
- /****************************************************************************************/
復制代碼 |