1创建TetrisGame类
首先贴出游戏界面图:
上图是俄罗斯方块游戏的主界面,从图中我们可以分解出以下部分:
- 游戏主界面边框
- 游戏方块显示区域
- 游戏方块显示区域网格线
- 游戏菜单区域
- 下一个方块提示区域边框
- 下一个方块提示区域
- 下一个方块提示区域网格线
- 游戏最高分显示区域边框
- 游戏最高分显示区域
- 游戏分数显示区域边框
- 游戏分数显示区域
- 游戏等级显示区域边框
- 游戏等级显示区域
- 游戏时间显示区域边框
- 游戏时间显示区域
- 游戏菜单文字
根据以上分析,将TetrisGame类的定义在TetrisGame.H文件中,下面是TetrisGame.H文件源码:
#ifndef _TETRISGAME_H_
#define _TETRISGAME_H_
#include <windows.h>
class TetrisGame
{
public:
TetrisGame();
TetrisGame(HWND hwnd, int left, int top, int width, int high);
~TetrisGame();
void SetRectFrame(int width, int high);
void SetRectArea(int width, int high);
void SetRectMenu(int width, int high);
void SetRectNextFrame(int width, int high);
void SetRectNextArea(int width, int high);
void SetRectHighestRecordFrame(int width, int high);
void SetRectHighestRecordArea(int width, int high);
void SetRectGameScoreFrame(int width, int high);
void SetRectGameScoreArea(int width, int high);
void SetRectGameLevelFrame(int width, int high);
void SetRectGameLevelArea(int width, int high);
void SetRectGameTimeFrame(int width, int high);
void SetRectGameTimeArea(int width, int high);
void SetMenuFont(HDC hdc);
void DrawGameInterface(HWND hwnd);
private:
int left; // 整个游戏区域的左边界
int top; // 整个游戏区域的上边界
int width; // 整个游戏区域的宽度
int high; // 整个游戏区域的高度
HBRUSH hBrushGameFrame; // 整个游戏边框画刷
HBRUSH hBrushGameArea; // 游戏方块区域画刷
HBRUSH hBrushGameMenu; // 游戏菜单区域画刷
HBRUSH hBrushGameNextFrame; // 游戏提示区域边框画刷
HBRUSH hBrushGameNextArea; // 游戏提示方块区域画刷
HPEN hPenGridOfGameArea; // 游戏方块区域的网格线画笔
HPEN hPenGridOfNextArea; // 游戏提示区域的网格线画笔
RECT rectFrame; // 整个游戏边框矩形
RECT rectArea; // 游戏方块区域矩形
RECT rectMenu; // 游戏菜单区域矩形
RECT rectNextFrame; // 游戏提示区域边框矩形
RECT rectNextArea; // 游戏提示方块区域矩形
RECT rectHighestRecordFrame; // 游戏最高分边框矩形
RECT rectHighestRecordArea; // 游戏最高分数字区域矩形
RECT rectGameScoreFrame; // 游戏分数边框矩形
RECT rectGameScoreArea; // 游戏分数数字区域矩形
RECT rectGameLevelFrame; // 游戏等级边框矩形
RECT rectGameLevelArea; // 游戏等级数字区域矩形
RECT rectGameTimeFrame; // 游戏时间边框矩形
RECT rectGameTimeArea; // 游戏时间数字区域矩形
int RectAreaWidth; // 每个小方块的宽度
int RectFrameHight; // 信息提示边框高度
int NextFrameWidth; // 下一个方块提示边框宽度
int VerticalDistanceOfCom; // 游戏菜单区域各个提示边框距离
LOGFONT lfGameMenu; // 游戏菜单字体类型
CHOOSEFONT cfGameMenu; // 游戏菜单字体类型选择
};
#endif
为了方便读者理解和博客撰写,这里只是分析了主界面绘制所需的元素,后面会逐步添加其他成员变量和功能函数。
TetrisGame类的实现代码在TetrisGame.cpp文件中实现,下面是TetrisGame.cpp文件源码:
#include "TetrisGame.h"
// 默认构造TetrisGame
TetrisGame::TetrisGame()
{
}
// 有参构造TetrisGame
//
TetrisGame::TetrisGame(HWND hwnd, int left, int top, int width, int high)
{
this->left = left; // 整个游戏区域的左边界
this->top = top; // 整个游戏区域的上边界
this->width = width; // 整个游戏区域的宽度
this->high = high; // 整个游戏区域的高度
hBrushGameFrame = CreateSolidBrush(RGB(29, 32, 136)); // 创建整个游戏区域边框画刷
hBrushGameArea = CreateSolidBrush(RGB(160, 160, 160)); // 创建游戏方块区域画刷
hBrushGameMenu = CreateSolidBrush(RGB(49, 0, 74)); // 创建游戏菜单区域画刷
hBrushGameNextFrame = CreateSolidBrush(RGB(126, 206, 244)); // 创建提示区边框画刷
hBrushGameNextArea = hBrushGameMenu; // 创建提示区画刷
hPenGridOfGameArea = CreatePen(PS_SOLID, 2, RGB(69, 69, 214)); // 创建游戏区域网格线画笔
hPenGridOfNextArea = CreatePen(PS_SOLID, 2, RGB(5, 227, 235)); // 创建提示区域网格线画笔
SetRectFrame(width, high); // 设置整个游戏边框矩形结构体
SetRectArea(width, high); // 设置整个游戏方块区域矩形结构体
SetRectMenu(width, high); // 设置游戏菜单区域矩形结构体
SetRectNextFrame(width, high); // 设置游戏提示区域边框矩形结构体
SetRectNextArea(width, high); // 设置游戏提示方块区域矩形结构体
SetRectHighestRecordFrame(width, high); // 设置游戏最高分边框矩形结构体
SetRectHighestRecordArea(width, high); // 设置游戏最高分数字区域矩形结构体
SetRectGameScoreFrame(width, high); // 设置游戏分数边框矩形结构体
SetRectGameScoreArea(width, high); // 设置游戏分数数字区域矩形结构体
SetRectGameLevelFrame(width, high); // 设置游戏等级边框矩形结构体
SetRectGameLevelArea(width, high); // 设置游戏等级数字区域矩形结构体
SetRectGameTimeFrame(width, high); // 设置游戏时间边框矩形结构体
SetRectGameTimeArea(width, high); // 设置游戏时间数字区域矩形结构体
}
// 析构函数
TetrisGame::~TetrisGame()
{
}
// 设置整个游戏边框矩形结构体
void TetrisGame::SetRectFrame(int width, int high)
{
rectFrame.left = 0;
rectFrame.top = 0;
rectFrame.right = width - GetSystemMetrics(SM_CXBORDER) * 10;
rectFrame.bottom = high;
}
// 设置整个游戏方块区域矩形结构体
void TetrisGame::SetRectArea(int width, int high)
{
rectArea.left = width / 110;
rectArea.top = rectArea.left;
rectArea.bottom = high - rectArea.left - GetSystemMetrics(SM_CYMENU) * 2;
rectArea.right = (rectArea.bottom - rectArea.top) / 2 + rectArea.left;
}
// 设置游戏菜单区域矩形结构体
void TetrisGame::SetRectMenu(int width, int high)
{
rectMenu.left = rectArea.right + rectArea.left;
rectMenu.top = rectArea.top;
rectMenu.right = rectFrame.right - rectArea.left * 2;
rectMenu.bottom = rectArea.bottom;
}
// 设置游戏提示区域边框矩形结构体
void TetrisGame::SetRectNextFrame(int width, int high)
{
RectAreaWidth = (rectArea.right - rectArea.left) / 10;
RectFrameHight = RectAreaWidth + rectArea.left * 2;
NextFrameWidth = RectAreaWidth * 4 + rectArea.left * 2;
VerticalDistanceOfCom = ((rectArea.bottom - rectArea.top) - RectAreaWidth * 8 - rectArea.left * 10) / 6;
rectNextFrame.left = rectMenu.left + (rectMenu.right - rectMenu.left - NextFrameWidth) / 2;
rectNextFrame.top = rectArea.top + VerticalDistanceOfCom;
rectNextFrame.right = rectNextFrame.left + NextFrameWidth;
rectNextFrame.bottom = rectNextFrame.top + NextFrameWidth;
}
// 设置游戏提示方块区域矩形结构体
void TetrisGame::SetRectNextArea(int width, int high)
{
rectNextArea.left = rectNextFrame.left + rectArea.left;
rectNextArea.top = rectNextFrame.top + rectArea.left;
rectNextArea.right = rectNextArea.left + RectAreaWidth * 4;
rectNextArea.bottom = rectNextArea.top + RectAreaWidth * 4;
}
// 设置游戏最高分边框矩形结构体
void TetrisGame::SetRectHighestRecordFrame(int width, int high)
{
rectHighestRecordFrame.left = rectNextFrame.left;
rectHighestRecordFrame.top = rectNextFrame.bottom + VerticalDistanceOfCom;
rectHighestRecordFrame.right = rectNextFrame.right;
rectHighestRecordFrame.bottom = rectHighestRecordFrame.top + RectFrameHight;
}
// 设置游戏最高分数字区域矩形结构体
void TetrisGame::SetRectHighestRecordArea(int width, int high)
{
rectHighestRecordArea.left = rectHighestRecordFrame.left + rectArea.left;
rectHighestRecordArea.top = rectHighestRecordFrame.top + rectArea.left;
rectHighestRecordArea.right = rectNextArea.right;
rectHighestRecordArea.bottom = rectHighestRecordArea.top + RectAreaWidth;
}
// 设置游戏分数边框矩形结构体
void TetrisGame::SetRectGameScoreFrame(int width, int high)
{
rectGameScoreFrame.left = rectNextFrame.left;
rectGameScoreFrame.top = rectHighestRecordFrame.bottom + VerticalDistanceOfCom;
rectGameScoreFrame.right = rectNextFrame.right;
rectGameScoreFrame.bottom = rectGameScoreFrame.top + RectFrameHight;
}
// 设置游戏分数数字区域矩形结构体
void TetrisGame::SetRectGameScoreArea(int width, int high)
{
rectGameScoreArea.left = rectNextFrame.left + rectArea.left;
rectGameScoreArea.top = rectGameScoreFrame.top + rectArea.left;
rectGameScoreArea.right = rectNextArea.right;
rectGameScoreArea.bottom = rectGameScoreArea.top + RectAreaWidth;
}
// 设置游戏等级边框矩形结构体
void TetrisGame::SetRectGameLevelFrame(int width, int high)
{
rectGameLevelFrame.left = rectNextFrame.left;
rectGameLevelFrame.top = rectGameScoreFrame.bottom + VerticalDistanceOfCom;
rectGameLevelFrame.right = rectNextFrame.right;
rectGameLevelFrame.bottom = rectGameLevelFrame.top + RectFrameHight;
}
// 设置游戏等级数字区域矩形结构体
void TetrisGame::SetRectGameLevelArea(int width, int high)
{
rectGameLevelArea.left = rectNextFrame.left + rectArea.left;
rectGameLevelArea.top = rectGameLevelFrame.top + rectArea.left;
rectGameLevelArea.right = rectNextArea.right;
rectGameLevelArea.bottom = rectGameLevelArea.top + RectAreaWidth;
}
// 设置游戏时间边框矩形结构体
void TetrisGame::SetRectGameTimeFrame(int width, int high)
{
rectGameTimeFrame.left = rectNextFrame.left;
rectGameTimeFrame.top = rectGameLevelFrame.bottom + VerticalDistanceOfCom;
rectGameTimeFrame.right = rectNextFrame.right;
rectGameTimeFrame.bottom = rectGameTimeFrame.top + RectFrameHight;
}
// 设置游戏时间数字区域矩形结构体
void TetrisGame::SetRectGameTimeArea(int width, int high)
{
rectGameTimeArea.left = rectNextFrame.left + rectArea.left;
rectGameTimeArea.top = rectGameTimeFrame.top + rectArea.left;
rectGameTimeArea.right = rectNextArea.right;
rectGameTimeArea.bottom = rectGameTimeArea.top + RectAreaWidth;
}
// 设置游戏菜单字体
void TetrisGame::SetMenuFont(HDC hdc)
{
lstrcpy(lfGameMenu.lfFaceName, TEXT("新宋体"));
lfGameMenu.lfHeight = RectAreaWidth * 3 / 4;
lfGameMenu.lfWeight = FW_EXTRABOLD;
cfGameMenu.lStructSize = sizeof(CHOOSEFONT);
cfGameMenu.hwndOwner = NULL;
cfGameMenu.hDC = NULL;
cfGameMenu.lpLogFont = &lfGameMenu;
cfGameMenu.iPointSize = 0;
cfGameMenu.Flags = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS | CF_EFFECTS;
cfGameMenu.rgbColors = RGB(11, 223, 35);
cfGameMenu.lCustData = 0;
cfGameMenu.lpfnHook = NULL;
cfGameMenu.lpTemplateName = NULL;
cfGameMenu.hInstance = NULL;
cfGameMenu.lpszStyle = NULL;
cfGameMenu.nFontType = 0;
cfGameMenu.nSizeMin = 0;
cfGameMenu.nSizeMax = 0;
SelectObject(hdc, CreateFontIndirect(&lfGameMenu));
SetTextColor(hdc, cfGameMenu.rgbColors);
}
// 绘制游戏界面
void TetrisGame::DrawGameInterface(HWND hwnd)
{
HDC hdc; // 设备句柄
hdc = GetDC(hwnd); // 获取设备句柄
SetMenuFont(hdc);
MoveWindow(hwnd, left, top, width, high, TRUE);
SetBkMode(hdc, TRANSPARENT);
FillRect(hdc, &rectFrame, hBrushGameFrame);
FillRect(hdc, &rectArea, hBrushGameArea);
FillRect(hdc, &rectMenu, hBrushGameMenu);
TextOut(hdc, rectMenu.left + rectArea.left, rectNextFrame.top - RectAreaWidth, TEXT("下一个方块:"), 6);
FillRect(hdc, &rectNextFrame, hBrushGameNextFrame);
FillRect(hdc, &rectNextArea, hBrushGameNextArea);
TextOut(hdc, rectMenu.left + rectArea.left, rectHighestRecordFrame.top - RectAreaWidth, TEXT("最高记录:"), 5);
FillRect(hdc, &rectHighestRecordFrame, hBrushGameNextFrame);
FillRect(hdc, &rectHighestRecordArea, hBrushGameNextArea);
TextOut(hdc, rectHighestRecordArea.left + RectAreaWidth / 25, rectHighestRecordArea.top + RectAreaWidth / 10, TEXT("0000000000"), 10);
TextOut(hdc, rectMenu.left + rectArea.left, rectGameScoreFrame.top - RectAreaWidth, TEXT("游戏分数:"), 5);
FillRect(hdc, &rectGameScoreFrame, hBrushGameNextFrame);
FillRect(hdc, &rectGameScoreArea, hBrushGameNextArea);
TextOut(hdc, rectGameScoreArea.left + RectAreaWidth / 25, rectGameScoreArea.top + RectAreaWidth / 10, TEXT("0000000000"), 10);
TextOut(hdc, rectMenu.left + rectArea.left, rectGameLevelFrame.top - RectAreaWidth, TEXT("游戏等级:"), 5);
FillRect(hdc, &rectGameLevelFrame, hBrushGameNextFrame);
FillRect(hdc, &rectGameLevelArea, hBrushGameNextArea);
TextOut(hdc, rectGameLevelArea.left + RectAreaWidth * 3 / 2, rectGameLevelArea.top + RectAreaWidth / 10, TEXT("00"), 2);
TextOut(hdc, rectMenu.left + rectArea.left, rectGameTimeFrame.top - RectAreaWidth, TEXT("游戏时间:"), 5);
FillRect(hdc, &rectGameTimeFrame, hBrushGameNextFrame);
FillRect(hdc, &rectGameTimeArea, hBrushGameNextArea);
TextOut(hdc, rectGameTimeArea.left + RectAreaWidth / 2, rectGameTimeArea.top + RectAreaWidth / 10, TEXT("00:00:00"), 8);
SelectObject(hdc, hPenGridOfGameArea);
for (int i = 1; i < 10; i++)
{
MoveToEx(hdc, i * RectAreaWidth + rectArea.left, rectArea.top, NULL);
LineTo(hdc, i * RectAreaWidth + rectArea.left, rectArea.bottom);
}
for (int i = 1; i < 20; i++)
{
MoveToEx(hdc, rectArea.left, i * RectAreaWidth + rectArea.top, NULL);
LineTo(hdc, rectArea.right, i * RectAreaWidth + rectArea.top);
}
SelectObject(hdc, hPenGridOfNextArea);
for (int i = 1; i < 4; i++)
{
MoveToEx(hdc, i * RectAreaWidth + rectNextArea.left, rectNextArea.top, NULL);
LineTo(hdc, i * RectAreaWidth + rectNextArea.left, rectNextArea.bottom);
}
for (int i = 1; i < 4; i++)
{
MoveToEx(hdc, rectNextArea.left, i * RectAreaWidth + rectNextArea.top, NULL);
LineTo(hdc, rectNextArea.right, i * RectAreaWidth + rectNextArea.top);
}
}
俄罗斯方块游戏程序主框架实现代码在MainFrame.h和MainFrame.cpp两个文件中,下面贴出这两个文件的源码:
MainFrame.h
#ifndef _MAINFRAME_H_
#define _MAINFRAME_H_
/****************************************
* 变量命名字首含义参照表 *
* --------------------------------------*
* c | char或WCHAR或TCHAR *
* by | BYTE(无正负号字元) *
* n | short *
* i | int *
* x, y | int分别用作x,y坐标 *
* cx, cy| int分别用作x,y长度c代表计数器*
* b或f | BOOL(int);f代表【旗标】 *
* w | WORD(无正负号短整数) *
* l | LONG(长整数) *
* dw | DWORD(无正负号长整数) *
* fn | function(函式) *
* s | string(字串) *
* sz | 以位元组值0结尾的字符串 *
* h | 代号 *
* p | 指针 *
*****************************************/
#include <windows.h>
#include "TetrisGame.h"
TetrisGame *pTetrisGame; // 创建俄罗斯方块游戏类指针
#endif
MainFrame.cpp
#include "MainFrame.h"
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT("俄罗斯方块"); // 应用程序名
HWND hwnd; // 视窗代号
MSG msg; // 讯息结构
WNDCLASS wndclass; // 视窗类型结构
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass))
{
MessageBox(NULL, TEXT("这个程序需要运行再Windows NT!操作系统上!"), szAppName, MB_ICONERROR);
}
hwnd = CreateWindow(szAppName,
szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, iCmdShow);
UpdateWindow(hwnd);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static int cxScreen, cyScreen; // 屏幕分辨率
static int cxClient, cyClient; // 客户区域大小
PAINTSTRUCT ps; // 绘图结构
HDC hdc; // 装置内容代号
switch (message)
{
case WM_CREATE:
cxScreen = GetSystemMetrics(SM_CXSCREEN); // 获取屏幕横向分辨率
cyScreen = GetSystemMetrics(SM_CYSCREEN); // 获取屏幕纵向分辨率
cxClient = cyScreen / 4 * 3; // 默认游戏窗口宽度
cyClient = cxClient * 25 / 22; // 默认游戏窗口高度
pTetrisGame = new TetrisGame(hwnd, (cxScreen - cxClient) / 2, (cyScreen - cyClient) / 2, cxClient, cyClient);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
pTetrisGame->DrawGameInterface(hwnd);
EndPaint(hwnd, &ps);
return 0;
case WM_CLOSE:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
注意:
本工程是在Visual Studio2015中开发的