- 游戏界面设计
宏定义如下:
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; }