diff --git a/image.png b/image.png index e0526fb..545a4b1 100644 Binary files a/image.png and b/image.png differ diff --git a/src/source/Tetris.cpp b/src/source/Tetris.cpp index ed79fbe..63bf6aa 100644 --- a/src/source/Tetris.cpp +++ b/src/source/Tetris.cpp @@ -200,6 +200,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) InvalidateRect(hWnd, nullptr, FALSE); } break; + case WM_SIZE: + InvalidateRect(hWnd, nullptr, FALSE); + break; case WM_KEYDOWN: if (wParam == 'R') { diff --git a/src/source/TetrisRender.cpp b/src/source/TetrisRender.cpp index 7f05468..07a35f0 100644 --- a/src/source/TetrisRender.cpp +++ b/src/source/TetrisRender.cpp @@ -16,20 +16,59 @@ void TDrawScreen(HDC hdc, HWND hWnd) RECT clientRect; GetClientRect(hWnd, &clientRect); + int clientWidth = clientRect.right - clientRect.left; + int clientHeight = clientRect.bottom - clientRect.top; + int scaleX = MulDiv(clientWidth, 1000, WINDOW_CLIENT_WIDTH); + int scaleY = MulDiv(clientHeight, 1000, WINDOW_CLIENT_HEIGHT); + int scale = (scaleX < scaleY) ? scaleX : scaleY; + + if (scale < 500) + { + scale = 500; + } + + int layoutWidth = MulDiv(WINDOW_CLIENT_WIDTH, scale, 1000); + int layoutHeight = MulDiv(WINDOW_CLIENT_HEIGHT, scale, 1000); + int offsetX = (clientWidth - layoutWidth) / 2; + int offsetY = (clientHeight - layoutHeight) / 2; + + auto SX = [offsetX, scale](int value) -> int + { + return offsetX + MulDiv(value, scale, 1000); + }; + + auto SY = [offsetY, scale](int value) -> int + { + return offsetY + MulDiv(value, scale, 1000); + }; + + auto SS = [scale](int value) -> int + { + int result = MulDiv(value, scale, 1000); + return result < 1 ? 1 : result; + }; + + 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; + int boardHeight = grid * nGameHeight; + const RECT gameRect = { - WINDOW_PADDING, - WINDOW_PADDING, - WINDOW_PADDING + nGameWidth * GRID, - WINDOW_PADDING + nGameHeight * GRID + SX(WINDOW_PADDING), + SY(WINDOW_PADDING), + SX(WINDOW_PADDING) + boardWidth, + SY(WINDOW_PADDING) + boardHeight }; const RECT panelRect = { - gameRect.right + SIDE_PANEL_GAP, - WINDOW_PADDING, - gameRect.right + SIDE_PANEL_GAP + SIDE_PANEL_WIDTH, - WINDOW_PADDING + nGameHeight * GRID + gameRect.right + panelGap, + SY(WINDOW_PADDING), + gameRect.right + panelGap + panelWidth, + SY(WINDOW_PADDING) + boardHeight }; const COLORREF pageColor = RGB(255, 244, 248); @@ -64,22 +103,22 @@ void TDrawScreen(HDC hdc, HWND hWnd) // 创建中文清晰字体 HFONT titleFont = CreateFont( - -34, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, + -SS(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, + -SS(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, + -SS(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, + -SS(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")); @@ -92,9 +131,9 @@ void TDrawScreen(HDC hdc, HWND hWnd) 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); + RoundRect(hdc, gameRect.left - SS(10), gameRect.top - SS(10), gameRect.right + SS(10), gameRect.bottom + SS(10), SS(28), SS(28)); SelectObject(hdc, panelBrush); - RoundRect(hdc, panelRect.left, panelRect.top, panelRect.right, panelRect.bottom, 30, 30); + RoundRect(hdc, panelRect.left, panelRect.top, panelRect.right, panelRect.bottom, SS(30), SS(30)); SelectObject(hdc, oldBrush); SelectObject(hdc, oldPen); DeleteObject(gameCardBrush); @@ -108,10 +147,10 @@ void TDrawScreen(HDC hdc, HWND hWnd) RECT innerRect = { - gameRect.left + 6, - gameRect.top + 6, - gameRect.right - 6, - gameRect.bottom - 6 + gameRect.left + SS(6), + gameRect.top + SS(6), + gameRect.right - SS(6), + gameRect.bottom - SS(6) }; HBRUSH innerBrush = CreateSolidBrush(boardInnerColor); @@ -119,10 +158,10 @@ void TDrawScreen(HDC hdc, HWND hWnd) DeleteObject(innerBrush); // 绘制游戏区边框 - HPEN borderPen = CreatePen(PS_SOLID, 2, RGB(132, 108, 146)); + HPEN borderPen = CreatePen(PS_SOLID, SS(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); + RoundRect(hdc, gameRect.left, gameRect.top, gameRect.right, gameRect.bottom, SS(18), SS(18)); SelectObject(hdc, oldBrush); SelectObject(hdc, oldPen); DeleteObject(borderPen); @@ -133,14 +172,14 @@ void TDrawScreen(HDC hdc, HWND hWnd) for (int i = 1; i < nGameWidth; i++) { - int x = gameRect.left + i * GRID; + int x = gameRect.left + i * grid; MoveToEx(hdc, x, gameRect.top, nullptr); LineTo(hdc, x, gameRect.bottom); } for (int i = 1; i < nGameHeight; i++) { - int y = gameRect.top + i * GRID; + int y = gameRect.top + i * grid; MoveToEx(hdc, gameRect.left, y, nullptr); LineTo(hdc, gameRect.right, y); } @@ -158,17 +197,17 @@ void TDrawScreen(HDC hdc, HWND hWnd) int colorIndex = workRegion[i][j] - 1; RECT brickRect = { - gameRect.left + j * GRID + 2, - gameRect.top + i * GRID + 2, - gameRect.left + (j + 1) * GRID - 2, - gameRect.top + (i + 1) * GRID - 2 + gameRect.left + j * grid + SS(2), + gameRect.top + i * grid + SS(2), + gameRect.left + (j + 1) * grid - SS(2), + gameRect.top + (i + 1) * grid - SS(2) }; HBRUSH brickBrush = CreateSolidBrush(BrickColor[colorIndex]); 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); + RoundRect(hdc, brickRect.left, brickRect.top, brickRect.right, brickRect.bottom, SS(10), SS(10)); SelectObject(hdc, oldBrush); SelectObject(hdc, oldPen); DeleteObject(brickBrush); @@ -180,7 +219,7 @@ void TDrawScreen(HDC hdc, HWND hWnd) // 绘制预测落点 if (targetFlag) { - HPEN targetPen = CreatePen(PS_DOT, 2, RGB(255, 240, 245)); + HPEN targetPen = CreatePen(PS_DOT, SS(2), RGB(255, 240, 245)); oldPen = (HPEN)SelectObject(hdc, targetPen); oldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH)); @@ -197,11 +236,11 @@ void TDrawScreen(HDC hdc, HWND hWnd) { RoundRect( hdc, - gameRect.left + drawX * GRID + 5, - gameRect.top + drawY * GRID + 5, - gameRect.left + (drawX + 1) * GRID - 5, - gameRect.top + (drawY + 1) * GRID - 5, - 8, 8); + gameRect.left + drawX * grid + SS(5), + gameRect.top + drawY * grid + SS(5), + gameRect.left + (drawX + 1) * grid - SS(5), + gameRect.top + (drawY + 1) * grid - SS(5), + SS(8), SS(8)); } } } @@ -226,17 +265,17 @@ void TDrawScreen(HDC hdc, HWND hWnd) { RECT brickRect = { - gameRect.left + drawX * GRID + 2, - gameRect.top + drawY * GRID + 2, - gameRect.left + (drawX + 1) * GRID - 2, - gameRect.top + (drawY + 1) * GRID - 2 + gameRect.left + drawX * grid + SS(2), + gameRect.top + drawY * grid + SS(2), + gameRect.left + (drawX + 1) * grid - SS(2), + gameRect.top + (drawY + 1) * grid - SS(2) }; HBRUSH brickBrush = CreateSolidBrush(BrickColor[type]); 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); + RoundRect(hdc, brickRect.left, brickRect.top, brickRect.right, brickRect.bottom, SS(12), SS(12)); SelectObject(hdc, oldBrush); SelectObject(hdc, oldPen); DeleteObject(brickBrush); @@ -249,12 +288,12 @@ void TDrawScreen(HDC hdc, HWND hWnd) // 绘制右侧信息面板 HFONT oldFont = (HFONT)SelectObject(hdc, titleFont); SetTextColor(hdc, titleColor); - TextOut(hdc, panelRect.left + 24, panelRect.top + 22, _T("俄罗斯方块"), lstrlen(_T("俄罗斯方块"))); + TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(22), _T("俄罗斯方块"), lstrlen(_T("俄罗斯方块"))); - HPEN accentPen = CreatePen(PS_SOLID, 3, accentColor); + HPEN accentPen = CreatePen(PS_SOLID, SS(3), accentColor); oldPen = (HPEN)SelectObject(hdc, accentPen); - MoveToEx(hdc, panelRect.left + 24, panelRect.top + 68, nullptr); - LineTo(hdc, panelRect.left + 160, panelRect.top + 68); + MoveToEx(hdc, panelRect.left + SS(24), panelRect.top + SS(68), nullptr); + LineTo(hdc, panelRect.left + SS(160), panelRect.top + SS(68)); SelectObject(hdc, oldPen); DeleteObject(accentPen); @@ -263,23 +302,23 @@ void TDrawScreen(HDC hdc, HWND hWnd) TCHAR scoreText[64]; _stprintf_s(scoreText, _T("当前得分 %d"), tScore); - TextOut(hdc, panelRect.left + 24, panelRect.top + 104, scoreText, lstrlen(scoreText)); + TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(104), scoreText, lstrlen(scoreText)); - TextOut(hdc, panelRect.left + 24, panelRect.top + 172, _T("下一个方块"), lstrlen(_T("下一个方块"))); + TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(172), _T("下一个方块"), lstrlen(_T("下一个方块"))); RECT nextCard = { - panelRect.left + 24, - panelRect.top + 210, - panelRect.left + 24 + GRID * 4 + 32, - panelRect.top + 210 + GRID * 4 + 32 + panelRect.left + SS(24), + panelRect.top + SS(210), + panelRect.left + SS(24) + grid * 4 + SS(32), + panelRect.top + SS(210) + grid * 4 + SS(32) }; 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); + RoundRect(hdc, nextCard.left, nextCard.top, nextCard.right, nextCard.bottom, SS(22), SS(22)); SelectObject(hdc, oldBrush); SelectObject(hdc, oldPen); DeleteObject(nextCardBrush); @@ -294,17 +333,17 @@ void TDrawScreen(HDC hdc, HWND hWnd) { RECT brickRect = { - nextCard.left + 16 + j * GRID, - nextCard.top + 16 + i * GRID, - nextCard.left + 16 + (j + 1) * GRID - 2, - nextCard.top + 16 + (i + 1) * GRID - 2 + nextCard.left + SS(16) + j * grid, + nextCard.top + SS(16) + i * grid, + nextCard.left + SS(16) + (j + 1) * grid - SS(2), + nextCard.top + SS(16) + (i + 1) * grid - SS(2) }; HBRUSH brickBrush = CreateSolidBrush(BrickColor[nType]); 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); + RoundRect(hdc, brickRect.left, brickRect.top, brickRect.right, brickRect.bottom, SS(10), SS(10)); SelectObject(hdc, oldBrush); SelectObject(hdc, oldPen); DeleteObject(brickBrush); @@ -314,29 +353,29 @@ void TDrawScreen(HDC hdc, HWND hWnd) } SelectObject(hdc, sectionFont); - TextOut(hdc, panelRect.left + 24, panelRect.top + 390, _T("操作提示"), lstrlen(_T("操作提示"))); + TextOut(hdc, panelRect.left + SS(24), panelRect.top + SS(390), _T("操作提示"), lstrlen(_T("操作提示"))); SelectObject(hdc, bodyFont); - TextOut(hdc, panelRect.left + 24, panelRect.top + 432, _T("方向键 / WASD:移动 / 旋转"), lstrlen(_T("方向键 / WASD:移动 / 旋转"))); - 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:显示 / 隐藏落点"))); + 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:显示 / 隐藏落点"))); if (suspendFlag || gameOverFlag) { RECT overlayRect = { - gameRect.left + GRID, - gameRect.top + GRID * 6, - gameRect.right - GRID, - gameRect.top + GRID * 13 + gameRect.left + grid, + gameRect.top + grid * 6, + gameRect.right - grid, + gameRect.top + grid * 13 }; 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); + RoundRect(hdc, overlayRect.left, overlayRect.top, overlayRect.right, overlayRect.bottom, SS(26), SS(26)); SelectObject(hdc, oldBrush); SelectObject(hdc, oldPen); DeleteObject(overlayBrush); @@ -345,17 +384,17 @@ void TDrawScreen(HDC hdc, HWND hWnd) RECT titleRect = { overlayRect.left, - overlayRect.top + GRID, + overlayRect.top + grid, overlayRect.right, - overlayRect.top + GRID * 3 + overlayRect.top + grid * 3 }; RECT tipRect = { - overlayRect.left + 20, - overlayRect.top + GRID * 3, - overlayRect.right - 20, - overlayRect.bottom - GRID + overlayRect.left + SS(20), + overlayRect.top + grid * 3, + overlayRect.right - SS(20), + overlayRect.bottom - grid }; SetTextColor(hdc, RGB(121, 76, 99));