基於51單片機的俄羅斯方塊遊戲

俄羅斯方塊遊戲算法 請參考俄羅斯方塊遊戲的算法

1.概述
俄羅斯方塊是一款風靡全球的益智遊戲。它規則簡單,容易上手,且遊戲過程變化無窮,使用戶在遊戲中得到樂趣。 
本設計是採用單片機來實現的智能俄羅斯方塊遊戲,該設計選用的處理器型號爲AT89C51的單片機。重點從軟件工程角度論述了俄羅斯方塊模型構造,圖形旋轉,座標變換,雙人遊戲中多任務實時操作的設計方法與實現。
在這裏插入圖片描述
2.硬件設計
總體電路圖
在這裏插入圖片描述
硬件電路相對簡單,主要爲:

  1. 單片機最小系統
  2. LCD12864顯示屏電路
  3. 按鍵電路
  4. 系統電源

3.軟件設計
(1)LCD12864顯示屏驅動程序

#define LCD_DATA P2
sbit LCD_RS=P1^0;
sbit LCD_RW=P1^1;
sbit LCD_E=P1^2;
sbit LCD_CS2=P1^4;		//右屏選擇(左右屏有時候相反)
sbit LCD_CS1=P1^3;		//左屏選擇
sbit LCD_RST=P3^7;
struct
{
	unsigned char mode;//類型
	unsigned char shape;//形狀
	unsigned char x;//x座標
	unsigned char y;//y座標
	unsigned int box;//定義方塊緩存
}s_box;	//定義方塊結構體
//LCD檢測忙狀態函數
void LCD_check_busy()
{
	unsigned char temp;
	LCD_RS=0;
	LCD_RW=1;
	do
	{
		LCD_DATA=0xff;
		LCD_E=1;
		temp=LCD_DATA;
		LCD_E=0;
	}while((temp&0x80)==0x80);		
}
//寫指令代碼(cs爲0選左屏,cs爲1選右屏)
void LCD_W_code(unsigned char tpcode,bit cs)
{
	LCD_RS=0;
	LCD_RW=0;
	LCD_CS2=~cs;
	LCD_CS1=cs;
	LCD_DATA=tpcode;
	LCD_E=1;
	_nop_();
	LCD_E=0;
}
//寫顯示數據(cs爲0選左屏,cs爲1選右屏)
void LCD_W_data(unsigned char tpdata,bit cs)
{
	LCD_check_busy();
	LCD_RS=1;
	LCD_RW=0;
	LCD_CS2=~cs;
	LCD_CS1=cs;	
	LCD_DATA=tpdata;
	LCD_E=1;	
	_nop_();
	LCD_E=0;
}

//LCD初始化函數
void LCD_initialize()
{
	LCD_RST=0;
	_nop_();
	_nop_();
	LCD_RST=1;
	LCD_W_code(0x3f,0);		//開顯示設置	
	LCD_W_code(0xc0,0);		//設置顯示起始行爲第一行	
	LCD_W_code(0xb8,0);		//頁面地址設置	
	LCD_W_code(0x40,0);		//列地址設爲0
	LCD_W_code(0x3f,1);
	LCD_W_code(0xc0,1);	
	LCD_W_code(0xb8,1);
	LCD_W_code(0x40,1);
}
//LCD清屏函數
void LCD_clear()
{
	unsigned char i,j;
	for(j=0;j<8;j++)
	{
		LCD_W_code(0xb8+j,0);
		LCD_W_code(0x40,0);
		LCD_W_code(0xb8+j,1);
		LCD_W_code(0x40,1);
		for(i=0;i<64;i++)
			{	
				LCD_W_data(0x00,0);	
				LCD_W_data(0x00,1);
			}
	}
}
//LCD顯示字符串函數(word表示要顯示的字符串,
 //length表示要顯示的字符串寬度,
 //x表示首字符所在行數,
 //y表示首字符所在列數)
void LCD_display_word(unsigned char word[],
                      unsigned int length,
					  unsigned char x,
					  unsigned char y)
{
	unsigned char i;
	for(i=0;i<length;i++)
	{
		
		LCD_W_code(0xb8+x,0);
		LCD_W_code(0xb8+x,1);
		if(y+i<64)
		{
			LCD_W_code(0x40+y+i,0);	
			LCD_W_data(word[i],0);
		}
		else
		{
			LCD_W_code(y+i,1);	
			LCD_W_data(word[i],1);
		}
	}
}
//LCD畫全屏函數
void LCD_full_draw(unsigned char word[])
{
	unsigned char i,j;
	for(i=0;i<8;i++)
	{
		LCD_W_code(0xb8+i,0);
		LCD_W_code(0x40,0);	
		for(j=0;j<64;j++)
		{
			LCD_W_data(word[i*128+j],0);
		}
		LCD_W_code(0xb8+i,1);
		LCD_W_code(0x40,1);	
		for(j=0;j<64;j++)
		{
			LCD_W_data(word[i*128+64+j],1);
		}			
	}
}
//LCD顯示一個字節函數(
  //x表示x座標,
  //y表示y座標,
  //tpdata表示要顯示的數據)
void LCD_display_byte(unsigned char x,
					  unsigned char y,
					  unsigned char tpdata)
{
	if(x<64)
	{
		LCD_W_code(0xb8+y,0);
		LCD_W_code(0x40+x,0);
		LCD_W_data(tpdata,0);	
	}
	else
	{
		LCD_W_code(0xb8+y,1);
		LCD_W_code(x,1);
		LCD_W_data(tpdata,1);	
	}
} 

void LCD_draw(unsigned char word[])
{
  unsigned char i,j;
  for(i=0;i<8;i++)
  {
    LCD_W_code(0xb8+i,1);
	LCD_W_code(0x40+20,1);
	for(j=0;j<44;j++)
	{
	  LCD_W_data(word[i*44+j],1);
	}
  }
}
//基本界面顯示函數
void display_basic()
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		LCD_display_byte(GAME_LOCATION,i,0xff);
		LCD_display_byte(GAME_LOCATION+41,i,0xff);
	}
}
//刷新遊戲區域函數
void refurbish_display()
{
	unsigned char i,j,tpdata;
	for(i=0;i<8;i++)
	{
		for(j=0;j<10;j++)
		{
			tpdata=0x00;
			if(  (Box_Ram[2*i]>>(12-j))&0x0001==1  )
			{
				tpdata=0x0f;
			}
			if(  (Box_Ram[2*i+1]>>(12-j))&0x0001==1  )
			{
				tpdata|=0xf0;
			}
			LCD_display_byte(GAME_LOCATION+1+j*4,i,tpdata);
			LCD_display_byte(GAME_LOCATION+2+j*4,i,0xbb&tpdata);
			LCD_display_byte(GAME_LOCATION+3+j*4,i,0xdd&tpdata);
			LCD_display_byte(GAME_LOCATION+4+j*4,i,tpdata);
		}
	}
}

(2)按鍵驅動程序

sbit button_a = P3^4;	 //變形
sbit button_b = P3^5;	//開始
sbit up = P3^2;	   //暫停開始
sbit down = P3^0;
sbit left = P3^1;
sbit right = P3^3;

//基本按鍵程序(返回0表示沒按鍵被按下,返回1表示down被按下,返回2表示up被按下,返回3表示button_a被按下,返回4表示left被按下,返回5表示right被按下)
//遊戲中按鍵識別程序(有優先級,從高到低依次是button_a_reg>down>left>right>up)
unsigned char basic_button()
{
	unsigned char tpflag=0;
	if(button_b==0)
	{
	    if(button_b_reg<button_delay*8)
		{
		  button_b_reg++;
		}
		else
		{
		  button_b_reg=0;
		  tpflag=6;
		}
	}
	else
	{
   	     button_b_reg=button_delay*8;
	}
	if(down==0)
	{
		if(down_reg<button_delay)//按鍵一直被按下時設置時間間隔觸發
		{
			down_reg++;
		}
		else
		{
			down_reg=0;
			tpflag=1;//返回1表示down被按下
		}		
	}
	else
	{
		down_reg=button_delay;//釋放按鍵時置按鍵緩存爲button_delay,以便在下次按鍵時及時響應
	}
	if(up==0)
	{
		if(up_reg<button_delay)//按鍵一直被按下時設置時間間隔觸發
		{
			up_reg++;
		}
		else
		{
			up_reg=0;
			tpflag=2;//返回2表示up被按下
		}		
	}
	else
	{
		up_reg=button_delay;//釋放按鍵時置按鍵緩存爲button_delay,以便在下次按鍵時及時響應
	}
	if(button_a==0)
	{
		if(button_a_reg<button_delay*8)//按鍵一直被按下時設置時間間隔觸發
		{
			button_a_reg++;
		}
		else
		{
			button_a_reg=0;
			tpflag=3;//返回3表示button_a被按下
		}		
	}
	else
	{
		button_a_reg=button_delay*8;//釋放按鍵時置按鍵緩存爲button_delay,以便在下次按鍵時及時響應
	}
	if(left==0)
	{
		if(left_reg<(button_delay))//按鍵一直被按下時設置時間間隔觸發
		{
			left_reg++;
		}
		else
		{
			left_reg=left_acceleration*button_acceleration;
			if(left_acceleration<2)left_acceleration++;
			tpflag=4;//返回4表示left被按下
		}		
	}
	else
	{
		left_acceleration=0;
		left_reg=button_delay;//釋放按鍵時置按鍵緩存爲button_delay,以便在下次按鍵時及時響應
	}
	if(right==0)
	{
		if(right_reg<(button_delay))//按鍵一直被按下時設置時間間隔觸發
		{
			right_reg++;
		}
		else
		{
			right_reg=right_acceleration*button_acceleration;
			if(right_acceleration<2)right_acceleration++;
			tpflag=5;//返回5表示right被按下
		}		
	}
	else
	{
		right_acceleration=0;
		right_reg=button_delay;//釋放按鍵時置按鍵緩存爲button_delay,以便在下次按鍵時及時響應
	}
	return(tpflag);
}

void game_button()
{
	
    switch(basic_button())
    {
        case 3: if(s_box.y!=0)//3表示button_a被按下
                {
                    EA=0;//關中斷,如果不關的話可能引起遊戲顯示混亂
                    speaker=0;
                    if(s_box.shape==3&&check_cover(s_box.x,s_box.y,box_read_data(s_box.mode,0)))
                    {
							
                        s_box.shape=0;
                        box_load();
                        box_to_Box_Ram(s_box.x,s_box.y,box_read_data(s_box.mode,3));
                    }
                    else if(check_cover(s_box.x,s_box.y,box_read_data(s_box.mode,0)))
                    {	if(check_cover(s_box.x,s_box.y,box_read_data(s_box.mode,s_box.shape+1)))
							{	
								s_box.shape++;
								box_load();
								box_to_Box_Ram(s_box.x,s_box.y,box_read_data(s_box.mode,s_box.shape-1));
							}
                     }
                    EA=1;//開中斷
                    speaker=1;
					}break;
        case 1: if(s_box.y!=0)//1表示down被按下
        {
            EA=0;//關中斷,如果不關的話可能引起遊戲顯示混亂
            speaker=0;
            while(check_cover(s_box.x,s_box.y+1,s_box.box))//檢測是否能下降,指導不能再下降爲止
            {
                s_box.y++;
                box_to_Box_Ram(s_box.x,s_box.y-1,s_box.box);
            }
            destroy_row();
            box_build();
            box_load();
					//	game_over_flag=check_game_over();//遊戲結束標誌位置1表示遊戲結束
					//	next_box();
            box_to_Box_Ram(s_box.x,s_box.y,s_box.box);
            EA=1;//開中斷
            speaker=1;
            }break;
        case 4: if(s_box.y!=0)//4表示left被按下
        {
            EA=0;//關中斷,如果不關的話可能引起遊戲顯示混亂
            speaker=0;
            if(check_cover(s_box.x-1,s_box.y,s_box.box))
            {
                s_box.x--;
                box_to_Box_Ram(s_box.x+1,s_box.y,s_box.box);
            }
            EA=1;//開中斷
            speaker=1;
        }break;
        case 5: if(s_box.y!=0)//5表示right被按下
                {
                    EA=0;//關中斷,如果不關的話可能引起遊戲顯示混亂
                    speaker=0;
                    if(check_cover(s_box.x+1,s_box.y,s_box.box))
                    {
                        s_box.x++;
                        box_to_Box_Ram(s_box.x-1,s_box.y,s_box.box);
                    }
						EA=1;//開中斷
						speaker=1;
					}break;
        case 2: //2表示up被按下
            speaker=0;
            pause_game_flag=~pause_game_flag;//遊戲暫停標誌取反
            while(up==0);
            speaker=1;
            break;
        default:;
    }	
}

(3)俄羅斯方塊圖形顯示函數

//檢查覆蓋函數(檢查此時帶入的參數所確定的方塊是否會覆蓋原有圖形,不會覆蓋返回1,覆蓋返回0)
bit check_cover(unsigned char tpx,unsigned char tpy,unsigned int tpbox)
{
	unsigned char i;
	bit tpflag=1;
	unsigned int temp;
	temp=s_box.box;
	for(i=0;i<4;i++)
	{
		Box_Ram[3-i+s_box.y]&=(~((temp&0x000f)<<(9-s_box.x))); 
		temp=temp>>4;
	}//先將現有的方塊從遊戲點陣緩存中刪除
	temp=tpbox;
	for(i=0;i<4;i++)
	{
		if((((temp&0x000f)<<(9-tpx))&Box_Ram[3-i+tpy])!=0x0000)
		{
			tpflag=0;
		}
		temp=temp>>4;
	}//檢查方塊是否和原有圖形重疊,重疊置標誌位tpflag爲0,不重疊不置標誌位,即tpflag爲1
	temp=s_box.box;
	for(i=0;i<4;i++)
	{
		Box_Ram[3-i+s_box.y]|=((temp&0x000f)<<(9-s_box.x));
		temp=temp>>4;
	}//在遊戲點陣緩存中恢復原有方塊
	return(tpflag);
}
//方塊緩存數據函數(輸入方塊類型和形狀即可獲得方塊緩存數據)
unsigned int box_read_data(unsigned char tpmode,unsigned char tpshape)
{
	unsigned int tpbox;
	switch(tpmode)
	{
		case 0: switch(tpshape)
				{
					case 0: tpbox=0xf000;break;
					case 1: tpbox=0x4444;break;
					case 2: tpbox=0xf000;break;
					case 3: tpbox=0x4444;break;
					default:;
				}break;	
		case 1: switch(tpshape)
				{
					case 0: tpbox=0xe800;break;
					case 1: tpbox=0xc440;break;
					case 2: tpbox=0x2e00;break;
					case 3: tpbox=0x88c0;break;
					default:;
				}break;	
		case 2: switch(tpshape)
				{
					case 0: tpbox=0xe200;break;
					case 1: tpbox=0x44c0;break;
					case 2: tpbox=0x8e00;break;
					case 3: tpbox=0xc880;break;
					default:;
				}break;	
		case 3: switch(tpshape)
				{
					case 0: tpbox=0xcc00;break;
					case 1: tpbox=0xcc00;break;
					case 2: tpbox=0xcc00;break;
					case 3: tpbox=0xcc00;break;
					default:;
				}break;	
		case 4: switch(tpshape)
				{
					case 0: tpbox=0xc600;break;
					case 1: tpbox=0x4c80;break;
					case 2: tpbox=0xc600;break;
					case 3: tpbox=0x4c80;break;
					default:;
				}break;	
		case 5: switch(tpshape)
				{
					case 0: tpbox=0x6c00;break;
					case 1: tpbox=0x8c40;break;
					case 2: tpbox=0x6c00;break;
					case 3: tpbox=0x8c40;break;
					default:;
				}break;
		case 6: switch(tpshape)
				{
					case 0: tpbox=0x4e00;break;
					case 1: tpbox=0x8c80;break;
					case 2: tpbox=0xe400;break;
					case 3: tpbox=0x4c40;break;
					default:;
				}break;
		default:;
	}
	return(tpbox);
}
//方塊載入函數
void box_load()
{
	s_box.box=box_read_data(s_box.mode,s_box.shape);
}
//方塊映射遊戲點陣緩存函數(參數是原來方塊的位置、緩存,先消去原有位置的方塊)
void box_to_Box_Ram(unsigned char tpx,unsigned char tpy,unsigned int tpbox)
{
	unsigned char i;
	unsigned int temp;
	temp=tpbox;
	for(i=0;i<4;i++)
	{
		Box_Ram[3-i+tpy]=Box_Ram[3-i+tpy]&(~((temp&0x000f)<<(9-tpx))); 
		temp=temp>>4;
	}//從遊戲點陣緩存中刪除以前的方塊
	temp=s_box.box;
	for(i=0;i<4;i++)
	{
		Box_Ram[3-i+s_box.y]=((temp&0x000f)<<(9-s_box.x))|Box_Ram[3-i+s_box.y];
		temp=temp>>4;
	}//在遊戲點陣緩存中加入新的方塊
}
//顯示數字函數(
  //x表示x座標,
  //y表示y座標,
  //tpdata表示要顯示的數字)
//顯示速度函數
void show_num(unsigned char x,
					  unsigned char y,
					  unsigned char tpdata)
{
	unsigned char i;
	for(i=0;i<4;i++)
	{
		LCD_display_byte(x+i,y,num_data[tpdata*4+i]);	
	}
} 
void show_speed_num(unsigned char x,unsigned char y)
{
	show_num(x,y,speed_num);
}
//顯示得分函數
void show_score_num(unsigned char x,unsigned char y)
{
	show_num(x,y,destroy_row_num/10000);
	show_num(x+=5,y,(destroy_row_num%10000)/1000);
	show_num(x+=5,y,(destroy_row_num%1000)/100);
	show_num(x+=5,y,(destroy_row_num%100)/10);
	show_num(x+=5,y,destroy_row_num%10);
}
//消行函數
void destroy_row()
{
	unsigned char i,j=0;
	unsigned char tpflag[4]={0,0,0,0};//最多一次只能消四行,所以設置四個標誌位即可,初值爲0
	for(i=0;i<16;i++)
	{
		if((Box_Ram[i]&0x3ffc)==0x3ffc)
		{
			tpflag[j]=i+1;//tpflag爲0表示不標誌,1表示第0行緩存爲0xffff,n表示第n+1行緩存爲0xffff
			destroy_row_num++;//消除的行數加一
			/*如不把Box_Ram[19]定義成idata類型的話加入這段代碼顯示數據區就溢出了*/
			if(destroy_row_num%30==0&&speed_num!=9)
			{
				speed_num++;//消夠三十行遊戲速度加一
				show_speed_num(13,4);//調用顯示遊戲速度函數
			}
			/*如不把Box_Ram[19]定義成idata類型的話加入這段代碼顯示數據區就溢出了*/
			j++;
			if(j==4)
			{
				break;
			}//檢查完有四行要消除則退出檢查循環
		}
	}//依次檢測是否有行緩存爲0xffff,如果是則標誌tpflag爲此行的行號
	for(j=0;j<4;j++)
	{
		if(tpflag[j]!=0)
		{
			for(i=tpflag[j]-1;i>0;i--)
			{
			Box_Ram[i]=Box_Ram[i-1];
			Box_Ram[0]=0x2004;
			}
		}
	}//被標誌的行依次被上一行所取代,即被消去
	show_score_num(3,1);
}
//顯示下一個方塊函數
void show_next_box()
{
	unsigned char i,tpdata;
	unsigned int temp;
	temp=box_read_data(next_mode,next_shape);
	for(i=0;i<4;i++)
	{
		tpdata=0x00;
		if(  ((temp>>(15-i))&0x0001)==1  )
		{
			tpdata=0x0f;
		}
		if(  ((temp>>(11-i))&0x0001)==1  )
		{
			tpdata|=0xf0;
		}
		LCD_display_byte(7+i*4,6,tpdata);
		LCD_display_byte(8+i*4,6,0xbb&tpdata);
		LCD_display_byte(9+i*4,6,0xdd&tpdata);
		LCD_display_byte(10+i*4,6,tpdata);	
		tpdata=0x00;
		if(  ((temp>>(7-i))&0x0001)==1  )
		{
			tpdata=0x0f;
		}
		if(  ((temp>>(3-i))&0x0001)==1  )
		{
			tpdata|=0xf0;
		}
		LCD_display_byte(7+i*4,7,tpdata);
		LCD_display_byte(8+i*4,7,0xbb&tpdata);
		LCD_display_byte(9+i*4,7,0xdd&tpdata);
		LCD_display_byte(10+i*4,7,tpdata);		
	}
}
//方塊生成函數
void box_build()
{
	s_box.mode=next_mode;
	s_box.shape=next_shape;
	s_box.x=3;
	s_box.y=0;
	next_mode=TL0%7;//產生隨機數,但是是僞隨機的
	next_shape=TL0%4;//產生隨機數,但是是僞隨機的
	show_next_box();//放到game_execute()函數中不知道爲什麼就是不正常顯示
}

//檢查遊戲結束函數(遊戲結束返回1,遊戲沒有結束返回0)
bit check_game_over()
{
	unsigned char i;
	bit tpflag=0;
	unsigned int temp;
	temp=s_box.box;
	for(i=0;i<4;i++)
	{
		if((((temp&0x000f)<<(9-s_box.x))&Box_Ram[3-i+s_box.y])!=0x0000)
		{
			tpflag=1;
		}
		temp=temp>>4;
	}//檢查新建方塊是否和原有圖形重疊,重疊置標誌位tpflag爲1,不重疊不置標誌位,即tpflag爲0
	return(tpflag);
}
//遊戲執行函數(控制方塊下落,檢測是否到底,如果到底調用消行函數)
void game_execute()
{
	if(box_down_reg<20-(speed_num<<1))
	{				  
		box_down_reg++;
	}
	else
	{
		box_down_reg=0;
		if(check_cover(s_box.x,s_box.y+1,s_box.box))
		{
			s_box.y++;
			box_to_Box_Ram(s_box.x,s_box.y-1,s_box.box);
		}//檢測是否還可以下降,如果還能下降則繼續下降
		else
		{
			destroy_row();
			box_build();
			box_load();
			game_over_flag=check_game_over();//遊戲結束標誌位置1表示遊戲結束
			box_to_Box_Ram(s_box.x,s_box.y,s_box.box);
			box_down_reg=(20-(speed_num<<1)-1);//爲了使方塊一出現就能變換形狀,所以需要儘快使得方塊下降一行,不知道爲什麼最高行不能變換形狀
		}//如果不能下降則調用消行函數檢查是否可以消行,之後重新建立方塊
	}	
}
//選擇遊戲速度函數
void select_speed()
{
	unsigned char i;
	bit tpflag=1;//置循環標誌位爲1
	LCD_clear();
	for(i=0;i<128;i++)
	{
		LCD_display_byte(i,0,0xff);
		LCD_display_byte(i,7,0xff);
	}
	LCD_display_byte(60,4,0x7f);
	LCD_display_byte(59,4,0x3e);
	LCD_display_byte(58,4,0x1c);
	LCD_display_byte(57,4,0x08);
	LCD_display_byte(67,4,0x7f);
	LCD_display_byte(68,4,0x3e);
	LCD_display_byte(69,4,0x1c);
	LCD_display_byte(70,4,0x08);
	LCD_display_word(speed_data,24,3,52);
	show_speed_num(62,4);
	while(tpflag)
	{
		switch(basic_button())
		{
			case 4: if(speed_num!=0)
					{
						speaker=0;
						speed_num--;
						show_speed_num(62,4);
						speaker=1;
					}
					while(left==0);
					break;
			case 5: if(speed_num!=9)
					{
					    speaker=0;
						speed_num++;
						show_speed_num(62,4);
						speaker=1;
					}
					while(right==0);
					break;
			case 6: tpflag=0;
		 	        speaker=0;
					while(button_b==0);
					speaker=1;
					break;
			default:;
		}
	}//選擇遊戲速度循環
}
//遊戲開始顯示畫面
void game_start_show()
{
	bit tpflag=1;//置循環標誌位爲1
	LCD_full_draw(start_pic);
	while(tpflag)
	{
		switch(basic_button())
		{
			case 6: tpflag=0;
			        speaker=0;
					while(button_b==0);
					speaker=1;
					break;
			default:;
		}
	}//game_start_show循環
}
//遊戲初始化函數
void game_initialize()
{
	box_down_reg=0;
	next_mode=6;
	next_shape=2;
	destroy_row_num=0;
	game_over_flag=0;
	pause_game_flag=0;
	LCD_clear();
	time0_reg=0;
	display_basic();	
	LCD_display_word(score_data,24,0,3);
	LCD_display_word(speed_data,24,3,3);
	show_score_num(3,1);
	show_speed_num(13,4);
}
//定時器0初始化函數
void time0_initialize()
{
	TMOD=0x03;//定時器0,16位工作方式
	TR0=1; //啓動定時器
	ET0=1; //打開定時器0中斷
			//默認中斷優先級爲低
	EA=1; //打開總中斷
}
//俄羅斯方塊遊戲主函數
void Tetris_main()
{
	unsigned char i;
	for(i=0;i<19;i++)
	{
		Box_Ram[i]=Box_Ram_data[i];
	};//載入遊戲初始顯示畫面
	LCD_draw(mpic);
	game_over_flag=0;//遊戲結束標誌位置0表示遊戲未結束
	box_build();
	box_load();
//	next_box();
	box_to_Box_Ram(s_box.x,s_box.y,s_box.box);
	box_down_reg=(20-(speed_num<<1)-1);//爲了使方塊一出現就能變換形狀,所以需要儘快使得方塊下降一行,不知道爲什麼最高行不能變換形狀
	time0_initialize();
	while(!game_over_flag)//如果遊戲結束標誌位置1,表示遊戲結束,打破循環,調用遊戲結束畫面顯示函數
	{
		game_button();
	}
	EA=0;//遊戲結束後關中斷
}
//遊戲結束畫面顯示函數
void game_over_show()
{
	unsigned char i;
	bit tpflag=1;//置循環標誌位爲1
	LCD_full_draw(over_pic);
	while(button_a==0);
	while(tpflag)
	{
		switch(basic_button())
		{
			case 6: tpflag=0;
			        speaker=0;
					while(button_b==0);
					speaker=1;
					break;
			default:;
		}
	}//game over畫面循環
	LCD_clear();
	for(i=0;i<128;i++)
	{
		LCD_display_byte(i,0,0xff);
		LCD_display_byte(i,7,0xff);
	}
	LCD_display_word(score_data,24,3,52);
	show_score_num(52,4);
	tpflag=1;
	while(tpflag)
	{
		switch(basic_button())
		{
			case 6: tpflag=0;
			        speaker=0;
					while(button_b==0);
					speaker=1;
					break;
			default:;
		}
	}//遊戲得分顯示循環
}

(4)主函數

void main()
{
	LCD_initialize();
	LCD_clear();
	while(1)
	{
		game_start_show();
		select_speed();
		game_initialize();//調用遊戲初始化函數,初始化遊戲所有變量以及在液晶屏上顯示基本的信息
		Tetris_main();
		game_over_show();	
	}	
}

仿真+源碼+AD電路圖 下載:關注公衆號,首頁回覆“俄羅斯方塊”獲取資料
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章