移除旧的GameOver判定并统一顶部溢出失败逻辑
This commit is contained in:
+12
-6
@@ -188,8 +188,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
else
|
||||
{
|
||||
Fixing();
|
||||
DeleteLines();
|
||||
gameOverFlag = GameOver();
|
||||
if (!gameOverFlag)
|
||||
{
|
||||
DeleteLines();
|
||||
}
|
||||
}
|
||||
|
||||
if (!gameOverFlag)
|
||||
@@ -255,8 +257,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
else
|
||||
{
|
||||
Fixing();
|
||||
DeleteLines();
|
||||
gameOverFlag = GameOver();
|
||||
if (!gameOverFlag)
|
||||
{
|
||||
DeleteLines();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VK_UP:
|
||||
@@ -266,8 +270,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
case VK_SPACE:
|
||||
DropDown();
|
||||
Fixing();
|
||||
DeleteLines();
|
||||
gameOverFlag = GameOver();
|
||||
if (!gameOverFlag)
|
||||
{
|
||||
DeleteLines();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
+96
-46
@@ -69,6 +69,77 @@ COLORREF BrickColor[7] =
|
||||
RGB(197, 170, 255)
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 计算指定方块在指定旋转状态下的最小包围盒边界。
|
||||
*
|
||||
* 该函数会遍历 4x4 形状矩阵,找出所有非空单元的上下左右边界,
|
||||
* 供后续统一计算生成位置和对齐方式时使用。
|
||||
*
|
||||
* @param brickType 方块类型编号。
|
||||
* @param brickState 方块旋转状态编号。
|
||||
* @param minRow 返回最上方非空行号。
|
||||
* @param maxRow 返回最下方非空行号。
|
||||
* @param minCol 返回最左侧非空列号。
|
||||
* @param maxCol 返回最右侧非空列号。
|
||||
*/
|
||||
static void GetBrickBounds(int brickType, int brickState, int& minRow, int& maxRow, int& minCol, int& maxCol)
|
||||
{
|
||||
minRow = 4;
|
||||
maxRow = -1;
|
||||
minCol = 4;
|
||||
maxCol = -1;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
if (bricks[brickType][brickState][i][j] != 0)
|
||||
{
|
||||
if (i < minRow)
|
||||
{
|
||||
minRow = i;
|
||||
}
|
||||
if (i > maxRow)
|
||||
{
|
||||
maxRow = i;
|
||||
}
|
||||
if (j < minCol)
|
||||
{
|
||||
minCol = j;
|
||||
}
|
||||
if (j > maxCol)
|
||||
{
|
||||
maxCol = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算指定方块的统一生成位置。
|
||||
*
|
||||
* 该函数会根据方块在初始旋转状态下的最小包围盒,
|
||||
* 自动把方块水平居中到游戏区附近,并将顶部非空行对齐到可视区域顶部。
|
||||
* 这样不同形状的方块在生成时看起来会更加统一。
|
||||
*
|
||||
* @param brickType 方块类型编号。
|
||||
* @return Point 计算得到的生成坐标。
|
||||
*/
|
||||
static Point GetSpawnPoint(int brickType)
|
||||
{
|
||||
int minRow, maxRow, minCol, maxCol;
|
||||
GetBrickBounds(brickType, 0, minRow, maxRow, minCol, maxCol);
|
||||
|
||||
int brickWidth = maxCol - minCol + 1;
|
||||
int brickHeight = maxRow - minRow + 1;
|
||||
Point spawnPoint;
|
||||
spawnPoint.x = (nGameWidth - brickWidth) / 2 - minCol;
|
||||
spawnPoint.y = -brickHeight;
|
||||
|
||||
return spawnPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 判断当前方块是否可以继续向下移动。
|
||||
*
|
||||
@@ -98,7 +169,7 @@ bool CanMoveDown()
|
||||
}
|
||||
|
||||
// 检查下方是否有其他固定方块
|
||||
if (workRegion[nextY][nextX] != 0)
|
||||
if (nextY >= 0 && workRegion[nextY][nextX] != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -138,7 +209,7 @@ bool CanMoveLeft()
|
||||
}
|
||||
|
||||
// 检查左侧是否有其他固定方块
|
||||
if (workRegion[nextY][nextX] != 0)
|
||||
if (nextY >= 0 && workRegion[nextY][nextX] != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -178,7 +249,7 @@ bool CanMoveRight()
|
||||
}
|
||||
|
||||
// 检查右侧是否有其他固定方块
|
||||
if (workRegion[nextY][nextX] != 0)
|
||||
if (nextY >= 0 && workRegion[nextY][nextX] != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -247,14 +318,14 @@ void Rotate()
|
||||
int checkX = point.x + j;
|
||||
|
||||
// 旋转后若越界,则恢复原状态
|
||||
if (checkX < 0 || checkX >= nGameWidth || checkY < 0 || checkY >= nGameHeight)
|
||||
if (checkX < 0 || checkX >= nGameWidth || checkY >= nGameHeight)
|
||||
{
|
||||
state = oldState;
|
||||
return;
|
||||
}
|
||||
|
||||
// 旋转后若与固定方块重叠,则恢复原状态
|
||||
if (workRegion[checkY][checkX] != 0)
|
||||
if (checkY >= 0 && workRegion[checkY][checkX] != 0)
|
||||
{
|
||||
state = oldState;
|
||||
return;
|
||||
@@ -284,11 +355,15 @@ void DropDown()
|
||||
*
|
||||
* 遍历当前方块 4x4 形状矩阵,把其中所有非空单元写入工作区数组,
|
||||
* 表示该方块已经落地并转为固定状态。
|
||||
* 随后将“下一方块”切换为新的当前方块,重置旋转状态,
|
||||
* 如果固定时仍有任意非空单元位于可视区域顶部之外,则判定游戏结束。
|
||||
* 此时当前方块在可视区域内的部分仍会保留在工作区中。
|
||||
* 若未超出顶部,再将“下一方块”切换为新的当前方块,重置旋转状态,
|
||||
* 并把新方块生成到工作区上方的初始位置,同时刷新预测落点。
|
||||
*/
|
||||
void Fixing()
|
||||
{
|
||||
bool overflowTop = false;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
@@ -298,7 +373,13 @@ void Fixing()
|
||||
int fixY = point.y + i;
|
||||
int fixX = point.x + j;
|
||||
|
||||
// 将当前方块的非空单元写入工作区
|
||||
// 只要当前方块任意非空单元仍超出顶部,就标记为结束
|
||||
if (fixY < 0)
|
||||
{
|
||||
overflowTop = true;
|
||||
}
|
||||
|
||||
// 将当前方块在可视区域内的部分写入工作区
|
||||
if (fixY >= 0 && fixY < nGameHeight && fixX >= 0 && fixX < nGameWidth)
|
||||
{
|
||||
workRegion[fixY][fixX] = bricks[type][state][i][j];
|
||||
@@ -307,12 +388,17 @@ void Fixing()
|
||||
}
|
||||
}
|
||||
|
||||
if (overflowTop)
|
||||
{
|
||||
gameOverFlag = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// 生成下一个活动方块
|
||||
type = nType;
|
||||
nType = rand() % 7;
|
||||
state = 0;
|
||||
point.x = 3;
|
||||
point.y = 0;
|
||||
point = GetSpawnPoint(type);
|
||||
target = point;
|
||||
ComputeTarget();
|
||||
}
|
||||
@@ -374,41 +460,6 @@ void DeleteLines()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 判断游戏是否结束。
|
||||
*
|
||||
* 当新的活动方块生成到初始位置后,如果它的任意一个非空单元
|
||||
* 与工作区中已经固定的方块发生重叠,则说明顶部已被占满,
|
||||
* 当前局面无法继续生成新方块,游戏结束。
|
||||
*
|
||||
* @return bool 若游戏结束返回 true,否则返回 false。
|
||||
*/
|
||||
bool GameOver()
|
||||
{
|
||||
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 (checkY >= 0 && checkY < nGameHeight && checkX >= 0 && checkX < nGameWidth)
|
||||
{
|
||||
if (workRegion[checkY][checkX] != 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 计算当前活动方块的预测落点位置。
|
||||
*
|
||||
@@ -460,8 +511,7 @@ void Restart()
|
||||
type = rand() % 7;
|
||||
nType = rand() % 7;
|
||||
state = 0;
|
||||
point.x = 3;
|
||||
point.y = 0;
|
||||
point = GetSpawnPoint(type);
|
||||
target = point;
|
||||
|
||||
ComputeTarget();
|
||||
|
||||
+27
-24
@@ -217,7 +217,7 @@ void TDrawScreen(HDC hdc, HWND hWnd)
|
||||
}
|
||||
|
||||
// 绘制预测落点
|
||||
if (targetFlag)
|
||||
if (targetFlag && !gameOverFlag)
|
||||
{
|
||||
HPEN targetPen = CreatePen(PS_DOT, SS(2), RGB(255, 240, 245));
|
||||
oldPen = (HPEN)SelectObject(hdc, targetPen);
|
||||
@@ -252,34 +252,37 @@ void TDrawScreen(HDC hdc, HWND hWnd)
|
||||
}
|
||||
|
||||
// 绘制当前活动方块
|
||||
for (int i = 0; i < 4; i++)
|
||||
if (!gameOverFlag)
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (bricks[type][state][i][j] != 0)
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
int drawY = point.y + i;
|
||||
int drawX = point.x + j;
|
||||
|
||||
if (drawY >= 0 && drawY < nGameHeight && drawX >= 0 && drawX < nGameWidth)
|
||||
if (bricks[type][state][i][j] != 0)
|
||||
{
|
||||
RECT brickRect =
|
||||
{
|
||||
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)
|
||||
};
|
||||
int drawY = point.y + i;
|
||||
int drawX = point.x + j;
|
||||
|
||||
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, SS(12), SS(12));
|
||||
SelectObject(hdc, oldBrush);
|
||||
SelectObject(hdc, oldPen);
|
||||
DeleteObject(brickBrush);
|
||||
DeleteObject(brickPen);
|
||||
if (drawY >= 0 && drawY < nGameHeight && drawX >= 0 && drawX < nGameWidth)
|
||||
{
|
||||
RECT brickRect =
|
||||
{
|
||||
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, SS(12), SS(12));
|
||||
SelectObject(hdc, oldBrush);
|
||||
SelectObject(hdc, oldPen);
|
||||
DeleteObject(brickBrush);
|
||||
DeleteObject(brickPen);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user