• 3.俄罗斯方块项目


    • 游戏界面设计

    宏定义如下:

    1 #define ELEM 30
    2 #define X_SIZE 510
    3 #define Y_SIZE 660
    • 设置窗口大小和位置
       1 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
       2 {
       3    HWND hWnd;
       4 
       5    hInst = hInstance; // 将实例句柄存储在全局变量中
       6 
       7    //改变窗口大小和位置,并且把最大框功能去掉
       8    hWnd = CreateWindow(szWindowClass, L"池国维--俄罗斯方块",WS_SYSMENU | WS_MINIMIZEBOX,
       9        500, 200, X_SIZE + 18, Y_SIZE + 18 , NULL, NULL, hInstance, NULL);
      10 
      11    if (!hWnd)
      12    {
      13       return FALSE;
      14    }
      15 
      16    ShowWindow(hWnd, nCmdShow);
      17    UpdateWindow(hWnd);
      18 
      19    return TRUE;
      20 }

      此时的截图:

    • 设置游戏背景
      • 使用双缓冲绘图
    1 HDC g_hdc;//全局DC
    2 HDC g_hdcBuf;//缓存DC
    3 HDC g_hdcBg;//背景DC
    4 HBITMAP g_hBmp;//背景

    创建四个函数,一个用于载入资源,一个用于初始化,一个用于画图,一个用于回收资源

    1 VOID Load_Game(HWND);
    2 void Init_Game();
    3 VOID Paint_Game();
    4 VOID Clear_Game();

    Load_Game()函数

     1 VOID Load_Game(HWND hWnd)
     2 {
     3     //获取窗口的DC
     4     g_hdc = GetDC(hWnd);
     5 
     6     //以下实现g_hdcBuf的初始化
     7     //创建与窗口兼容的缓存DC
     8     g_hdcBuf = CreateCompatibleDC(g_hdc);
     9     //创建位图资源
    10     g_hBmp = CreateCompatibleBitmap(g_hdc, X_SIZE, Y_SIZE);
    11     //位图和缓存DC绑定
    12     SelectObject(g_hdcBuf, g_hBmp);
    13 
    14     //以下实现g_hdcBg的初始化
    15     //载入位图资源
    16     HBITMAP hBmp = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BG));
    17     //创建与窗口兼容的背景DC
    18     g_hdcBg = CreateCompatibleDC(g_hdc);
    19     //把位图和背景DC绑定
    20     SelectObject(g_hdcBg, hBmp);
    21     //删除位图资源
    22     DeleteObject(hBmp);
    23     return;
    24 }

    在Init_Game()中画格子中画边框,以及画背景

     1 VOID Init_Game()
     2 {
     3     
     4     //初始化方块
     5     srand(GetTickCount());
     6     int x = rand() % CNT;
     7     //随机初始化当前方块
     8     memcpy(g_astCur, g_astTetris[x], sizeof(g_astCur));
     9 
    10     //随机初始化下一个方块
    11     x = rand()&CNT;
    12     memcpy(g_astNext, g_astTetris[x], sizeof(g_astNext));
    13 
    14     //方块出现的初始位置
    15     g_x = (10 - 4) / 2;
    16     g_y = 1;
    17 
    18 }

    Paint_Game()函数

     1 VOID Paint_Game()
     2 {
     3     //g_hdcBg存放在g_hdcBuf中 加载背景到缓存DC
     4     BitBlt(g_hdcBuf, 0, 0, X_SIZE, Y_SIZE, g_hdcBg, 0, 0, SRCCOPY);
     5     //画一些边框
     6     int x, y;
     7     HBRUSH hBrush = CreateSolidBrush(RGB(0xbb, 0xff, 0xff));
     8     for (x = 0; x < X_SIZE / ELEM; x++)
     9     {
    10         for (y = 0; y < Y_SIZE / ELEM; y++)
    11         {
    12             if (x == 0 || x == X_SIZE / ELEM - 1 || y == 0 || y == Y_SIZE / ELEM - 1 || x == 11)
    13             {
    14                 SelectObject(g_hdcBuf, hBrush);
    15                 Rectangle(g_hdcBuf, x * ELEM, y*ELEM, (x + 1)*ELEM, (y + 1)*ELEM);
    16             }
    17         }
    18     }
    19     //删除画刷
    20     DeleteObject(SelectObject(g_hdcBuf, GetStockObject(NULL_BRUSH)));
    21 
    22     //显示当前下降的方块
    23     for (int x = 0; x < 4; x++)
    24     {
    25         for (int y = 0; y < 4; y++)
    26         {
    27             if (g_astCur[x][y])
    28             {
    29                 SelectObject(g_hdcBuf, (HBRUSH)(GetStockObject(WHITE_BRUSH)));
    30                 Rectangle(g_hdcBuf, (g_x + x) * 30, (g_y + y) * 30, (g_x + x + 1) * 30, (g_y + y + 1) * 30);
    31 
    32                 SelectObject(g_hdcBuf, (HBRUSH)(GetStockObject(GRAY_BRUSH)));
    33                 Rectangle(g_hdcBuf, (g_x + x) * 30 + 5, (g_y + y) * 30 + 5, (g_x + x + 1) * 30 - 5, (g_y + y + 1) * 30 - 5);
    34             }
    35         }
    36     }
    37 
    38     //显示下一个方块
    39     for (int y = 0; y < 4; y++)
    40     {
    41         for (int x = 0; x < 4; x++)
    42         {
    43             if (g_astNext[y][x])
    44             {
    45                 SelectObject(g_hdcBuf, (HBRUSH)(GetStockObject(WHITE_BRUSH)));
    46                 Rectangle(g_hdcBuf, (12 + x) * 30 + 20, (2 + y) * 30 , (12 + x + 1) * 30 +20, (2 + y + 1) * 30);
    47 
    48                 SelectObject(g_hdcBuf, (HBRUSH)(GetStockObject(GRAY_BRUSH)));
    49                 Rectangle(g_hdcBuf, (12 + x) * 30 + 20 + 5, (2 + y) * 30 + 5, (12 + x + 1) * 30 + 20 -5, (2 + y + 1) * 30 - 5);
    50             }
    51         }
    52     }
    53 
    54     //g_hdcBuf存放在g_hdc中 把缓存DC内的东西刷新到游戏DC
    55     BitBlt(g_hdc,0,0,X_SIZE,Y_SIZE,g_hdcBuf,0,0,SRCCOPY);
    56 }

    Clear_Game()函数

    1 VOID Clear_Game()
    2 {
    3     DeleteObject(g_hBmp);
    4     DeleteDC(g_hdcBuf);
    5     DeleteDC(g_hdcBg);
    6 
    7     return;
    8 }

    由于背景只需要画一次,所以Load_Game(),Init_Game()在InitInstance函数中调用

     1 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
     2 {
     3    HWND hWnd;
     4 
     5    hInst = hInstance; // 将实例句柄存储在全局变量中
     6 
     7    //改变窗口大小和位置,并且把最大框功能去掉
     8    hWnd = CreateWindow(szWindowClass, L"池国维--俄罗斯方块", WS_SYSMENU | WS_MINIMIZEBOX,
     9        500, 200, X_SIZE + 18, Y_SIZE + 40 , NULL, NULL, hInstance, NULL);
    10 
    11    if (!hWnd)
    12    {
    13       return FALSE;
    14    }
    15    Load_Game(hWnd);
    16    Init_Game();
    17 
    18    ShowWindow(hWnd, nCmdShow);
    19    UpdateWindow(hWnd);
    20 
    21    return TRUE;
    22 }

    此时截图:

     

     俄罗斯方块用4*4的格子表示:

    用数组表示

     1 INT g_astTetris[][4][4] =
     2 {
     3     { { 1, 1, 1, 1 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
     4     { { 1, 1, 1, 0 }, { 1, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0, } },
     5     { { 1, 1, 1, 0 }, { 0, 0, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
     6     { { 1, 1, 1, 0 }, { 0, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
     7     { { 1, 1, 0, 0 }, { 1, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
     8     { { 0, 1, 1, 0 }, { 1, 1, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
     9     { { 1, 1, 0, 0 }, { 0, 1, 1, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } },
    10 };
    11 INT g_astCur[4][4];//当前是那一块方块
    12 INT g_astNext[4][4];//下一块是哪一块方块

    在Init_Game中初始化方块:

     1 #define CNT sizeof(g_astTetris)/sizeof(g_astTetris[0])
     2 VOID Init_Game()
     3 {
     4     //g_hdcBg存放在g_hdcBuf中 加载背景到缓存DC
     5     BitBlt(g_hdcBuf, 0, 0, X_SIZE, Y_SIZE, g_hdcBg, 0, 0, SRCCOPY);
     6     //画一些边框
     7     int x, y;
     8     HBRUSH hBrush = CreateSolidBrush(RGB(0xbb, 0xff, 0xff));
     9     for (x = 0; x < X_SIZE / ELEM; x++)
    10     {
    11         for (y = 0; y < Y_SIZE / ELEM; y++)
    12         {
    13             if (x == 0 || x == X_SIZE / ELEM - 1 || y == 0 || y == Y_SIZE / ELEM - 1 || x == 11)
    14             {
    15                 SelectObject(g_hdcBuf, hBrush);
    16                 Rectangle(g_hdcBuf, x * ELEM, y*ELEM, (x + 1)*ELEM, (y + 1)*ELEM);
    17             }
    18         }
    19     }
    20     //删除画刷
    21     DeleteObject(SelectObject(g_hdcBuf, GetStockObject(NULL_BRUSH)));
    22 
    23     //初始化方块
    24     srand(GetTickCount());
    25     int x = rand() % CNT;
    26     //随机初始化当前方块
    27     memcpy(g_astCur, g_astTetris[x], sizeof(g_astCur));
    28 }

    设定方块的初始位置:

    1 INT g_x, g_y;//当前方块下降到那个位置

    并在Init_Game中初始化

    1 //方块出现的初始位置
    2     g_x = (10 - 4) / 2;
    3     g_y = 1;

    在Paint_Game中画方块:

     1 VOID Paint_Game()
     2 {
     3     
     4     //显示当前下降的方块
     5     for (int x = 0; x < 4; x++)
     6     {
     7         for (int y = 0; y < 4; y++)
     8         {
     9             if (g_astCur[x][y])
    10             {
    11                 SelectObject(g_hdcBuf, (HBRUSH)(GetStockObject(WHITE_BRUSH)));
    12                 Rectangle(g_hdcBuf, (g_x + x) * 30, (g_y + y) * 30, (g_x + x + 1) * 30, (g_y + y + 1) * 30);
    13 
    14                 SelectObject(g_hdcBuf, (HBRUSH)(GetStockObject(GRAY_BRUSH)));
    15                 Rectangle(g_hdcBuf, (g_x + x) * 30 + 5, (g_y + y) * 30 + 5, (g_x + x + 1) * 30 - 5, (g_y + y + 1) * 30 - 5);
    16             }
    17         }
    18     }
    19 
    20     //显示下一个方块
    21     for (int y = 0; y < 4; y++)
    22     {
    23         for (int x = 0; x < 4; x++)
    24         {
    25             if (g_astNext[y][x])
    26             {
    27                 SelectObject(g_hdcBuf, (HBRUSH)(GetStockObject(WHITE_BRUSH)));
    28                 Rectangle(g_hdcBuf, (12 + x) * 30 + 20, (2 + y) * 30 , (12 + x + 1) * 30 +20, (2 + y + 1) * 30);
    29 
    30                 SelectObject(g_hdcBuf, (HBRUSH)(GetStockObject(GRAY_BRUSH)));
    31                 Rectangle(g_hdcBuf, (12 + x) * 30 + 20 + 5, (2 + y) * 30 + 5, (12 + x + 1) * 30 + 20 -5, (2 + y + 1) * 30 - 5);
    32             }
    33         }
    34     }
    35 
    36     //g_hdcBuf存放在g_hdc中 把缓存DC内的东西刷新到游戏DC
    37     BitBlt(g_hdc,0,0,X_SIZE,Y_SIZE,g_hdcBuf,0,0,SRCCOPY);
    38 }

     此时项目截图:

    设置定时器动起来:

    在消息循环中加入以下代码:

     1 case WM_CREATE:
     2         SetTimer(hWnd, 1, 200, 0);
     3         break;
     4     case WM_TIMER:
     5         //下降
     6         if (CheckMeet(g_x,g_y+1))//可以下降
     7         {
     8             g_y++;
     9         }
    10         else//停止下降
    11         {
    12             RefreshMap();
    13             //生成新的方块
    14             memcpy(g_astCur, g_astNext, sizeof(g_astCur));
    15             g_x = 4;
    16             g_y = 1;
    17             srand(GetTickCount());
    18             int x = rand() % CNT;
    19             memcpy(g_astNext, g_astTetris[x], sizeof(g_astNext));
    20         }
    21         Paint_Game();
    22         break;
    23     case WM_COMMAND:
    24         wmId    = LOWORD(wParam);
    25         wmEvent = HIWORD(wParam);
    26         // 分析菜单选择: 
    27         switch (wmId)
    28         {
    29         case IDM_ABOUT:
    30             DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
    31             break;
    32         case IDM_EXIT:
    33             DestroyWindow(hWnd);
    34             break;
    35         default:
    36             return DefWindowProc(hWnd, message, wParam, lParam);
    37         }
    38         break;
    39     case WM_PAINT:
    40         hdc = BeginPaint(hWnd, &ps);
    41         // TODO:  在此添加任意绘图代码...
    42         Paint_Game();
    43         EndPaint(hWnd, &ps);
    44         break;
    45 
    46     case WM_KEYDOWN:
    47         if (g_gameOver)//游戏结束
    48         {
    49             break;
    50         }
    51         switch (wParam)
    52         {
    53         case VK_LEFT:
    54             if (CheckMeet(g_x - 1, g_y))
    55             {
    56                 g_x--;
    57             }
    58             break;
    59         case VK_RIGHT:
    60             if (CheckMeet(g_x + 1, g_y))
    61             {
    62                 g_x++;
    63             }
    64             break;
    65         case VK_UP://变形
    66             break;
    67         case VK_DOWN://移到下面
    68             break;
    69         }
    70         Paint_Game();
    71         break;

    CheckMeet函数:

    //无碰撞返回TRUE,否则返回FALSE
    BOOL CheckMeet()
    {
        //判断是否到了最下面
        for (int y = 0; y < 4; y++)
        {
            for (int x = 0; x < 4; x++)
            {
                if (g_astCur[y][x])
                {
                    if (g_y + x>=20) 
                        return FALSE;
                }
            }
        }
        return TRUE;
    }
  • 相关阅读:
    516. 最长回文子序列
    NC50493 环形石子合并
    NC16650 采药
    NC16664 合唱队形
    NC51170 石子合并
    148. 合并果子
    NC25138 子串查询
    二维数组对角线 的 规律
    如何讲一个网页转换为jpg?(图片!)
    Java两倍 犯错题
  • 原文地址:https://www.cnblogs.com/xiaochi/p/8283116.html
Copyright © 2020-2023  润新知