C++ 俄羅斯方塊實現代碼

md3c 9年前發布 | 2K 次閱讀 C/C++

#include <windows.h>

include <stdio.h>

include <time.h>

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<ROWS; y++ )
{
    for ( x=0; x<COLS; 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<height_block; y++ )
{
    for ( x=0; x<width_block; 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<height_block; 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<width_block; i++ )
{
    for ( j=0; j<height_block; 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<max_len; i++ )
{
    for ( j=0; j<max_len; j++ )
    {
        //轉向所需的空間內有已被占用的實心方格存在,即轉向失敗
        if ( g_panel[temp_cur_top+i][temp_cur_left+j] )
        {
            free ( temp );      //退出前必須先釋放內存
            return;
        }
    }
}

//把臨時變量的值賦給block,只能賦值,而不能賦指針值
for ( i=0; i<height_block; i++ )
{
    for ( j=0; j<width_block; 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<height_block; i++ )
    {
        for ( j=0; j<width_block; 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<width_block; 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<height_block; i++ )
                {
                    for ( j=0; j<width_block; 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<COLS; j++ ) { if ( !g_panel[i][j] ) { isFilled=false; break; } } if ( isFilled ) { for ( j=0; j<COLS; j++ ) { g_panel[i][j]=0; } //所有方塊往下移 for ( k=i-1; k>=0; k-- ) { for ( j=0; j<COLS; 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<ROWS; y++ )
{
    for ( x=0; x<COLS; 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<height_block; y++ )
{
    for ( x=0; x<width_block; 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 );

}</pre>

 本文由用戶 md3c 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!