Win32API____Cpp俄罗斯方块

本文介绍如何使用Win32API和C++来实现经典的俄罗斯方块游戏。通过详细解析游戏窗口创建、绘图及游戏逻辑,帮助读者理解Windows编程的基础知识,并掌握游戏开发的基本技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Win32API____Cpp俄罗斯方块

//Tetris.cpp

#include <windows.h>  
#include <iostream>  
#include <cstdlib>  
#include <ctime>

using namespace std;  

#define  CellWidth 20  
#define  MAP_WIDTH  12  
#define  MAP_HEIGHT  18  
#define  ID_TIMER 1 

class map_floor;  
class Block;  
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);  
    /*  Make the class name into a global variable  */  
char   szClassName[] = "MinGW_WindowsApp";  

int WINAPI WinMain 
(HINSTANCE hThisInstance,  
HINSTANCE hPrevInstance,  
LPSTR lpszArgument,  
int nCmdShow)  
{  
    HWND hwnd;               /* This is the handle for our window */  
    MSG messages;            /* Here messages to the application are saved */  
    WNDCLASSEX wincl;        /* Data structure for the windowclass */  

        /* The Window structure */  
    wincl.hInstance = hThisInstance;  
    wincl.lpszClassName = szClassName;  
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */  
    wincl.style = CS_DBLCLKS|CS_HREDRAW | CS_VREDRAW;       /* Catch double-clicks */  
    wincl.cbSize = sizeof (WNDCLASSEX);  

     /* Use default icon and mouse-pointer */  
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);  
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);  
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);  
    wincl.lpszMenuName = NULL;                 /* No menu */  
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */  
    wincl.cbWndExtra = 0;                      /* structure or the window instance */  
     /* Use Windows's default colour as the background of the window */  
    wincl.hbrBackground =(HBRUSH) GetStockObject(WHITE_BRUSH);//COLOR_BACKGROUND;  

        /* Register the window class, and if it fails quit the program */  
    if (!RegisterClassEx (&wincl))  
        return 0;  

        /* The class is registered, let's create the program*/  
    hwnd = CreateWindowEx (  
               0,                 /* Extended possibilites for variation */  
               szClassName,         /* Classname */  
               "MinGW Template Windows App",       /* Title Text */  
               WS_OVERLAPPEDWINDOW, /* default window */  
               CW_USEDEFAULT,       /* Windows decides the position */  
               CW_USEDEFAULT,       /* where the window ends up on the screen */  
               CW_USEDEFAULT,                 /* The programs width */  
               CW_USEDEFAULT,                 /* and height in pixels */  
               NULL,        /* The window is a child-window to desktop */  
               NULL,                /* No menu */  
               hThisInstance,       /* Program Instance handler */  
               NULL                 /* No Window Creation data */  
               );  

        /* Make the window visible on the screen */  
    ShowWindow (hwnd, nCmdShow);  

        /* Run the message loop. It will run until GetMessage() returns 0 */  
    while (GetMessage (&messages, NULL, 0, 0))  
    {     
            /* Translate virtual-key messages into character messages */  
        TranslateMessage(&messages);  
            /* Send message to WindowProcedure */  
        DispatchMessage(&messages);  
    }  

        /* The program return-value is 0 - The value that PostQuitMessage() gave */  
        return messages.wParam;  
}  


enum{e_LINE,e_CORNER,e_STAIR,e_TANCK,e_TIAN};  
const int TOTAL_BLOCK_STYLE = 5;   //?????4?  
class Block  
{  
public:  
    Block(int x = 100, int y = 100);  
    Block(const Block & rh)//??????,??????,????????  
    {  
        this->m_style  = rh.m_style;  
        this->m_direct = rh.m_direct;  
        for(int i = 0 ; i < 4 ; i ++)  
            this->m_block[i] = rh.m_block[i];  
    }

    Block & operator = (const Block& rh)//??=?,???????  
    {  
        this->m_style  = rh.m_style;  
        this->m_direct = rh.m_direct;  
        for(int i = 0 ; i < 4 ; i ++)  
            this->m_block[i] = rh.m_block[i];  
        return *this;  
    }  

    ~Block(){} 

int     create_block(int x = 100 , int y = 100);  
        //????????????  
int     show_block(HDC hdc,const POINT& GameLeftTop);  
        //?????????,?????????  
int     show_next_block(HDC hdc);  
        //??,????????,???????,??????????,????????  
int     rotate();  
        //??????  
int     random_block();  

        //????????????  
int     get_block_height(){ return m_block[1].y;}  
int     move_down(const RECT& GameClient);  
int     move_left(const RECT& GameClient);  
int     move_right(const RECT& GameClient);  
int     move_up(const RECT& GameClient);  
int     move_to(int x , int y);  
        //???????????  
        //int     check_block(const map_floor& map, const RECT& GameClent);  
int     check_block(const map_floor& map, const POINT& LeftTopScrCdnt);  
int     print_to_map(map_floor& map , const POINT& LeftTopScrCdnt);  
private:  
    int     m_style;//???????,??????????  
    int     m_direct;//?????,??m_style?????  
    POINT     m_block[4];//???1????????,????????????,?????????????  
};


class map_floor  
{  
public:  
    map_floor()  
    {  
        ZeroMemory(m_block_bar,sizeof(int )*12*18);  
    }  
    ~map_floor(){}  
    void show_block_bar(HDC hdc , const POINT& LeftTopScrCdnt)  
    {  
        for(int i = 0 ; i < MAP_HEIGHT ; ++ i)  
        {  
            for(int j = 0 ; j < MAP_WIDTH ; ++ j)  
            {  
                if(m_block_bar[i][j])  
                {  
                Rectangle(hdc,LeftTopScrCdnt.x + j*CellWidth , LeftTopScrCdnt.y + i*CellWidth,  
                LeftTopScrCdnt.x + (j+1)*CellWidth , LeftTopScrCdnt.y + (i+1)*CellWidth);  
                }  
            }  
        }  
    }  

friend  class Block;  
protected:  
private:  
    int    m_block_bar[MAP_HEIGHT][MAP_WIDTH];//??????,?18*12???????  
};  


Block::Block(int x , int y)  
{  
    //    ZeroMemory(m_block_bar,sizeof(int )*12*18);  
    srand( (unsigned)time( NULL ) );//??????,??????  
    //    POINT pt = {100,100};  
    create_block(x,y);  
}  

int Block::random_block()  
{  
    m_style = rand()%TOTAL_BLOCK_STYLE;  
    //    m_style = e_CORNER; //????  
    //    m_style = e_LINE; //????  
    if(m_style == e_STAIR || m_style == e_TANCK)  
        m_direct = rand()%4;  
    else if(m_style == e_LINE)  
        m_direct = rand()%2;  
    else if(m_style == e_CORNER)  
        m_direct = rand()%8;  
    else if(m_style == e_TIAN)  
        m_direct = 0;  
    m_direct = 1;  
}  


int   Block::check_block(const map_floor& map, const POINT& LeftTopScrCdnt)  
{  
    int x , y ; //x , y ???????????,????(0,0)  
    for(int i = 0 ; i < 4 ; i ++)  
    {  
        x = (m_block[i].x - LeftTopScrCdnt.x)/CellWidth;  
        y = (m_block[i].y - LeftTopScrCdnt.y)/CellWidth;  
        if(x < 0 || x >= MAP_WIDTH || y >= MAP_HEIGHT)//????y < 0 ???  
            return 0;  
        if(y < 0) continue;  
        if(map.m_block_bar[y][x])  
        return 0;  
    }  

    return 1;  
}  

int Block::move_down(const RECT& GameClient)//??,????????  
{  
    int i;  
    //    for (i = 0 ; i < 4 ; i ++ )  
    //    {  
    //      if(m_block[i].y == GameClient.bottom - CellWidth)  
    //      return 0;  
    //    }  
    for (i = 0; i < 4 ;i ++ )  
    {  
        m_block[i].y += CellWidth;  
    }  

    return 1;  
}  

int Block::move_up(const RECT& GameClient)
{  
    move_to(m_block[1].x,m_block[1].y - CellWidth);  
    return 1;  
}  

int Block::move_left(const RECT& GameClient)  
{  
    move_to(m_block[1].x - CellWidth,m_block[1].y);  
    return 1;  
}  


int Block::move_right(const RECT& GameClient)  
{  
    move_to(m_block[1].x + CellWidth , m_block[1].y);  
    return 1;  
}  


int Block::create_block(int x , int y)  
{  
    m_block[1].x = x;  
    m_block[1].y = y;  
    random_block();  
    rotate();  
    return 1;  
}  

int Block::move_to(int x , int y)  
{  
    int Vx = x - m_block[1].x;  
    int Vy = y - m_block[1].y;  
    for(int i = 0 ; i < 4 ; i ++)  
    {  
        m_block[i].x += Vx;  
        m_block[i].y += Vy;  
    }  
}


int Block::print_to_map(map_floor& map , const POINT& LeftTopScrCdnt)  
{  
    int x , y;  
    int i , j;  
    for(i = 0 ; i < 4 ; i ++ )  
    { 
        x = (m_block[i].x - LeftTopScrCdnt.x)/CellWidth;  
        y = (m_block[i].y - LeftTopScrCdnt.y)/CellWidth;  
        if(x<0 || x >= MAP_WIDTH || y <0 || y >= MAP_HEIGHT)//???? ,????,????????  
            return 0;  
        map.m_block_bar[y][x]  = 1 ;  
        for(j = 0 ; j < MAP_WIDTH ; j ++)  
        {  
            if(map.m_block_bar[y][j] != 1)  
            break;  
        }  
        if(MAP_WIDTH == j)  
        {  
            for(j = 0 ; j < MAP_WIDTH ; j ++)  
            {  
                map.m_block_bar[y][j] = 5;//??5???????  
            }  
        }  

    }  
    int idx;  
    for(i = 0 ; i < MAP_WIDTH ; i ++)  
    {  
        for(idx = j = MAP_HEIGHT - 1  ; j >= 0 ; j --)  
        {  
            if(map.m_block_bar[j][i] != 5)  
            {  
                map.m_block_bar[idx--][i] = map.m_block_bar[j][i];  
            }  
        }  
        while(idx >= 0)  
        {  
            map.m_block_bar[idx--][i] = 0;  
        }  
    }  
    return 1;  
}  

//??????????????,??????????????????,???????  
//??????block?4???,??3???????block?1???,??????????  
//??,??????7?,??????????,???????????????,???:  
//  
//e_LINE ??      ????????,????????,???????????????,??  
//                ?m_direct??,???????  
//  
//e_TANCK ???  ?????????,?????,??m_direct?4?????????????  
//                ???,??????????????????????,???????????,  
//                ????????????  
//  
//e_STAIR  ??? ????????????????,???????????,?????????  
//            ??????,??????m_direct??????,??????e_STAIR_BACK?e_STAIR_FRONT  
//           ??????,?????????????????????block?0??block?1??????  
//           ??,????block?2??block?3?,block?2???block?1??????,x???block?1?  
//                ??,block?3?.y???block?1?????,???????  
//  
//  e_CORNER  ?? ????????????,???????,???????e_CORNER_FRONT , e_CORNER_BACK  
//      ??,??????????,?????????????????????,??block?3?????  
//                ??m_direct???????  

int Block::rotate()  
{  
    switch (m_style)  
    {  
        case e_LINE:  
        {  
            switch(m_direct)  
            {  
                case 0://??????  
                {  
                    for(int i = 0 ; i < 4 ; i ++)  
                    {  
                        m_block[i].x = m_block[1].x;  
                        m_block[i].y = m_block[1].y + (1-i)*CellWidth;  
                    }  
                    m_direct = 1;  
                }  
                break;  
                case 1://??????  
                {  
                    for(int i = 0 ; i < 4 ; i ++)  
                    {  
                        m_block[i].y = m_block[1].y;  
                        m_block[i].x = m_block[1].x + (1-i)*CellWidth;  
                    }  
                    m_direct = 0;  
                }  
                break;  
            }  
        }  
        break;  
                    //??????????,???????????????,???????????,  
                    //m_direct% == 0??????????  
        case e_STAIR:  
        {  
            int flag;  
            flag = m_direct < 2 ? 1 : -1;  
            m_block[0].x = m_block[1].x + flag*CellWidth;  
            m_block[0].y = m_block[1].y;  
            m_block[2].x = m_block[1].x;  
            m_block[3].y = m_block[1].y + CellWidth;  
            if(m_direct%2 == 0)  
            {  
                m_block[2].y = m_block[1].y - CellWidth;  
                m_block[3].x = m_block[1].x + flag*CellWidth;  
                m_direct++;  
            }  
            else  
            {  
                m_block[2].y = m_block[1].y + CellWidth;  
                m_block[3].x = m_block[1].x - flag*CellWidth;  
                if(m_direct < 2) m_direct = 0;  
                else             m_direct = 2;  
            }  
        }  
        break;  
                    //????,???????????,??????,???????,  
                    //????m_direct%4???????????,???,???????  
                    //?????,??block?3????????,?????????????  
        case e_CORNER:  
        {  
            switch (m_direct%4)  
            {  
                case 0:  
                {  
                    m_block[0].x = m_block[1].x+CellWidth;  
                    m_block[0].y =  m_block[2].y = m_block[1].y;  
                    m_block[2].x = m_block[1].x-CellWidth;  
                    m_block[3].x = m_block[1].x-CellWidth;  
                    if(m_direct>=4)  m_block[3].y = m_block[1].y-CellWidth;  
                    else             m_block[3].y = m_block[1].y+CellWidth;  
                    m_direct ++;  
                }  
                break;  
                case 1:  
                {  
                    m_block[0].x = m_block[2].x = m_block[1].x;  
                    m_block[0].y = m_block[1].y+CellWidth;  
                    m_block[2].y = m_block[1].y-CellWidth;  
                    if(m_direct>=4)     m_block[3].x = m_block[1].x+CellWidth;  
                    else             m_block[3].x = m_block[1].x-CellWidth;  
                    m_block[3].y = m_block[1].y-CellWidth;  
                    m_direct ++;  
                }  
                break;  
                case 2:  
                {  
                    m_block[0].x = m_block[1].x-CellWidth;  
                    m_block[0].y = m_block[2].y = m_block[1].y;  
                    m_block[2].x = m_block[1].x+CellWidth;  
                    m_block[3].x = m_block[1].x+CellWidth;  
                    if (m_direct>=4)    m_block[3].y = m_block[1].y+CellWidth;  
                    else             m_block[3].y = m_block[1].y-CellWidth;  
                    m_direct ++;  
                }  
                break;  
                case 3:  
                {  
                    m_block[0].x = m_block[2].x = m_block[1].x;  
                    m_block[0].y = m_block[1].y-CellWidth;  
                    m_block[2].y = m_block[1].y+CellWidth;  
                    if(m_direct>=4)   {  m_block[3].x = m_block[1].x-CellWidth;  m_direct = 4;}  
                    else              {  m_block[3].x = m_block[1].x+CellWidth;  m_direct = 0;}  
                    m_block[3].y = m_block[1].y+CellWidth;  
                }  
                break;  
                default:    break;  
            }  

        }  
        break;  

        case e_TANCK://?????,???????????,?????  
        {  
            switch (m_direct%2)  
            {  
                case 0:  
                {  
                    m_block[0].x = m_block[2].x = m_block[1].x;  
                    m_block[0].y = m_block[1].y - CellWidth;  
                    m_block[2].y = m_block[1].y + CellWidth;  
                    int flag = m_direct == 0 ? 1 : -1;  
                    m_block[3].x = m_block[1].x + flag*CellWidth;  
                    m_block[3].y = m_block[1].y;  
                    m_direct++;  
                }  
                break;  

                case 1:  
                {  
                    m_block[0].y = m_block[2].y = m_block[1].y;  
                    m_block[0].x = m_block[1].x - CellWidth;  
                    m_block[2].x = m_block[1].x + CellWidth;  
                    m_block[3].x = m_block[1].x;  
                    int flag = m_direct == 3 ? -1:1;  
                    m_block[3].y = m_block[1].y + flag*CellWidth;  
                    if(m_direct == 3)  m_direct = 0;  
                    else m_direct++;  
                }  
                break;  

               default:   break;  
                }  

            }  
            break;  

            case e_TIAN:  
            {  
                        m_block[0].y = m_block[1].y;  
                        m_block[0].x = m_block[1].x + CellWidth;  
                        m_block[2].x = m_block[1].x;  
                        m_block[2].y = m_block[1].y + CellWidth;  
                        m_block[3].x = m_block[1].x + CellWidth;  
                        m_block[3].y = m_block[1].y + CellWidth;  
            }  
            break;  

            default:     break;  
        }  

        return 0;  
}  


int Block::show_block(HDC hdc,const POINT& GameLeftTop)  
{  
    for (int i = 0 ; i < 4  ; i ++ )  
    {  
            if(m_block[i].y >= GameLeftTop.y)  
                Rectangle(hdc,m_block[i].x,m_block[i].y,m_block[i].  
                          x+CellWidth,m_block[i].y+CellWidth);  
            if(i==0)//????,?????????  
            {MoveToEx(hdc,m_block[i].x,m_block[i].y,NULL);  
            LineTo(hdc,m_block[i].x+CellWidth,m_block[i].y+CellWidth);}  

    }  
    return 1;  
}  



int Block::show_next_block(HDC hdc)  
{  
        for (int i = 0 ; i < 4  ; i ++ )  
        {  
            Rectangle(hdc,m_block[i].x,m_block[i].y,m_block[i].  
                          x+CellWidth,m_block[i].y+CellWidth);  
        }  
        return 1;  
}  


Block block , next_block , try_block;  
map_floor map;int d = 0;  
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)  
{  
         HDC         hdc ;  
         PAINTSTRUCT ps ;  
         //?????  
         static RECT GameClient;  
         //????????CellWidth = 20  ???? 12 ???  ? 18 ???  
         const int   Width = 240  ,Height = 360;  
         static POINT  LeftTopScrCdnt;//?????????  

         switch (message)  
         {  
         case WM_CREATE:  
              SetTimer(hwnd,ID_TIMER,500,NULL);  
              return 0 ;  
         case WM_SIZE:  
              GetClientRect(hwnd,&GameClient);  
              LeftTopScrCdnt.x = (GameClient.right-GameClient.left)/2 - Width/2;  
              LeftTopScrCdnt.y = GameClient.top + 50;  
              GameClient.left   = LeftTopScrCdnt.x;  
              GameClient.top    = LeftTopScrCdnt.y;  
              GameClient.right  = LeftTopScrCdnt.x + Width;  
              GameClient.bottom = LeftTopScrCdnt.y + Height;  
              //????????????  
        next_block.create_block(GameClient.right+2*CellWidth,
                                (GameClient.bottom+GameClient.top)/2-3*CellWidth);  
              block.move_to((GameClient.right+GameClient.left)/2,GameClient.top-CellWidth);  

              break;  
         case WM_TIMER:  
              block.move_down(GameClient);  
              if(!block.check_block(map,LeftTopScrCdnt))
            //???????,???????????,???????????  
              {  
                  block.move_up(GameClient);  
                  if(!block.check_block(map,LeftTopScrCdnt) ||  
                      block.get_block_height() <= LeftTopScrCdnt.y )//????????  
                     {  
                         KillTimer(hwnd,ID_TIMER);  
                         d = 4;  
                     }  
                  block.print_to_map(map,LeftTopScrCdnt);  
                  SendMessage(hwnd,WM_KEYDOWN,VK_ESCAPE,0);  
              }  
              InvalidateRect(hwnd,NULL,true);  
              break;  
         case WM_PAINT:  
              hdc = BeginPaint (hwnd, &ps) ;  
              MoveToEx(hdc,LeftTopScrCdnt.x,LeftTopScrCdnt.y,NULL);  
              Rectangle(hdc,GameClient.left,GameClient.top,GameClient.right,GameClient.bottom);
                //?????  
              SelectObject(hdc,GetStockObject(BLACK_BRUSH));  
              map.show_block_bar(hdc,LeftTopScrCdnt);  
              block.show_block(hdc,LeftTopScrCdnt);  
              next_block.show_next_block(hdc);  
              EndPaint (hwnd, &ps);  
              break;  
         case WM_KEYDOWN:  
              InvalidateRect(hwnd,NULL,true);  
              switch (wParam)  
              {  
                case VK_SPACE:  
                {  
                    try_block = block;  
                    try_block.rotate();  
                    if(try_block.check_block(map ,LeftTopScrCdnt))  
                        block = try_block;  
                    break;  
                }  
                case VK_LEFT:  
                {  
                    block.move_left(GameClient);  
                    if(!block.check_block(map ,LeftTopScrCdnt))  
                        block.move_right(GameClient);  
                }  
                    break;  
                case VK_RIGHT:  
                {  
                    block.move_right(GameClient);  
                    if (!block.check_block(map ,LeftTopScrCdnt))  
                        block.move_left(GameClient);  
                }  
                    break;  
                case VK_DOWN:  
                {  
                //  block.move_down(GameClient);  
                      SendMessage(hwnd,WM_TIMER,0,0);  
                }  
                    break;  

                case VK_ESCAPE://???,?????????  
                {  
                    block = next_block;  
                    next_block.create_block(GameClient.right+2*CellWidth,
                                        (GameClient.bottom+GameClient.top)/2-3*CellWidth);  
                    block.move_to((GameClient.right+GameClient.left)/2,GameClient.top-CellWidth);  
                }  
                    break;  
                default:  
                    break;  
              }  
              break;  
         case WM_DESTROY:  
              PostQuitMessage (0) ;  
              return 0 ;  
         }  
         return DefWindowProc (hwnd, message, wParam, lParam) ;  
}  

g++ -mwindows -o Tetris Tetris.cpp

Tetris.exe运行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值