完善运行链路 调整中文界面

This commit is contained in:
2026-04-24 10:18:43 +08:00
parent 5f7d7d9949
commit 2f477272ab
3 changed files with 161 additions and 14 deletions
+108 -2
View File
@@ -3,6 +3,8 @@
#include "Tetris.h" #include "Tetris.h"
#define MAX_LOADSTRING 100 #define MAX_LOADSTRING 100
#define GAME_TIMER_ID 1
#define GAME_TIMER_INTERVAL 500
HINSTANCE hInst; HINSTANCE hInst;
TCHAR szTitle[MAX_LOADSTRING]; TCHAR szTitle[MAX_LOADSTRING];
@@ -31,6 +33,7 @@ int APIENTRY _tWinMain(HINSTANCE hInstance,
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_TETRIS, szWindowClass, MAX_LOADSTRING); LoadString(hInstance, IDC_TETRIS, szWindowClass, MAX_LOADSTRING);
lstrcpy(szTitle, _T("俄罗斯方块"));
MyRegisterClass(hInstance); MyRegisterClass(hInstance);
if (!InitInstance(hInstance, nCmdShow)) if (!InitInstance(hInstance, nCmdShow))
@@ -126,8 +129,8 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
/** /**
* @brief 主窗口消息处理函数,负责响应菜单、绘制和退出等系统消息。 * @brief 主窗口消息处理函数,负责响应菜单、绘制和退出等系统消息。
* *
* 当前阶段主要处理“关于”和“退出”菜单命令、窗口重绘请求以及销毁消息, * 该函数除菜单和绘制外,还负责初始化游戏、处理定时下落、
* 其余未处理的消息统一交给系统默认窗口过程继续处理 * 响应键盘操作以及管理暂停、重开和游戏结束状态
* *
* @param hWnd 当前窗口句柄。 * @param hWnd 当前窗口句柄。
* @param message 当前接收到的消息类型。 * @param message 当前接收到的消息类型。
@@ -139,6 +142,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{ {
switch (message) switch (message)
{ {
case WM_CREATE:
srand((unsigned int)time(nullptr));
Restart();
SetTimer(hWnd, GAME_TIMER_ID, GAME_TIMER_INTERVAL, nullptr);
InvalidateRect(hWnd, nullptr, TRUE);
break;
case WM_COMMAND: case WM_COMMAND:
{ {
int wmId = LOWORD(wParam); int wmId = LOWORD(wParam);
@@ -156,6 +165,101 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
} }
} }
break; break;
case WM_TIMER:
if (wParam == GAME_TIMER_ID && !suspendFlag && !gameOverFlag)
{
if (CanMoveDown())
{
MoveDown();
}
else
{
Fixing();
DeleteLines();
gameOverFlag = GameOver();
}
if (!gameOverFlag)
{
ComputeTarget();
}
InvalidateRect(hWnd, nullptr, TRUE);
}
break;
case WM_KEYDOWN:
if (wParam == 'R')
{
Restart();
InvalidateRect(hWnd, nullptr, TRUE);
break;
}
if (wParam == 'P')
{
suspendFlag = !suspendFlag;
InvalidateRect(hWnd, nullptr, TRUE);
break;
}
if (wParam == 'G')
{
targetFlag = !targetFlag;
InvalidateRect(hWnd, nullptr, TRUE);
break;
}
if (gameOverFlag || suspendFlag)
{
break;
}
switch (wParam)
{
case VK_LEFT:
if (CanMoveLeft())
{
MoveLeft();
}
break;
case VK_RIGHT:
if (CanMoveRight())
{
MoveRight();
}
break;
case VK_DOWN:
if (CanMoveDown())
{
MoveDown();
}
else
{
Fixing();
DeleteLines();
gameOverFlag = GameOver();
}
break;
case VK_UP:
Rotate();
break;
case VK_SPACE:
DropDown();
Fixing();
DeleteLines();
gameOverFlag = GameOver();
break;
default:
break;
}
if (!gameOverFlag)
{
ComputeTarget();
}
InvalidateRect(hWnd, nullptr, TRUE);
break;
case WM_PAINT: case WM_PAINT:
{ {
PAINTSTRUCT ps; PAINTSTRUCT ps;
@@ -165,6 +269,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
} }
break; break;
case WM_DESTROY: case WM_DESTROY:
KillTimer(hWnd, GAME_TIMER_ID);
PostQuitMessage(0); PostQuitMessage(0);
break; break;
default: default:
@@ -193,6 +298,7 @@ INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
switch (message) switch (message)
{ {
case WM_INITDIALOG: case WM_INITDIALOG:
SetWindowText(hDlg, _T("关于俄罗斯方块"));
return (INT_PTR)TRUE; return (INT_PTR)TRUE;
case WM_COMMAND: case WM_COMMAND:
+33 -4
View File
@@ -228,13 +228,40 @@ void MoveRight()
/** /**
* @brief 旋转当前活动方块到下一种朝向。 * @brief 旋转当前活动方块到下一种朝向。
* *
* 游戏中的每种方块都预置了 4 种旋转状态,该函数通过切换状态编号实现旋转。 * 游戏中的每种方块都预置了 4 种旋转状态,该函数会先尝试切换到下一状态,
* 当状态增加到 4 时重新回到 0,形成循环旋转效果 * 然后检查旋转后的方块是否越界或与固定方块重叠
* 如果旋转后的状态非法,则恢复到旋转前的状态。
*/ */
void Rotate() void Rotate()
{ {
// 切换到下一种旋转状态 int oldState = state;
state = (state + 1) % 4; state = (state + 1) % 4;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (bricks[type][state][i][j] != 0)
{
int checkY = point.y + i;
int checkX = point.x + j;
// 旋转后若越界,则恢复原状态
if (checkX < 0 || checkX >= nGameWidth || checkY < 0 || checkY >= nGameHeight)
{
state = oldState;
return;
}
// 旋转后若与固定方块重叠,则恢复原状态
if (workRegion[checkY][checkX] != 0)
{
state = oldState;
return;
}
}
}
}
} }
/** /**
@@ -258,7 +285,7 @@ void DropDown()
* 遍历当前方块 4x4 形状矩阵,把其中所有非空单元写入工作区数组, * 遍历当前方块 4x4 形状矩阵,把其中所有非空单元写入工作区数组,
* 表示该方块已经落地并转为固定状态。 * 表示该方块已经落地并转为固定状态。
* 随后将“下一方块”切换为新的当前方块,重置旋转状态, * 随后将“下一方块”切换为新的当前方块,重置旋转状态,
* 并把新方块生成到工作区上方的初始位置。 * 并把新方块生成到工作区上方的初始位置,同时刷新预测落点
*/ */
void Fixing() void Fixing()
{ {
@@ -286,6 +313,8 @@ void Fixing()
state = 0; state = 0;
point.x = 3; point.x = 3;
point.y = 0; point.y = 0;
target = point;
ComputeTarget();
} }
/** /**
+20 -8
View File
@@ -160,13 +160,13 @@ void TDrawScreen(HDC hdc, HWND hWnd)
gameRect.bottom gameRect.bottom
}; };
DrawText(hdc, _T("Tetris"), -1, &infoRect, DT_TOP | DT_LEFT | DT_SINGLELINE); DrawText(hdc, _T("俄罗斯方块"), -1, &infoRect, DT_TOP | DT_LEFT | DT_SINGLELINE);
TCHAR scoreText[64]; TCHAR scoreText[64];
_stprintf_s(scoreText, _T("Score: %d"), tScore); _stprintf_s(scoreText, _T("当前得分:%d"), tScore);
TextOut(hdc, infoRect.left, infoRect.top + GRID * 2, scoreText, lstrlen(scoreText)); TextOut(hdc, infoRect.left, infoRect.top + GRID * 2, scoreText, lstrlen(scoreText));
TextOut(hdc, infoRect.left, infoRect.top + GRID * 4, _T("Next:"), 5); TextOut(hdc, infoRect.left, infoRect.top + GRID * 4, _T("下一个方块:"), lstrlen(_T("下一个方块:")));
RECT nextRect = RECT nextRect =
{ {
@@ -210,19 +210,31 @@ void TDrawScreen(HDC hdc, HWND hWnd)
} }
} }
TextOut(hdc, infoRect.left, infoRect.top + GRID * 11, _T("Controls:"), 9); TextOut(hdc, infoRect.left, infoRect.top + GRID * 11, _T("操作说明:"), lstrlen(_T("操作说明:")));
TextOut(hdc, infoRect.left, infoRect.top + GRID * 12, _T("Arrow Keys"), 10); TextOut(hdc, infoRect.left, infoRect.top + GRID * 12, _T("方向键:移动 / 旋转"), lstrlen(_T("方向键:移动 / 旋转")));
TextOut(hdc, infoRect.left, infoRect.top + GRID * 13, _T("Space: Drop"), 11); 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:显示/隐藏落点")));
if (suspendFlag) if (suspendFlag)
{ {
TextOut(hdc, infoRect.left, infoRect.top + GRID * 15, _T("Paused"), 6); SetTextColor(hdc, RGB(220, 120, 0));
TextOut(hdc, infoRect.left, infoRect.top + GRID * 17, _T("游戏已暂停"), lstrlen(_T("游戏已暂停")));
SetTextColor(hdc, RGB(40, 40, 40));
} }
if (gameOverFlag) if (gameOverFlag)
{ {
RECT overRect = gameRect; RECT overRect = gameRect;
SetTextColor(hdc, RGB(255, 80, 80)); SetTextColor(hdc, RGB(255, 80, 80));
DrawText(hdc, _T("GAME OVER"), -1, &overRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); DrawText(hdc, _T("游戏结束"), -1, &overRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
RECT tipRect =
{
gameRect.left,
gameRect.top + GRID * 11,
gameRect.right,
gameRect.top + GRID * 13
};
DrawText(hdc, _T("按 R 键重新开始"), -1, &tipRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
} }
} }