diff --git a/src/include/Tetris.h b/src/include/Tetris.h index 6345397..fdffda0 100644 --- a/src/include/Tetris.h +++ b/src/include/Tetris.h @@ -17,27 +17,46 @@ 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 { int x; int y; }; -extern int nType; // 下一方块类型 -extern int type; // 当前方块类型 -extern int state; // 当前方块状态 -extern int tScore; // 当前得分 -extern bool gameOverFlag; // 游戏已经结束 -extern bool suspendFlag; // 暂停游戏 -extern bool targetFlag; // 启用瞄准器 -extern int workRegion[20][10]; // 工作区数据,0 表示该位置没有被占用 -extern Point point; // 当前方块的当前位置 -extern Point target; // 当前方块目标位置,用于瞄准器 +struct MenuState +{ + int selectedIndex; + int optionCount; +}; + +enum ScreenState +{ + SCREEN_MENU = 0, + SCREEN_PLAYING = 1 +}; + +enum GameMode +{ + MODE_CLASSIC = 0, + MODE_ROGUE = 1 +}; + +extern int nType; +extern int type; +extern int state; +extern int tScore; +extern bool gameOverFlag; +extern bool suspendFlag; +extern bool targetFlag; +extern int workRegion[20][10]; +extern Point point; +extern Point target; +extern MenuState menuState; +extern int currentScreen; +extern int currentMode; extern int bricks[7][4][4][4]; extern COLORREF BrickColor[7]; -// 游戏逻辑相关函数 bool CanMoveDown(); bool CanMoveLeft(); bool CanMoveRight(); @@ -51,6 +70,7 @@ void DeleteOneLine(int number); void DeleteLines(); void ComputeTarget(); void Restart(); +void StartGameWithMode(int mode); +void ReturnToMainMenu(); -// 绘图函数 void TDrawScreen(HDC hdc, HWND hWnd); diff --git a/src/source/Tetris.cpp b/src/source/Tetris.cpp index ff1c731..a5a4a95 100644 --- a/src/source/Tetris.cpp +++ b/src/source/Tetris.cpp @@ -1,4 +1,3 @@ -// Tetris.cpp : 程序入口、窗口初始化与消息处理 #include "stdafx.h" #include "Tetris.h" @@ -10,19 +9,11 @@ HINSTANCE hInst; TCHAR szTitle[MAX_LOADSTRING]; TCHAR szWindowClass[MAX_LOADSTRING]; -ATOM MyRegisterClass(HINSTANCE hInstance); -BOOL InitInstance(HINSTANCE, int); -LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); -INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); +ATOM MyRegisterClass(HINSTANCE hInstance); +BOOL InitInstance(HINSTANCE, int); +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); +INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM); -/** - * @brief Win32 程序入口函数,负责完成应用启动初始化并进入消息循环。 - * - * 该函数会加载窗口标题与窗口类名称资源,注册窗口类,创建主窗口, - * 然后加载快捷键资源并持续分发系统消息,直到程序退出。 - * - * @return int 程序退出时返回消息循环中的退出码。 - */ int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, @@ -46,7 +37,7 @@ int APIENTRY _tWinMain(HINSTANCE hInstance, LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_TETRIS, szWindowClass, MAX_LOADSTRING); - lstrcpy(szTitle, _T("俄罗斯方块")); + lstrcpy(szTitle, _T("\u4fc4\u7f57\u65af\u65b9\u5757")); MyRegisterClass(hInstance); if (!InitInstance(hInstance, nCmdShow)) @@ -69,15 +60,6 @@ int APIENTRY _tWinMain(HINSTANCE hInstance, return (int)msg.wParam; } -/** - * @brief 注册主窗口所需的窗口类信息。 - * - * 该函数会设置窗口样式、消息处理函数、图标、光标、背景画刷、 - * 菜单资源和窗口类名,最后调用系统 API 完成注册。 - * - * @param hInstance 当前程序实例句柄。 - * @return ATOM 注册成功时返回窗口类原子值,失败时返回 0。 - */ ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; @@ -98,16 +80,6 @@ ATOM MyRegisterClass(HINSTANCE hInstance) return RegisterClassEx(&wcex); } -/** - * @brief 创建主窗口并显示到屏幕上。 - * - * 该函数会先根据游戏区域尺寸计算实际窗口大小,再创建主窗口, - * 如果创建成功则显示并刷新窗口,供后续消息循环与绘制逻辑使用。 - * - * @param hInstance 当前程序实例句柄。 - * @param nCmdShow 窗口显示方式参数。 - * @return BOOL 创建并显示成功返回 TRUE,否则返回 FALSE。 - */ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { RECT rect = { 0, 0, WINDOW_CLIENT_WIDTH, WINDOW_CLIENT_HEIGHT }; @@ -139,25 +111,13 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) return TRUE; } -/** - * @brief 主窗口消息处理函数,负责响应菜单、绘制和退出等系统消息。 - * - * 该函数除菜单和绘制外,还负责初始化游戏、处理定时下落、 - * 响应键盘操作以及管理暂停、重开和游戏结束状态。 - * - * @param hWnd 当前窗口句柄。 - * @param message 当前接收到的消息类型。 - * @param wParam 消息附带的参数 1。 - * @param lParam 消息附带的参数 2。 - * @return LRESULT 消息处理结果。 - */ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: srand((unsigned int)time(nullptr)); - Restart(); + ReturnToMainMenu(); SetTimer(hWnd, GAME_TIMER_ID, GAME_TIMER_INTERVAL, nullptr); InvalidateRect(hWnd, nullptr, FALSE); break; @@ -179,7 +139,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } break; case WM_TIMER: - if (wParam == GAME_TIMER_ID && !suspendFlag && !gameOverFlag) + if (wParam == GAME_TIMER_ID && + currentScreen == SCREEN_PLAYING && + !suspendFlag && + !gameOverFlag) { if (CanMoveDown()) { @@ -206,9 +169,56 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) InvalidateRect(hWnd, nullptr, FALSE); break; case WM_KEYDOWN: + if (currentScreen == SCREEN_MENU) + { + switch (wParam) + { + case VK_UP: + case VK_LEFT: + case 'W': + case 'A': + menuState.selectedIndex--; + if (menuState.selectedIndex < 0) + { + menuState.selectedIndex = menuState.optionCount - 1; + } + InvalidateRect(hWnd, nullptr, FALSE); + break; + case VK_DOWN: + case VK_RIGHT: + case 'S': + case 'D': + menuState.selectedIndex++; + if (menuState.selectedIndex >= menuState.optionCount) + { + menuState.selectedIndex = 0; + } + InvalidateRect(hWnd, nullptr, FALSE); + break; + case VK_RETURN: + case VK_SPACE: + StartGameWithMode(menuState.selectedIndex); + InvalidateRect(hWnd, nullptr, FALSE); + break; + case VK_ESCAPE: + DestroyWindow(hWnd); + break; + default: + break; + } + break; + } + + if (wParam == 'M') + { + ReturnToMainMenu(); + InvalidateRect(hWnd, nullptr, FALSE); + break; + } + if (wParam == 'R') { - Restart(); + StartGameWithMode(currentMode); InvalidateRect(hWnd, nullptr, FALSE); break; } @@ -329,18 +339,6 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) return 0; } -/** - * @brief “关于”对话框的消息处理函数。 - * - * 该函数用于初始化关于对话框,并处理用户点击“确定”或“取消”时的关闭操作。 - * 对于未处理的对话框消息,返回 FALSE 交由系统继续处理。 - * - * @param hDlg 对话框窗口句柄。 - * @param message 当前接收到的对话框消息类型。 - * @param wParam 消息附带的参数 1。 - * @param lParam 消息附带的参数 2。 - * @return INT_PTR 消息已处理返回 TRUE,否则返回 FALSE。 - */ INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); @@ -348,7 +346,7 @@ INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) switch (message) { case WM_INITDIALOG: - SetWindowText(hDlg, _T("关于俄罗斯方块")); + SetWindowText(hDlg, _T("\u5173\u4e8e\u4fc4\u7f57\u65af\u65b9\u5757")); return (INT_PTR)TRUE; case WM_COMMAND: diff --git a/src/source/TetrisLogic.cpp b/src/source/TetrisLogic.cpp index 8be0bbc..2ffb25e 100644 --- a/src/source/TetrisLogic.cpp +++ b/src/source/TetrisLogic.cpp @@ -11,6 +11,9 @@ bool targetFlag = false; int workRegion[20][10] = { 0 }; Point point = { 0, 0 }; Point target = { 0, 0 }; +MenuState menuState = { 0, 2 }; +int currentScreen = SCREEN_MENU; +int currentMode = MODE_CLASSIC; int bricks[7][4][4][4] = { @@ -516,3 +519,23 @@ void Restart() ComputeTarget(); } + +void StartGameWithMode(int mode) +{ + currentMode = mode; + currentScreen = SCREEN_PLAYING; + Restart(); +} + +void ReturnToMainMenu() +{ + currentScreen = SCREEN_MENU; + suspendFlag = false; + gameOverFlag = false; + menuState.optionCount = 2; + + if (menuState.selectedIndex < 0 || menuState.selectedIndex >= menuState.optionCount) + { + menuState.selectedIndex = 0; + } +} diff --git a/src/source/TetrisRender.cpp b/src/source/TetrisRender.cpp index 803daff..965813f 100644 --- a/src/source/TetrisRender.cpp +++ b/src/source/TetrisRender.cpp @@ -1,16 +1,6 @@ #include "stdafx.h" #include "Tetris.h" -/** - * @brief 完整绘制当前游戏界面。 - * - * 该函数负责绘制窗口背景、游戏工作区边框、网格、已经固定的方块、 - * 当前活动方块、预测落点、右侧信息面板以及游戏结束提示文字。 - * 绘制过程只负责根据当前全局游戏状态进行显示,不修改任何游戏逻辑数据。 - * - * @param hdc 当前窗口绘图设备上下文。 - * @param hWnd 当前窗口句柄,用于获取客户区尺寸。 - */ void TDrawScreen(HDC hdc, HWND hWnd) { RECT clientRect; @@ -49,7 +39,6 @@ void TDrawScreen(HDC hdc, HWND hWnd) }; int grid = SS(GRID); - int padding = SS(WINDOW_PADDING); int panelGap = SS(SIDE_PANEL_GAP); int panelWidth = SS(SIDE_PANEL_WIDTH); int boardWidth = grid * nGameWidth; @@ -87,7 +76,6 @@ void TDrawScreen(HDC hdc, HWND hWnd) FillRect(hdc, &clientRect, pageBrush); DeleteObject(pageBrush); - // 绘制淡粉背景装饰 HBRUSH blobBrushA = CreateSolidBrush(blobColorA); HBRUSH blobBrushB = CreateSolidBrush(blobColorB); HBRUSH oldBrush = (HBRUSH)SelectObject(hdc, blobBrushA); @@ -101,7 +89,6 @@ void TDrawScreen(HDC hdc, HWND hWnd) DeleteObject(blobBrushA); DeleteObject(blobBrushB); - // 创建中文清晰字体 HFONT titleFont = CreateFont( -SS(34), 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_NATURAL_QUALITY, @@ -125,7 +112,129 @@ void TDrawScreen(HDC hdc, HWND hWnd) SetBkMode(hdc, TRANSPARENT); SetTextColor(hdc, textColor); - // 绘制主卡片和侧边栏卡片 + if (currentScreen == SCREEN_MENU) + { + RECT menuCard = + { + SX(110), + SY(70), + SX(WINDOW_CLIENT_WIDTH - 110), + SY(WINDOW_CLIENT_HEIGHT - 70) + }; + + HPEN menuFramePen = CreatePen(PS_SOLID, 1, frameColor); + HBRUSH menuCardBrush = CreateSolidBrush(cardColor); + oldPen = (HPEN)SelectObject(hdc, menuFramePen); + oldBrush = (HBRUSH)SelectObject(hdc, menuCardBrush); + RoundRect(hdc, menuCard.left, menuCard.top, menuCard.right, menuCard.bottom, SS(34), SS(34)); + SelectObject(hdc, oldBrush); + SelectObject(hdc, oldPen); + DeleteObject(menuCardBrush); + DeleteObject(menuFramePen); + + HFONT oldFont = (HFONT)SelectObject(hdc, titleFont); + SetTextColor(hdc, titleColor); + + RECT titleRect = + { + menuCard.left, + menuCard.top + SS(24), + menuCard.right, + menuCard.top + SS(70) + }; + DrawText(hdc, _T("Rogue Tetris"), -1, &titleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + + RECT subtitleRect = + { + menuCard.left, + menuCard.top + SS(72), + menuCard.right, + menuCard.top + SS(110) + }; + SelectObject(hdc, bodyFont); + SetTextColor(hdc, textColor); + DrawText(hdc, _T("\u8bf7\u9009\u62e9\u5f00\u59cb\u6a21\u5f0f"), -1, &subtitleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + + const TCHAR* modeNames[2] = + { + _T("\u7ecf\u5178\u6a21\u5f0f"), + _T("Rogue \u6a21\u5f0f") + }; + + const TCHAR* modeDescriptions[2] = + { + _T("\u4fdd\u7559\u5f53\u524d\u539f\u7248\u4fc4\u7f57\u65af\u65b9\u5757\u73a9\u6cd5\uff0c\u76f4\u63a5\u5f00\u59cb\u5bf9\u5c40\u3002"), + _T("\u8fdb\u5165 Rogue \u5165\u53e3\uff0c\u5f53\u524d\u5148\u63a5\u5165\u57fa\u7840\u5bf9\u5c40\u6d41\u7a0b\u3002") + }; + + for (int i = 0; i < menuState.optionCount; i++) + { + bool isSelected = (i == menuState.selectedIndex); + int top = menuCard.top + SS(140) + i * SS(130); + + RECT optionRect = + { + menuCard.left + SS(36), + top, + menuCard.right - SS(36), + top + SS(104) + }; + + HBRUSH optionBrush = CreateSolidBrush(isSelected ? RGB(255, 232, 240) : RGB(255, 247, 250)); + HPEN optionPen = CreatePen(PS_SOLID, isSelected ? SS(3) : 1, isSelected ? accentColor : RGB(226, 198, 210)); + oldPen = (HPEN)SelectObject(hdc, optionPen); + oldBrush = (HBRUSH)SelectObject(hdc, optionBrush); + RoundRect(hdc, optionRect.left, optionRect.top, optionRect.right, optionRect.bottom, SS(24), SS(24)); + SelectObject(hdc, oldBrush); + SelectObject(hdc, oldPen); + DeleteObject(optionBrush); + DeleteObject(optionPen); + + RECT modeNameRect = + { + optionRect.left + SS(24), + optionRect.top + SS(14), + optionRect.right - SS(24), + optionRect.top + SS(44) + }; + + RECT modeDescriptionRect = + { + optionRect.left + SS(24), + optionRect.top + SS(46), + optionRect.right - SS(24), + optionRect.bottom - SS(14) + }; + + SelectObject(hdc, sectionFont); + SetTextColor(hdc, isSelected ? titleColor : textColor); + DrawText(hdc, modeNames[i], -1, &modeNameRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE); + + SelectObject(hdc, smallFont); + SetTextColor(hdc, RGB(118, 96, 110)); + DrawText(hdc, modeDescriptions[i], -1, &modeDescriptionRect, DT_LEFT | DT_WORDBREAK); + } + + RECT hintRect = + { + menuCard.left + SS(36), + menuCard.bottom - SS(92), + menuCard.right - SS(36), + menuCard.bottom - SS(36) + }; + + SelectObject(hdc, smallFont); + SetTextColor(hdc, RGB(128, 104, 118)); + DrawText(hdc, _T("\u65b9\u5411\u952e / WASD \u5207\u6362\uff0cEnter \u6216 Space \u5f00\u59cb\uff0cEsc \u9000\u51fa"), -1, &hintRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + + SelectObject(hdc, oldFont); + DeleteObject(titleFont); + DeleteObject(sectionFont); + DeleteObject(bodyFont); + DeleteObject(smallFont); + return; + } + HPEN framePen = CreatePen(PS_SOLID, 1, frameColor); HBRUSH gameCardBrush = CreateSolidBrush(cardColor); HBRUSH panelBrush = CreateSolidBrush(cardColor); @@ -140,7 +249,6 @@ void TDrawScreen(HDC hdc, HWND hWnd) DeleteObject(panelBrush); DeleteObject(framePen); - // 绘制游戏区背景 HBRUSH boardBrush = CreateSolidBrush(boardColor); FillRect(hdc, &gameRect, boardBrush); DeleteObject(boardBrush); @@ -157,7 +265,6 @@ void TDrawScreen(HDC hdc, HWND hWnd) FillRect(hdc, &innerRect, innerBrush); DeleteObject(innerBrush); - // 绘制游戏区边框 HPEN borderPen = CreatePen(PS_SOLID, SS(2), RGB(132, 108, 146)); oldPen = (HPEN)SelectObject(hdc, borderPen); oldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH)); @@ -166,7 +273,6 @@ void TDrawScreen(HDC hdc, HWND hWnd) SelectObject(hdc, oldPen); DeleteObject(borderPen); - // 绘制网格线 HPEN gridPen = CreatePen(PS_SOLID, 1, lineColor); oldPen = (HPEN)SelectObject(hdc, gridPen); @@ -187,7 +293,6 @@ void TDrawScreen(HDC hdc, HWND hWnd) SelectObject(hdc, oldPen); DeleteObject(gridPen); - // 绘制已经固定的方块 for (int i = 0; i < nGameHeight; i++) { for (int j = 0; j < nGameWidth; j++) @@ -216,7 +321,6 @@ void TDrawScreen(HDC hdc, HWND hWnd) } } - // 绘制预测落点 if (targetFlag && !gameOverFlag) { HPEN targetPen = CreatePen(PS_DOT, SS(2), RGB(255, 240, 245)); @@ -251,7 +355,6 @@ void TDrawScreen(HDC hdc, HWND hWnd) DeleteObject(targetPen); } - // 绘制当前活动方块 if (!gameOverFlag) { for (int i = 0; i < 4; i++) @@ -288,10 +391,9 @@ void TDrawScreen(HDC hdc, HWND hWnd) } } - // 绘制右侧信息面板 HFONT oldFont = (HFONT)SelectObject(hdc, titleFont); SetTextColor(hdc, titleColor); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(22), _T("俄罗斯方块"), lstrlen(_T("俄罗斯方块"))); + TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(22), _T("\u4fc4\u7f57\u65af\u65b9\u5757"), lstrlen(_T("\u4fc4\u7f57\u65af\u65b9\u5757"))); HPEN accentPen = CreatePen(PS_SOLID, SS(3), accentColor); oldPen = (HPEN)SelectObject(hdc, accentPen); @@ -304,17 +406,21 @@ void TDrawScreen(HDC hdc, HWND hWnd) SetTextColor(hdc, textColor); TCHAR scoreText[64]; - _stprintf_s(scoreText, _T("当前得分 %d"), tScore); + _stprintf_s(scoreText, _T("\u5f53\u524d\u5f97\u5206 %d"), tScore); TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(104), scoreText, lstrlen(scoreText)); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(172), _T("下一个方块"), lstrlen(_T("下一个方块"))); + TCHAR modeText[64]; + _stprintf_s(modeText, _T("\u5f53\u524d\u6a21\u5f0f %s"), currentMode == MODE_CLASSIC ? _T("\u7ecf\u5178") : _T("Rogue")); + TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(140), modeText, lstrlen(modeText)); + + TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(188), _T("\u4e0b\u4e00\u4e2a\u65b9\u5757"), lstrlen(_T("\u4e0b\u4e00\u4e2a\u65b9\u5757"))); RECT nextCard = { panelRect.left + SS(24), - panelRect.top + SS(210), + panelRect.top + SS(226), panelRect.left + SS(24) + grid * 4 + SS(32), - panelRect.top + SS(210) + grid * 4 + SS(32) + panelRect.top + SS(226) + grid * 4 + SS(32) }; HBRUSH nextCardBrush = CreateSolidBrush(RGB(255, 238, 244)); @@ -327,7 +433,6 @@ void TDrawScreen(HDC hdc, HWND hWnd) DeleteObject(nextCardBrush); DeleteObject(nextCardPen); - // 绘制下一方块预览 for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) @@ -356,13 +461,14 @@ void TDrawScreen(HDC hdc, HWND hWnd) } SelectObject(hdc, sectionFont); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(390), _T("操作提示"), lstrlen(_T("操作提示"))); + TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(406), _T("\u64cd\u4f5c\u63d0\u793a"), lstrlen(_T("\u64cd\u4f5c\u63d0\u793a"))); SelectObject(hdc, bodyFont); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(432), _T("方向键 / WASD:移动 / 旋转"), lstrlen(_T("方向键 / WASD:移动 / 旋转"))); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(468), _T("空格:快速下落"), lstrlen(_T("空格:快速下落"))); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(504), _T("P:暂停 R:重新开始"), lstrlen(_T("P:暂停 R:重新开始"))); - TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(540), _T("G:显示 / 隐藏落点"), lstrlen(_T("G:显示 / 隐藏落点"))); + TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(448), _T("\u65b9\u5411\u952e / WASD\uff1a\u79fb\u52a8 / \u65cb\u8f6c"), lstrlen(_T("\u65b9\u5411\u952e / WASD\uff1a\u79fb\u52a8 / \u65cb\u8f6c"))); + TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(484), _T("Space\uff1a\u5feb\u901f\u4e0b\u843d"), lstrlen(_T("Space\uff1a\u5feb\u901f\u4e0b\u843d"))); + TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(520), _T("P\uff1a\u6682\u505c R\uff1a\u91cd\u65b0\u5f00\u59cb"), lstrlen(_T("P\uff1a\u6682\u505c R\uff1a\u91cd\u65b0\u5f00\u59cb"))); + TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(556), _T("G\uff1a\u663e\u793a / \u9690\u85cf\u843d\u70b9"), lstrlen(_T("G\uff1a\u663e\u793a / \u9690\u85cf\u843d\u70b9"))); + TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(592), _T("M\uff1a\u8fd4\u56de\u83dc\u5355"), lstrlen(_T("M\uff1a\u8fd4\u56de\u83dc\u5355"))); if (suspendFlag || gameOverFlag) { @@ -405,15 +511,15 @@ void TDrawScreen(HDC hdc, HWND hWnd) if (suspendFlag) { - DrawText(hdc, _T("游戏已暂停"), -1, &titleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + DrawText(hdc, _T("\u6e38\u620f\u5df2\u6682\u505c"), -1, &titleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); SelectObject(hdc, bodyFont); - DrawText(hdc, _T("按 P 键继续游戏"), -1, &tipRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + DrawText(hdc, _T("\u6309 P \u952e\u7ee7\u7eed\u6e38\u620f"), -1, &tipRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } else { - DrawText(hdc, _T("游戏结束"), -1, &titleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + DrawText(hdc, _T("\u6e38\u620f\u7ed3\u675f"), -1, &titleRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); SelectObject(hdc, bodyFont); - DrawText(hdc, _T("按 R 键重新开始"), -1, &tipRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); + DrawText(hdc, _T("\u6309 R \u952e\u91cd\u65b0\u5f00\u59cb \u6216 M \u8fd4\u56de\u83dc\u5355"), -1, &tipRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } }