From 141405c5f5b1861e702054f015b01cf7560d708a Mon Sep 17 00:00:00 2001 From: Qi-huanye <2728290997@qq.com> Date: Fri, 24 Apr 2026 10:37:30 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E6=A0=B7=E5=BC=8F=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=EF=BC=9A=E6=A8=B1=E8=8A=B1=E7=B2=89=E9=A3=8E=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- image.png | Bin 0 -> 22334 bytes src/include/Tetris.h | 5 + src/source/Tetris.cpp | 53 +++++- src/source/TetrisLogic.cpp | 14 +- src/source/TetrisRender.cpp | 313 ++++++++++++++++++++++++++---------- 5 files changed, 285 insertions(+), 100 deletions(-) create mode 100644 image.png diff --git a/image.png b/image.png new file mode 100644 index 0000000000000000000000000000000000000000..e0526fb91a40e4559f1eec6e0317e0c4a4f85bb3 GIT binary patch literal 22334 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 VUc_24;CUXc{l{{gl9><|C| literal 0 HcmV?d00001 diff --git a/src/include/Tetris.h b/src/include/Tetris.h index 2a157b9..c8b0c72 100644 --- a/src/include/Tetris.h +++ b/src/include/Tetris.h @@ -11,6 +11,11 @@ constexpr int nGameWidth = 10; constexpr int nGameHeight = 20; constexpr int nWidth = 16; constexpr int nHeight = 22; +constexpr int WINDOW_PADDING = 28; +constexpr int SIDE_PANEL_WIDTH = 320; +constexpr int SIDE_PANEL_GAP = 28; +constexpr int WINDOW_CLIENT_WIDTH = WINDOW_PADDING * 2 + nGameWidth * GRID + SIDE_PANEL_GAP + SIDE_PANEL_WIDTH; +constexpr int WINDOW_CLIENT_HEIGHT = WINDOW_PADDING * 2 + nGameHeight * GRID + 20; // 定义一个点,用来表示方块的位置 struct Point diff --git a/src/source/Tetris.cpp b/src/source/Tetris.cpp index 41bc0b8..60529bd 100644 --- a/src/source/Tetris.cpp +++ b/src/source/Tetris.cpp @@ -31,6 +31,19 @@ int APIENTRY _tWinMain(HINSTANCE hInstance, UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); + HMODULE user32Module = GetModuleHandle(_T("user32.dll")); + if (user32Module != nullptr) + { + typedef BOOL(WINAPI* SetProcessDPIAwareFunc)(); + SetProcessDPIAwareFunc setProcessDPIAware = + (SetProcessDPIAwareFunc)GetProcAddress(user32Module, "SetProcessDPIAware"); + + if (setProcessDPIAware != nullptr) + { + setProcessDPIAware(); + } + } + LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_TETRIS, szWindowClass, MAX_LOADSTRING); lstrcpy(szTitle, _T("俄罗斯方块")); @@ -97,7 +110,7 @@ ATOM MyRegisterClass(HINSTANCE hInstance) */ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { - RECT rect = { 0, 0, GRID * nWidth, GRID * nHeight }; + RECT rect = { 0, 0, WINDOW_CLIENT_WIDTH, WINDOW_CLIENT_HEIGHT }; AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, TRUE); hInst = hInstance; @@ -146,7 +159,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) srand((unsigned int)time(nullptr)); Restart(); SetTimer(hWnd, GAME_TIMER_ID, GAME_TIMER_INTERVAL, nullptr); - InvalidateRect(hWnd, nullptr, TRUE); + InvalidateRect(hWnd, nullptr, FALSE); break; case WM_COMMAND: { @@ -184,28 +197,28 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) ComputeTarget(); } - InvalidateRect(hWnd, nullptr, TRUE); + InvalidateRect(hWnd, nullptr, FALSE); } break; case WM_KEYDOWN: if (wParam == 'R') { Restart(); - InvalidateRect(hWnd, nullptr, TRUE); + InvalidateRect(hWnd, nullptr, FALSE); break; } if (wParam == 'P') { suspendFlag = !suspendFlag; - InvalidateRect(hWnd, nullptr, TRUE); + InvalidateRect(hWnd, nullptr, FALSE); break; } if (wParam == 'G') { targetFlag = !targetFlag; - InvalidateRect(hWnd, nullptr, TRUE); + InvalidateRect(hWnd, nullptr, FALSE); break; } @@ -258,13 +271,37 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) ComputeTarget(); } - InvalidateRect(hWnd, nullptr, TRUE); + InvalidateRect(hWnd, nullptr, FALSE); break; + case WM_ERASEBKGND: + return 1; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); - TDrawScreen(hdc, hWnd); + RECT clientRect; + GetClientRect(hWnd, &clientRect); + + HDC memDC = CreateCompatibleDC(hdc); + HBITMAP memBitmap = CreateCompatibleBitmap( + hdc, + clientRect.right - clientRect.left, + clientRect.bottom - clientRect.top); + HBITMAP oldBitmap = (HBITMAP)SelectObject(memDC, memBitmap); + + TDrawScreen(memDC, hWnd); + BitBlt( + hdc, + 0, 0, + clientRect.right - clientRect.left, + clientRect.bottom - clientRect.top, + memDC, + 0, 0, + SRCCOPY); + + SelectObject(memDC, oldBitmap); + DeleteObject(memBitmap); + DeleteDC(memDC); EndPaint(hWnd, &ps); } break; diff --git a/src/source/TetrisLogic.cpp b/src/source/TetrisLogic.cpp index e7a106d..51e0624 100644 --- a/src/source/TetrisLogic.cpp +++ b/src/source/TetrisLogic.cpp @@ -60,13 +60,13 @@ int bricks[7][4][4][4] = COLORREF BrickColor[7] = { - RGB(255, 0, 0), - RGB(0, 255, 0), - RGB(0, 0, 255), - RGB(0, 255, 255), - RGB(255, 150, 0), - RGB(255, 255, 0), - RGB(168, 0, 168) + RGB(244, 144, 165), + RGB(255, 181, 197), + RGB(170, 215, 255), + RGB(134, 230, 220), + RGB(255, 187, 143), + RGB(255, 223, 146), + RGB(197, 170, 255) }; /** diff --git a/src/source/TetrisRender.cpp b/src/source/TetrisRender.cpp index a8763df..6763198 100644 --- a/src/source/TetrisRender.cpp +++ b/src/source/TetrisRender.cpp @@ -16,34 +16,119 @@ void TDrawScreen(HDC hdc, HWND hWnd) RECT clientRect; GetClientRect(hWnd, &clientRect); - HBRUSH backgroundBrush = CreateSolidBrush(RGB(245, 245, 245)); - FillRect(hdc, &clientRect, backgroundBrush); - DeleteObject(backgroundBrush); - - RECT gameRect = + const RECT gameRect = { - GRID, - GRID, - GRID + nGameWidth * GRID, - GRID + nGameHeight * GRID + WINDOW_PADDING, + WINDOW_PADDING, + WINDOW_PADDING + nGameWidth * GRID, + WINDOW_PADDING + nGameHeight * GRID }; + const RECT panelRect = + { + gameRect.right + SIDE_PANEL_GAP, + WINDOW_PADDING, + gameRect.right + SIDE_PANEL_GAP + SIDE_PANEL_WIDTH, + WINDOW_PADDING + nGameHeight * GRID + }; + + const COLORREF pageColor = RGB(255, 244, 248); + const COLORREF blobColorA = RGB(255, 230, 238); + const COLORREF blobColorB = RGB(250, 221, 233); + const COLORREF cardColor = RGB(255, 252, 253); + const COLORREF boardColor = RGB(70, 57, 78); + const COLORREF boardInnerColor = RGB(54, 44, 62); + const COLORREF lineColor = RGB(104, 90, 116); + const COLORREF frameColor = RGB(212, 168, 188); + const COLORREF titleColor = RGB(104, 62, 84); + const COLORREF textColor = RGB(92, 73, 88); + const COLORREF accentColor = RGB(228, 145, 182); + + HBRUSH pageBrush = CreateSolidBrush(pageColor); + FillRect(hdc, &clientRect, pageBrush); + DeleteObject(pageBrush); + + // 绘制淡粉背景装饰 + HBRUSH blobBrushA = CreateSolidBrush(blobColorA); + HBRUSH blobBrushB = CreateSolidBrush(blobColorB); + HBRUSH oldBrush = (HBRUSH)SelectObject(hdc, blobBrushA); + HPEN oldPen = (HPEN)SelectObject(hdc, GetStockObject(NULL_PEN)); + Ellipse(hdc, clientRect.right - 260, -20, clientRect.right + 80, 260); + Ellipse(hdc, -80, clientRect.bottom - 200, 220, clientRect.bottom + 70); + SelectObject(hdc, blobBrushB); + Ellipse(hdc, clientRect.right - 180, clientRect.bottom - 220, clientRect.right + 120, clientRect.bottom + 40); + SelectObject(hdc, oldBrush); + SelectObject(hdc, oldPen); + DeleteObject(blobBrushA); + DeleteObject(blobBrushB); + + // 创建中文清晰字体 + HFONT titleFont = CreateFont( + -34, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, + DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY, + VARIABLE_PITCH, _T("Microsoft YaHei UI")); + + HFONT sectionFont = CreateFont( + -24, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, + DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY, + VARIABLE_PITCH, _T("Microsoft YaHei UI")); + + HFONT bodyFont = CreateFont( + -20, 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE, + DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY, + VARIABLE_PITCH, _T("Microsoft YaHei UI")); + + HFONT smallFont = CreateFont( + -17, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, + DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY, + VARIABLE_PITCH, _T("Microsoft YaHei UI")); + + SetBkMode(hdc, TRANSPARENT); + SetTextColor(hdc, textColor); + + // 绘制主卡片和侧边栏卡片 + HPEN framePen = CreatePen(PS_SOLID, 1, frameColor); + HBRUSH gameCardBrush = CreateSolidBrush(cardColor); + HBRUSH panelBrush = CreateSolidBrush(cardColor); + oldPen = (HPEN)SelectObject(hdc, framePen); + oldBrush = (HBRUSH)SelectObject(hdc, gameCardBrush); + RoundRect(hdc, gameRect.left - 10, gameRect.top - 10, gameRect.right + 10, gameRect.bottom + 10, 28, 28); + SelectObject(hdc, panelBrush); + RoundRect(hdc, panelRect.left, panelRect.top, panelRect.right, panelRect.bottom, 30, 30); + SelectObject(hdc, oldBrush); + SelectObject(hdc, oldPen); + DeleteObject(gameCardBrush); + DeleteObject(panelBrush); + DeleteObject(framePen); + // 绘制游戏区背景 - HBRUSH gameBrush = CreateSolidBrush(RGB(30, 30, 30)); - FillRect(hdc, &gameRect, gameBrush); - DeleteObject(gameBrush); + HBRUSH boardBrush = CreateSolidBrush(boardColor); + FillRect(hdc, &gameRect, boardBrush); + DeleteObject(boardBrush); + + RECT innerRect = + { + gameRect.left + 6, + gameRect.top + 6, + gameRect.right - 6, + gameRect.bottom - 6 + }; + + HBRUSH innerBrush = CreateSolidBrush(boardInnerColor); + FillRect(hdc, &innerRect, innerBrush); + DeleteObject(innerBrush); // 绘制游戏区边框 - HPEN borderPen = CreatePen(PS_SOLID, 2, RGB(80, 80, 80)); - HPEN oldPen = (HPEN)SelectObject(hdc, borderPen); - HBRUSH oldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH)); - Rectangle(hdc, gameRect.left, gameRect.top, gameRect.right, gameRect.bottom); + HPEN borderPen = CreatePen(PS_SOLID, 2, RGB(132, 108, 146)); + oldPen = (HPEN)SelectObject(hdc, borderPen); + oldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH)); + RoundRect(hdc, gameRect.left, gameRect.top, gameRect.right, gameRect.bottom, 18, 18); SelectObject(hdc, oldBrush); SelectObject(hdc, oldPen); DeleteObject(borderPen); // 绘制网格线 - HPEN gridPen = CreatePen(PS_SOLID, 1, RGB(55, 55, 55)); + HPEN gridPen = CreatePen(PS_SOLID, 1, lineColor); oldPen = (HPEN)SelectObject(hdc, gridPen); for (int i = 1; i < nGameWidth; i++) @@ -73,15 +158,21 @@ void TDrawScreen(HDC hdc, HWND hWnd) int colorIndex = workRegion[i][j] - 1; RECT brickRect = { - gameRect.left + j * GRID + 1, - gameRect.top + i * GRID + 1, - gameRect.left + (j + 1) * GRID - 1, - gameRect.top + (i + 1) * GRID - 1 + gameRect.left + j * GRID + 2, + gameRect.top + i * GRID + 2, + gameRect.left + (j + 1) * GRID - 2, + gameRect.top + (i + 1) * GRID - 2 }; HBRUSH brickBrush = CreateSolidBrush(BrickColor[colorIndex]); - FillRect(hdc, &brickRect, brickBrush); + HPEN brickPen = CreatePen(PS_SOLID, 1, RGB(255, 248, 250)); + oldPen = (HPEN)SelectObject(hdc, brickPen); + oldBrush = (HBRUSH)SelectObject(hdc, brickBrush); + RoundRect(hdc, brickRect.left, brickRect.top, brickRect.right, brickRect.bottom, 10, 10); + SelectObject(hdc, oldBrush); + SelectObject(hdc, oldPen); DeleteObject(brickBrush); + DeleteObject(brickPen); } } } @@ -89,7 +180,7 @@ void TDrawScreen(HDC hdc, HWND hWnd) // 绘制预测落点 if (targetFlag) { - HPEN targetPen = CreatePen(PS_DOT, 1, RGB(220, 220, 220)); + HPEN targetPen = CreatePen(PS_DOT, 2, RGB(255, 240, 245)); oldPen = (HPEN)SelectObject(hdc, targetPen); oldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH)); @@ -104,12 +195,13 @@ void TDrawScreen(HDC hdc, HWND hWnd) if (drawY >= 0 && drawY < nGameHeight && drawX >= 0 && drawX < nGameWidth) { - Rectangle( + RoundRect( hdc, - gameRect.left + drawX * GRID + 4, - gameRect.top + drawY * GRID + 4, - gameRect.left + (drawX + 1) * GRID - 4, - gameRect.top + (drawY + 1) * GRID - 4); + gameRect.left + drawX * GRID + 5, + gameRect.top + drawY * GRID + 5, + gameRect.left + (drawX + 1) * GRID - 5, + gameRect.top + (drawY + 1) * GRID - 5, + 8, 8); } } } @@ -134,59 +226,64 @@ void TDrawScreen(HDC hdc, HWND hWnd) { RECT brickRect = { - gameRect.left + drawX * GRID + 1, - gameRect.top + drawY * GRID + 1, - gameRect.left + (drawX + 1) * GRID - 1, - gameRect.top + (drawY + 1) * GRID - 1 + gameRect.left + drawX * GRID + 2, + gameRect.top + drawY * GRID + 2, + gameRect.left + (drawX + 1) * GRID - 2, + gameRect.top + (drawY + 1) * GRID - 2 }; HBRUSH brickBrush = CreateSolidBrush(BrickColor[type]); - FillRect(hdc, &brickRect, brickBrush); + HPEN brickPen = CreatePen(PS_SOLID, 1, RGB(255, 250, 252)); + oldPen = (HPEN)SelectObject(hdc, brickPen); + oldBrush = (HBRUSH)SelectObject(hdc, brickBrush); + RoundRect(hdc, brickRect.left, brickRect.top, brickRect.right, brickRect.bottom, 12, 12); + SelectObject(hdc, oldBrush); + SelectObject(hdc, oldPen); DeleteObject(brickBrush); + DeleteObject(brickPen); } } } } // 绘制右侧信息面板 - SetBkMode(hdc, TRANSPARENT); - SetTextColor(hdc, RGB(40, 40, 40)); + HFONT oldFont = (HFONT)SelectObject(hdc, titleFont); + SetTextColor(hdc, titleColor); + TextOut(hdc, panelRect.left + 24, panelRect.top + 22, _T("俄罗斯方块"), lstrlen(_T("俄罗斯方块"))); - RECT infoRect = - { - gameRect.right + GRID, - gameRect.top, - clientRect.right - GRID, - gameRect.bottom - }; + HPEN accentPen = CreatePen(PS_SOLID, 3, accentColor); + oldPen = (HPEN)SelectObject(hdc, accentPen); + MoveToEx(hdc, panelRect.left + 24, panelRect.top + 68, nullptr); + LineTo(hdc, panelRect.left + 160, panelRect.top + 68); + SelectObject(hdc, oldPen); + DeleteObject(accentPen); - DrawText(hdc, _T("俄罗斯方块"), -1, &infoRect, DT_TOP | DT_LEFT | DT_SINGLELINE); + SelectObject(hdc, sectionFont); + SetTextColor(hdc, textColor); TCHAR scoreText[64]; - _stprintf_s(scoreText, _T("当前得分:%d"), tScore); - TextOut(hdc, infoRect.left, infoRect.top + GRID * 2, scoreText, lstrlen(scoreText)); + _stprintf_s(scoreText, _T("当前得分 %d"), tScore); + TextOut(hdc, panelRect.left + 24, panelRect.top + 104, scoreText, lstrlen(scoreText)); - TextOut(hdc, infoRect.left, infoRect.top + GRID * 4, _T("下一个方块:"), lstrlen(_T("下一个方块:"))); + TextOut(hdc, panelRect.left + 24, panelRect.top + 172, _T("下一个方块"), lstrlen(_T("下一个方块"))); - RECT nextRect = + RECT nextCard = { - infoRect.left, - infoRect.top + GRID * 5, - infoRect.left + GRID * 4, - infoRect.top + GRID * 9 + panelRect.left + 24, + panelRect.top + 210, + panelRect.left + 24 + GRID * 4 + 32, + panelRect.top + 210 + GRID * 4 + 32 }; - HBRUSH nextBackBrush = CreateSolidBrush(RGB(220, 220, 220)); - FillRect(hdc, &nextRect, nextBackBrush); - DeleteObject(nextBackBrush); - - HPEN nextBorderPen = CreatePen(PS_SOLID, 1, RGB(120, 120, 120)); - oldPen = (HPEN)SelectObject(hdc, nextBorderPen); - oldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH)); - Rectangle(hdc, nextRect.left, nextRect.top, nextRect.right, nextRect.bottom); + HBRUSH nextCardBrush = CreateSolidBrush(RGB(255, 238, 244)); + HPEN nextCardPen = CreatePen(PS_SOLID, 1, RGB(233, 191, 208)); + oldPen = (HPEN)SelectObject(hdc, nextCardPen); + oldBrush = (HBRUSH)SelectObject(hdc, nextCardBrush); + RoundRect(hdc, nextCard.left, nextCard.top, nextCard.right, nextCard.bottom, 22, 22); SelectObject(hdc, oldBrush); SelectObject(hdc, oldPen); - DeleteObject(nextBorderPen); + DeleteObject(nextCardBrush); + DeleteObject(nextCardPen); // 绘制下一方块预览 for (int i = 0; i < 4; i++) @@ -197,44 +294,90 @@ void TDrawScreen(HDC hdc, HWND hWnd) { RECT brickRect = { - nextRect.left + j * GRID, - nextRect.top + i * GRID, - nextRect.left + (j + 1) * GRID, - nextRect.top + (i + 1) * GRID + nextCard.left + 16 + j * GRID, + nextCard.top + 16 + i * GRID, + nextCard.left + 16 + (j + 1) * GRID - 2, + nextCard.top + 16 + (i + 1) * GRID - 2 }; HBRUSH brickBrush = CreateSolidBrush(BrickColor[nType]); - FillRect(hdc, &brickRect, brickBrush); + HPEN brickPen = CreatePen(PS_SOLID, 1, RGB(255, 248, 250)); + oldPen = (HPEN)SelectObject(hdc, brickPen); + oldBrush = (HBRUSH)SelectObject(hdc, brickBrush); + RoundRect(hdc, brickRect.left, brickRect.top, brickRect.right, brickRect.bottom, 10, 10); + SelectObject(hdc, oldBrush); + SelectObject(hdc, oldPen); DeleteObject(brickBrush); + DeleteObject(brickPen); } } } - TextOut(hdc, infoRect.left, infoRect.top + GRID * 11, _T("操作说明:"), lstrlen(_T("操作说明:"))); - TextOut(hdc, infoRect.left, infoRect.top + GRID * 12, _T("方向键:移动 / 旋转"), lstrlen(_T("方向键:移动 / 旋转"))); - TextOut(hdc, infoRect.left, infoRect.top + GRID * 13, _T("空格:快速下落"), lstrlen(_T("空格:快速下落"))); - TextOut(hdc, infoRect.left, infoRect.top + GRID * 14, _T("P:暂停 R:重开"), lstrlen(_T("P:暂停 R:重开"))); - TextOut(hdc, infoRect.left, infoRect.top + GRID * 15, _T("G:显示/隐藏落点"), lstrlen(_T("G:显示/隐藏落点"))); + SelectObject(hdc, sectionFont); + TextOut(hdc, panelRect.left + 24, panelRect.top + 390, _T("操作提示"), lstrlen(_T("操作提示"))); - if (suspendFlag) - { - SetTextColor(hdc, RGB(220, 120, 0)); - TextOut(hdc, infoRect.left, infoRect.top + GRID * 17, _T("游戏已暂停"), lstrlen(_T("游戏已暂停"))); - SetTextColor(hdc, RGB(40, 40, 40)); - } + SelectObject(hdc, bodyFont); + TextOut(hdc, panelRect.left + 24, panelRect.top + 432, _T("方向键:移动 / 旋转"), lstrlen(_T("方向键:移动 / 旋转"))); + TextOut(hdc, panelRect.left + 24, panelRect.top + 468, _T("空格:快速下落"), lstrlen(_T("空格:快速下落"))); + TextOut(hdc, panelRect.left + 24, panelRect.top + 504, _T("P:暂停 R:重新开始"), lstrlen(_T("P:暂停 R:重新开始"))); + TextOut(hdc, panelRect.left + 24, panelRect.top + 540, _T("G:显示 / 隐藏落点"), lstrlen(_T("G:显示 / 隐藏落点"))); - if (gameOverFlag) + if (suspendFlag || gameOverFlag) { - RECT overRect = gameRect; - SetTextColor(hdc, RGB(255, 80, 80)); - DrawText(hdc, _T("游戏结束"), -1, &overRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); - RECT tipRect = + RECT overlayRect = { - gameRect.left, - gameRect.top + GRID * 11, - gameRect.right, + gameRect.left + GRID, + gameRect.top + GRID * 6, + gameRect.right - GRID, gameRect.top + GRID * 13 }; - DrawText(hdc, _T("按 R 键重新开始"), -1, &tipRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + + HBRUSH overlayBrush = CreateSolidBrush(RGB(255, 241, 246)); + HPEN overlayPen = CreatePen(PS_SOLID, 2, RGB(232, 170, 194)); + oldPen = (HPEN)SelectObject(hdc, overlayPen); + oldBrush = (HBRUSH)SelectObject(hdc, overlayBrush); + RoundRect(hdc, overlayRect.left, overlayRect.top, overlayRect.right, overlayRect.bottom, 26, 26); + SelectObject(hdc, oldBrush); + SelectObject(hdc, oldPen); + DeleteObject(overlayBrush); + DeleteObject(overlayPen); + + RECT titleRect = + { + overlayRect.left, + overlayRect.top + GRID, + overlayRect.right, + overlayRect.top + GRID * 3 + }; + + RECT tipRect = + { + overlayRect.left + 20, + overlayRect.top + GRID * 3, + overlayRect.right - 20, + overlayRect.bottom - GRID + }; + + SetTextColor(hdc, RGB(121, 76, 99)); + SelectObject(hdc, titleFont); + + if (suspendFlag) + { + DrawText(hdc, _T("游戏已暂停"), -1, &titleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + SelectObject(hdc, bodyFont); + DrawText(hdc, _T("按 P 键继续游戏"), -1, &tipRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + } + else + { + DrawText(hdc, _T("游戏结束"), -1, &titleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + SelectObject(hdc, bodyFont); + DrawText(hdc, _T("按 R 键重新开始"), -1, &tipRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + } } + + SelectObject(hdc, oldFont); + DeleteObject(titleFont); + DeleteObject(sectionFont); + DeleteObject(bodyFont); + DeleteObject(smallFont); }