[代碼運行效果截圖]
[c++]代碼庫
/*
*/
#include
#include
#include
#define CELL 20
#define ROWS 25
#define COLS 15
//升級所需分數值
#define SCORE_LEVEL_INC 80
#define ID_TIMER 1
/////////////////全局變量/////////////////////////////
HWND?hwnd;?//保存窗口句柄
int?score=0;?//分數
int?level=0;?//級數
int?interval_unit=25;?//隨級數遞增的時間間隔增量
int?interval_base=300;?//時間間隔基量
int?old_interval;?//保存當前的時間間隔,用于加速操作
int?cur_left,cur_top;?//記錄方塊當前的位置
int?width_block,height_block;?//方塊的寬帶和高度
bool?isPause=false;?//暫停標識
UINT?timer_id=0;?//保存計時器ID
static?byte *block=NULL;?//方塊,方塊為隨機大小,采用動態分配內存方式,所以這里是指針變量
byte g_panel[ROWS][COLS]={0};
////////////////////////////////////////////////////
LRESULT?CALLBACK WndProc (?HWND,UINT,WPARAM,LPARAM?);
void?DrawPanel (?HDC?hdc );?//繪制表格
void?RefreshPanel (?HDC?hdc );?//刷新面板
void?DoDownShift (?HDC?hdc );?//下移
void?DoLeftShift (?HDC?hdc );?//左移
void?DoRightShift (?HDC?hdc );?//右移
void?DoAccelerate (?HDC?hdc );?//加速
void?DoRedirection (?HDC?hdc );?//改變方向
void?ClearRow (?HDC?hdc );?//消行
bool?ExportBlock();?//輸出方塊,
//該函數會直接修改全局變量block,width_block,height_block,
//cur_left和cur_top
bool?IsTouchBottom (?HDC?hdc );?//判斷是否到達底部
int?main()
{
????HINSTANCE?hInstance=GetModuleHandle ( NULL );
????TCHAR?szAppName[]=TEXT (?"teris"?);
????MSG msg;
????WNDCLASS wc;
????wc.style=CS_HREDRAW|CS_VREDRAW;
????wc.lpfnWndProc=WndProc;
????wc.cbClsExtra=0;
????wc.cbWndExtra=0;
????wc.hInstance=hInstance;
????wc.hIcon=LoadIcon ( NULL,IDI_APPLICATION );
????wc.hCursor=LoadCursor ( NULL,IDC_ARROW );
????wc.hbrBackground= (?HBRUSH?) GetStockObject ( WHITE_BRUSH );
????wc.lpszMenuName=NULL;
????wc.lpszClassName=szAppName;
????if?( !RegisterClass ( &wc ) )
????{
????????printf?(?"RegisterClass occur errors!"?);
????????return?0;
????}
????hwnd=CreateWindow ( szAppName,TEXT (?"Teris Demo"?),
????????????????????????WS_OVERLAPPEDWINDOW,
????????????????????????0,0,0,0,
????????????????????????NULL,
????????????????????????NULL,
????????????????????????hInstance,
????????????????????????NULL );
????ShowWindow ( hwnd,SW_SHOW );
????UpdateWindow ( hwnd );
????while?( GetMessage ( &msg,NULL,0,0 ) )
????{
????????TranslateMessage ( &msg );
????????DispatchMessage ( &msg );
????}
????return?msg.wParam;
}
void?DrawPanel (?HDC?hdc )?//繪制游戲面板
{
????int?x,y;
????RECT rect;
????for?( y=0; y
????{
????????for?( x=0; x
????????{
????????????//計算方塊的邊框范圍
????????????rect.top=y*CELL+1;
????????????rect.bottom= ( y+1 ) *CELL-1;
????????????rect.left=x*CELL+1;
????????????rect.right= ( x+1 ) *CELL-1;
????????????FrameRect ( hdc,&rect, (?HBRUSH?) GetStockObject ( BLACK_BRUSH ) );
????????}
????}
}
void?DoDownShift (?HDC?hdc )?//下移
{
????if?( NULL==block )?return;
????//判斷是否到達底部
????if?( IsTouchBottom ( hdc ) )?//到底部
????{
????????//消行處理
????????ClearRow ( hdc );
????????ExportBlock();?//輸出下一個方塊
????}
????cur_top++;
????RefreshPanel ( hdc );
}
void?DoLeftShift (?HDC?hdc )?//左移
{
????int?x,y;
????if?( NULL==block )?return;
????if?( 0==cur_left )?return;
????if?( cur_top<0 )?return;?//方塊沒有完整顯示前,不能左移
????for?( y=0; y
????{
????????for?( x=0; x
????????{
????????????if?( * ( block+y*width_block+x ) )
????????????{
????????????????//判斷當前方格在面板上面左邊一個方格是否為實心,是就代表不能再左移
????????????????if?( g_panel[cur_top+y][cur_left+x-1] )?return;
????????????????break;?//只判斷最左邊的一個實心方格,之后直接掃描下一行
????????????}
????????}
????}
????cur_left--;
????RefreshPanel ( hdc );
}
void?DoRightShift (?HDC?hdc )?//右移
{
????int?x,y;
????if?( NULL==block )?return;
????if?( COLS-width_block==cur_left )?return;
????if?( cur_top<0 )?return;?//方塊完整顯示前不能右移
????for?( y=0; y
????{
????????for?( x=width_block-1; x>=0; x-- )?//從右邊開始掃描,獲取該行最右邊的實心方格塊
????????{
????????????if?( * ( block+y*width_block+x ) )
????????????{
????????????????//判斷當前方格在面板上右邊一個方格是否為實心,是就代表不能再右移
????????????????if?( g_panel[cur_top+y][cur_left+x+1] )?return;
????????????????break;?//只判斷最右邊的一個實心方格
????????????}
????????}
????}
????cur_left++;
????RefreshPanel ( hdc );
}
void?DoRedirection (?HDC?hdc )?//改變方向
{
????int?i,j;
????byte * temp=NULL;
????if?( NULL==block )?return;
????if?( cur_top<0 )?return;?//方塊完整顯示前不能轉向
????temp= ( byte * )?malloc?(?sizeof?( byte ) *width_block*height_block );
????for?( i=0; i
????{
????????for?( j=0; j
????????{
????????????//temp[i][j]=block[height_block-j-1][i];
????????????* ( temp+i*height_block+j ) =* ( block+ ( height_block-j-1 ) *width_block+i );
????????}
????}
????//給方塊重新定位
????int?incHeight=width_block-height_block;
????int?incWidth=height_block-width_block;
????int?temp_cur_top=cur_top-incHeight/2;
????int?temp_cur_left=cur_left-incWidth/2;
????//system("cls");
????//printf("temp_top=%d, temp_left=%d",temp_cur_top,temp_cur_left);
????//判斷當前空間是否足夠讓方塊改變方向
????int?max_len=max ( width_block,height_block );
????//防止下標訪問越界
????if?( temp_cur_top+max_len-1>=ROWS||temp_cur_left<0||temp_cur_left+max_len-1>=COLS )
????{
????????free?( temp );?//退出前必須先釋放內存
????????return;
????}
????for?( i=0; i
????{
????????for?( j=0; j
????????{
????????????//轉向所需的空間內有已被占用的實心方格存在,即轉向失敗
????????????if?( g_panel[temp_cur_top+i][temp_cur_left+j] )
????????????{
????????????????free?( temp );?//退出前必須先釋放內存
????????????????return;
????????????}
????????}
????}
????//把臨時變量的值賦給block,只能賦值,而不能賦指針值
????for?( i=0; i
????{
????????for?( j=0; j
????????{
????????????//block[i][j]=temp[i][j];
????????????* ( block+i*width_block+j ) =* ( temp+i*width_block+j );
????????}
????}
????//全局變量重新被賦值
????cur_top=temp_cur_top;
????cur_left=temp_cur_left;
????//交換
????i=width_block;
????width_block=height_block;
????height_block=i;
????free?( temp );?//釋放為臨時變量分配的內存
????RefreshPanel ( hdc );
}
void?DoAccelerate (?HDC?hdc )?//加速
{
????if?( NULL==block )?return;
????if?( IsTouchBottom ( hdc ) )
????{
????????//消行處理
????????ClearRow ( hdc );
????????ExportBlock();
????}
????cur_top++;
????RefreshPanel ( hdc );
}
bool?IsTouchBottom (?HDC?hdc )
{
????int?x,y;
????int?i,j;
????if?( NULL==block )?return?false;
????if?( ROWS==cur_top+height_block )
????{
????????//固定方塊
????????for?( i=0; i
????????{
????????????for?( j=0; j
????????????{
????????????????if?( * ( block+i*width_block+j ) ) g_panel[cur_top+i][cur_left+j]=1;
????????????}
????????}
????????return?true;
????}
????for?( y=height_block-1; y>=0; y-- )?//從底行開始掃描
????{
????????//判斷第一個實心方塊在面板上鄰接的下方方格是否為實心,是就代表已經到達底部
????????for?( x=0; x
????????{
????????????if?( * ( block+y*width_block+x ) )
????????????{
????????????????if?( cur_top+y+1<0 )?return?false;
????????????????if?( g_panel[cur_top+y+1][cur_left+x] )
????????????????{
????????????????????//判斷是否gameover
????????????????????if?( cur_top<=0 )
????????????????????{
????????????????????????if?( timer_id )
????????????????????????{
????????????????????????????KillTimer ( hwnd,ID_TIMER );
????????????????????????????timer_id=0;
????????????????????????}
????????????????????????MessageBox ( hwnd,TEXT (?"游戲結束"?),TEXT (?"MSG"?),MB_OK|MB_ICONEXCLAMATION );
????????????????????????SendMessage ( hwnd,WM_CLOSE,0,0 );
????????????????????}
????????????????????//
????????????????????//固定方塊
????????????????????for?( i=0; i
????????????????????{
????????????????????????for?( j=0; j
????????????????????????{
????????????????????????????if?( * ( block+i*width_block+j ) ) g_panel[cur_top+i][cur_left+j]=1;
????????????????????????}
????????????????????}
????????????????????return?true;
????????????????}
????????????}
????????}
????}
????return?false;
}
void?ClearRow (?HDC?hdc )?//消行
{
????int?i,j,k;
????int?count=0;?//消行次數
????bool?isFilled;
????//消行處理
????for?( i=ROWS-1; i>=0; i-- )
????{
????????isFilled=true;
????????for?( j=0; j
????????{
????????????if?( !g_panel[i][j] )
????????????{
????????????????isFilled=false;
????????????????break;
????????????}
????????}
????????if?( isFilled )
????????{
????????????for?( j=0; j
????????????{
????????????????g_panel[i][j]=0;
????????????}
????????????//所有方塊往下移
????????????for?( k=i-1; k>=0; k-- )
????????????{
????????????????for?( j=0; j
????????????????{
????????????????????g_panel[k+1][j]=g_panel[k][j];
????????????????}
????????????}
????????????i=i+1;
????????????count++;
????????}
????}
????//最高級別為9級,所以分數極限為(9+1)*SCORE_LEVEL_INC-1
????if?( score>=10*SCORE_LEVEL_INC-1 )?return;
????//加分規則:消除行數,1行加10分,2行加15分,3行加20分,4行加30分
????switch?( count )
????{
????case?1:
????????score+=10;
????????break;
????case?2:
????????score+=15;
????????break;
????case?3:
????????score+=20;
????????break;
????case?4:
????????score+=30;
????????break;
????}
????int?temp_level=score/SCORE_LEVEL_INC;
????if?( temp_level>level )
????{
????????level=temp_level;
????????//撤銷當前計時器,然后重設
????????if?( timer_id ) KillTimer ( hwnd,ID_TIMER );
????????timer_id=SetTimer ( hwnd,ID_TIMER,interval_base-level*interval_unit,NULL );
????}
????system?(?"cls"?);
????printf?(?"score: %d, level: %d ",score,level );
}
void?RefreshPanel (?HDC?hdc )?//刷新面板
{
????int?x,y;
????RECT rect;
????HBRUSH?h_bSolid= (?HBRUSH?) GetStockObject ( GRAY_BRUSH ),
?????????????????????h_bEmpty= (?HBRUSH?) GetStockObject ( WHITE_BRUSH );
????if?( NULL==block )?return;
????//先刷屏
????for?( y=0; y
????{
????????for?( x=0; x
????????{
????????????//為避免刷掉方塊的邊框,rect范圍必須比邊框范圍小1
????????????rect.top=y*CELL+2;
????????????rect.bottom= ( y+1 ) *CELL-2;
????????????rect.left=x*CELL+2;
????????????rect.right= ( x+1 ) *CELL-2;
????????????if?( g_panel[y][x] )
????????????????FillRect ( hdc,&rect,h_bSolid );
????????????else
????????????????FillRect ( hdc,&rect,h_bEmpty );
????????}
????}
????//再定位方塊
????for?( y=0; y
????{
????????for?( x=0; x
????????{
????????????if?( * ( block+y*width_block+x ) )?//實心
????????????{
????????????????rect.top= ( y+cur_top ) *CELL+2;
????????????????rect.bottom= ( y+cur_top+1 ) *CELL-2;
????????????????rect.left= ( x+cur_left ) *CELL+2;
????????????????rect.right= ( x+cur_left+1 ) *CELL-2;
????????????????FillRect ( hdc,&rect,h_bSolid );
????????????}
????????}
????}
}
bool?ExportBlock()?//輸出方塊
{
????int?sel;
????if?( block )
????{
????????free?( block );?//釋放之前分配的內存
????????block=NULL;
????}
????sel=rand() %7;
????switch?( sel )
????{
????case?0:?//水平條
????????width_block=4;
????????height_block=1;
????????block= ( byte * )?malloc?(?sizeof?( byte ) *width_block*height_block );
????????* ( block+0 ) =1;?//可以理解為*(block+0*width_block+0)=1,即第一行的第一個方格,下面同理
????????* ( block+1 ) =1;?//*(block+0*width_block+1)=1
????????* ( block+2 ) =1;?//*(block+0*width_block+2)=1
????????* ( block+3 ) =1;?//*(block+0*width_block+3)=1
????????cur_top=0-height_block;
????????cur_left= ( COLS-width_block ) /2;
????????break;
????case?1:?//三角
????????width_block=3;
????????height_block=2;
????????block= ( byte * )?malloc?(?sizeof?( byte ) *width_block*height_block );
????????* ( block+0 ) =0;?//可以理解為*(block+0*width_block+0)=0,即第一行的第一個方格,下面同理
????????* ( block+1 ) =1;?//*(block+0*width_block+1)=1
????????* ( block+2 ) =0;?//*(block+0*width_block+2)=0
????????* ( block+3 ) =1;?//*(block+1*width_block+0)=1,第二行開始
????????* ( block+4 ) =1;?//*(block+1*width_block+1)=1
????????* ( block+5 ) =1;?//*(block+1*width_block+2)=1
????????cur_top=0-height_block;
????????cur_left= ( COLS-width_block ) /2;
????????break;
????case?2:?//左橫折
????????width_block=3;
????????height_block=2;
????????block= ( byte * )?malloc?(?sizeof?( byte ) *width_block*height_block );
????????* ( block+0 ) =1;?//可以理解為*(block+0*width_block+0)=1,下面同理
????????* ( block+1 ) =0;?//*(block+0*width_block+1)=0
????????* ( block+2 ) =0;?//*(block+0*width_block+2)=0
????????* ( block+3 ) =1;?//*(block+1*width_block+0)=1
????????* ( block+4 ) =1;?//*(block+1*width_block+1)=1
????????* ( block+5 ) =1;?//*(block+1*width_block+2)=1
????????cur_top=0-height_block;
????????cur_left= ( COLS-width_block ) /2;
????????break;
????case?3:?//右橫折
????????width_block=3;
????????height_block=2;
????????block= ( byte * )?malloc?(?sizeof?( byte ) *width_block*height_block );
????????* ( block+0 ) =0;?//可以理解為*(block+0*width_block+0)=0,下面同理
????????* ( block+1 ) =0;?//*(block+0*width_block+1)=0
????????* ( block+2 ) =1;?//*(block+0*width_block+2)=1
????????* ( block+3 ) =1;?//*(block+1*width_block+0)=1
????????* ( block+4 ) =1;?//*(block+1*width_block+1)=1
????????* ( block+5 ) =1;?//*(block+1*width_block+2)=1
????????cur_top=0-height_block;
????????cur_left= ( COLS-width_block ) /2;
????????break;
????case?4:?//左閃電
????????width_block=3;
????????height_block=2;
????????block= ( byte * )?malloc?(?sizeof?( byte ) *width_block*height_block );
????????* ( block+0 ) =1;?//可以理解為*(block+0*width_block+0)=1,下面同理
????????* ( block+1 ) =1;?//*(block+0*width_block+1)=1
????????* ( block+2 ) =0;?//*(block+0*width_block+2)=0
????????* ( block+3 ) =0;?//*(block+1*width_block+0)=0
????????* ( block+4 ) =1;?//*(block+1*width_block+1)=1
????????* ( block+5 ) =1;?//*(block+1*width_block+2)=1
????????cur_top=0-height_block;
????????cur_left= ( COLS-width_block ) /2;
????????break;
????case?5:?//右閃電
????????width_block=3;
????????height_block=2;
????????block= ( byte * )?malloc?(?sizeof?( byte ) *width_block*height_block );
????????* ( block+0 ) =0;?//可以理解為*(block+0*width_block+0)=0,下面同理
????????* ( block+1 ) =1;?//*(block+0*width_block+1)=1
????????* ( block+2 ) =1;?//*(block+0*width_block+2)=1
????????* ( block+3 ) =1;?//*(block+1*width_block+0)=1
????????* ( block+4 ) =1;?//*(block+1*width_block+1)=1
????????* ( block+5 ) =0;?//*(block+1*width_block+2)=0
????????cur_top=0-height_block;
????????cur_left= ( COLS-width_block ) /2;
????????break;
????case?6:?//石頭
????????width_block=2;
????????height_block=2;
????????block= ( byte * )?malloc?(?sizeof?( byte ) *width_block*height_block );
????????* ( block+0 ) =1;?//可以理解為*(block+0*width_block+0)=1,下面同理
????????* ( block+1 ) =1;?//*(block+0*width_block+1)=1
????????* ( block+2 ) =1;?//*(block+1*width_block+0)=1
????????* ( block+3 ) =1;?//*(block+1*width_block+1)=1
????????cur_top=0-height_block;
????????cur_left= ( COLS-width_block ) /2;
????????break;
????}
????return?block!=NULL;
}
LRESULT?CALLBACK WndProc (?HWND?hwnd,UINT?message,WPARAM?wParam,LPARAM?lParam )
{
????HDC?hdc;
????PAINTSTRUCT ps;
????//TCHAR szBuffer[1024];
????switch?( message )
????{
????case?WM_CREATE:
????????MoveWindow ( hwnd,400,10,CELL*COLS+8,CELL*ROWS+32,FALSE );?//補齊寬度和高度
????????srand?(?time?( NULL ) );
????????ExportBlock();
????????timer_id=SetTimer ( hwnd,ID_TIMER,interval_base-level*interval_unit,NULL );
????????return?0;
????case?WM_TIMER:
????????hdc=GetDC ( hwnd );
????????DoDownShift ( hdc );
????????ReleaseDC ( hwnd,hdc );
????????return?0;
????case?WM_KEYDOWN:
????????hdc=GetDC ( hwnd );
????????switch?( wParam )
????????{
????????case?VK_LEFT:?//左移
????????????if?( !isPause ) DoLeftShift ( hdc );
????????????break;
????????case?VK_RIGHT:?//右移
????????????if?( !isPause ) DoRightShift ( hdc );
????????????break;
????????case?VK_UP:?//轉向
????????????if?( !isPause ) DoRedirection ( hdc );
????????????break;
????????case?VK_DOWN:?//加速
????????????if?( !isPause ) DoAccelerate ( hdc );
????????????break;
????????case?VK_SPACE:?//暫停
????????????isPause=!isPause;
????????????if?( isPause )
????????????{
????????????????if?( timer_id ) KillTimer ( hwnd,ID_TIMER );
????????????????timer_id=0;
????????????}
????????????else
????????????{
????????????????timer_id=SetTimer ( hwnd,ID_TIMER,interval_base-level*interval_unit,FALSE );
????????????}
????????????break;
????????}
????????ReleaseDC ( hwnd,hdc );
????????return?0;
????case?WM_PAINT:
????????hdc=BeginPaint ( hwnd,&ps );
????????DrawPanel ( hdc );?//繪制面板
????????RefreshPanel ( hdc );?//刷新
????????EndPaint ( hwnd,&ps );
????????return?0;
????case?WM_DESTROY:
????????if?( block )?free?( block );
????????if?( timer_id ) KillTimer ( hwnd,ID_TIMER );
????????PostQuitMessage ( 0 );
????????return?0;
????}
????return?DefWindowProc ( hwnd,message,wParam,lParam );
}