fixed next block

This commit is contained in:
2025-12-07 12:27:00 +01:00
parent f5424e8f72
commit d2ba311c5f
2 changed files with 119 additions and 15 deletions

View File

@ -156,6 +156,99 @@ void GameRenderer::drawSmallPiece(SDL_Renderer* renderer, SDL_Texture* blocksTex
} }
} }
void GameRenderer::renderNextPanel(
SDL_Renderer* renderer,
FontAtlas* pixelFont,
SDL_Texture* blocksTex,
const Game::Piece& nextPiece,
float panelX,
float panelY,
float panelW,
float panelH,
float tileSize
) {
if (!renderer || !pixelFont) {
return;
}
const SDL_Color gridBorderColor{60, 80, 160, 255}; // matches main grid outline
const SDL_Color bayColor{8, 12, 24, 235};
const SDL_Color bayOutline{25, 62, 86, 220};
const SDL_Color labelColor{255, 220, 0, 255};
SDL_FRect bayRect{panelX, panelY, panelW, panelH};
SDL_SetRenderDrawColor(renderer, bayColor.r, bayColor.g, bayColor.b, bayColor.a);
SDL_RenderFillRect(renderer, &bayRect);
SDL_FRect thinOutline{panelX - 1.0f, panelY - 1.0f, panelW + 2.0f, panelH + 2.0f};
auto drawOutlineNoBottom = [&](const SDL_FRect& rect, SDL_Color color) {
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
const float left = rect.x;
const float top = rect.y;
const float right = rect.x + rect.w;
const float bottom = rect.y + rect.h;
SDL_RenderLine(renderer, left, top, right, top); // top edge
SDL_RenderLine(renderer, left, top, left, bottom); // left edge
SDL_RenderLine(renderer, right, top, right, bottom); // right edge
};
drawOutlineNoBottom(thinOutline, gridBorderColor);
drawOutlineNoBottom(bayRect, bayOutline);
const float labelPad = tileSize * 0.25f;
pixelFont->draw(renderer, panelX + labelPad, panelY + labelPad * 0.5f, "NEXT", 0.9f, labelColor);
if (nextPiece.type >= PIECE_COUNT) {
return;
}
// Determine the occupied bounds of the tetromino within its 4x4 local grid.
int minCx = 4;
int maxCx = -1;
int minCy = 4;
int maxCy = -1;
for (int cy = 0; cy < 4; ++cy) {
for (int cx = 0; cx < 4; ++cx) {
if (!Game::cellFilled(nextPiece, cx, cy)) {
continue;
}
minCx = std::min(minCx, cx);
maxCx = std::max(maxCx, cx);
minCy = std::min(minCy, cy);
maxCy = std::max(maxCy, cy);
}
}
if (maxCx < minCx || maxCy < minCy) {
return;
}
// Reserve a little headroom for the NEXT label, then center the piece in screen-space.
const float labelReserve = tileSize * 0.9f;
const float previewTop = panelY + std::min(labelReserve, panelH * 0.45f);
const float previewBottom = panelY + panelH - tileSize * 0.25f;
const float previewCenterY = (previewTop + previewBottom) * 0.5f;
const float previewCenterX = panelX + panelW * 0.5f;
const float pieceWidth = static_cast<float>(maxCx - minCx + 1) * tileSize;
const float pieceHeight = static_cast<float>(maxCy - minCy + 1) * tileSize;
// Nudge preview slightly to the right so it aligns with the main grid's visual columns
const float previewNudgeX = tileSize * 0.5f;
const float startX = previewCenterX - pieceWidth * 0.5f - static_cast<float>(minCx) * tileSize + previewNudgeX;
const float startY = previewCenterY - pieceHeight * 0.5f - static_cast<float>(minCy) * tileSize;
for (int cy = 0; cy < 4; ++cy) {
for (int cx = 0; cx < 4; ++cx) {
if (!Game::cellFilled(nextPiece, cx, cy)) {
continue;
}
const float px = startX + static_cast<float>(cx) * tileSize;
const float py = startY + static_cast<float>(cy) * tileSize;
drawBlockTexture(renderer, blocksTex, px, py, tileSize, nextPiece.type);
}
}
}
void GameRenderer::renderPlayingState( void GameRenderer::renderPlayingState(
SDL_Renderer* renderer, SDL_Renderer* renderer,
Game* game, Game* game,
@ -235,10 +328,10 @@ void GameRenderer::renderPlayingState(
const float statsH = GRID_H; const float statsH = GRID_H;
// Next piece preview position // Next piece preview position
const float nextW = finalBlockSize * 4 + 20; const float NEXT_PANEL_WIDTH = finalBlockSize * 6.0f; // +1 cell padding on each horizontal side
const float nextH = finalBlockSize * 2 + 20; const float NEXT_PANEL_HEIGHT = finalBlockSize * 3.0f;
const float nextX = gridX + (GRID_W - nextW) * 0.5f; const float NEXT_PANEL_X = gridX + (GRID_W - NEXT_PANEL_WIDTH) * 0.5f;
const float nextY = contentStartY + contentOffsetY; const float NEXT_PANEL_Y = gridY - NEXT_PANEL_HEIGHT - 2.0f; // nudge up ~2px
// Handle line clearing effects // Handle line clearing effects
if (game->hasCompletedLines() && lineEffect && !lineEffect->isActive()) { if (game->hasCompletedLines() && lineEffect && !lineEffect->isActive()) {
@ -248,7 +341,17 @@ void GameRenderer::renderPlayingState(
// Draw game grid border // Draw game grid border
drawRectWithOffset(gridX - 3 - contentOffsetX, gridY - 3 - contentOffsetY, GRID_W + 6, GRID_H + 6, {100, 120, 200, 255}); drawRectWithOffset(gridX - 3 - contentOffsetX, gridY - 3 - contentOffsetY, GRID_W + 6, GRID_H + 6, {100, 120, 200, 255});
drawRectWithOffset(gridX - 1 - contentOffsetX, gridY - 1 - contentOffsetY, GRID_W + 2, GRID_H + 2, {60, 80, 160, 255}); // Draw a 1px blue border around grid but omit the top horizontal so the NEXT panel
// can visually join seamlessly. We'll draw left, right and bottom bands manually.
{
SDL_Color blue{60, 80, 160, 255};
// left vertical band (1px wide)
drawRectWithOffset(gridX - 1 - contentOffsetX, gridY - contentOffsetY, 1.0f, GRID_H, blue);
// right vertical band (1px wide)
drawRectWithOffset(gridX + GRID_W - contentOffsetX, gridY - contentOffsetY, 1.0f, GRID_H, blue);
// bottom horizontal band (1px high)
drawRectWithOffset(gridX - 1 - contentOffsetX, gridY + GRID_H - contentOffsetY, GRID_W + 2.0f, 1.0f, blue);
}
drawRectWithOffset(gridX - contentOffsetX, gridY - contentOffsetY, GRID_W, GRID_H, {20, 25, 35, 255}); drawRectWithOffset(gridX - contentOffsetX, gridY - contentOffsetY, GRID_W, GRID_H, {20, 25, 35, 255});
// Draw stats panel backdrop using the same art as the score panel // Draw stats panel backdrop using the same art as the score panel
@ -442,10 +545,16 @@ void GameRenderer::renderPlayingState(
} }
SDL_SetRenderDrawBlendMode(renderer, oldBlend); SDL_SetRenderDrawBlendMode(renderer, oldBlend);
// Draw next piece preview panel border renderNextPanel(renderer, pixelFont, blocksTex, game->next(), NEXT_PANEL_X, NEXT_PANEL_Y, NEXT_PANEL_WIDTH, NEXT_PANEL_HEIGHT, finalBlockSize);
drawRectWithOffset(nextX - 3 - contentOffsetX, nextY - 3 - contentOffsetY, nextW + 6, nextH + 6, {100, 120, 200, 255});
drawRectWithOffset(nextX - contentOffsetX, nextY - contentOffsetY, nextW, nextH, {30, 35, 50, 255}); // Draw a thin horizontal connector at the bottom of the NEXT panel so it visually
// connects to the top of the grid (appears as a single continuous frame).
SDL_SetRenderDrawColor(renderer, 60, 80, 160, 255); // same as grid border
float connectorY = NEXT_PANEL_Y + NEXT_PANEL_HEIGHT; // bottom of next panel (near grid top)
// Draw a 2px-high filled connector to overwrite any existing grid border pixels
SDL_FRect connRect{ NEXT_PANEL_X, connectorY - 1.0f, NEXT_PANEL_WIDTH, 2.0f };
SDL_RenderFillRect(renderer, &connRect);
// Precompute row drop offsets (line collapse effect) // Precompute row drop offsets (line collapse effect)
std::array<float, Game::ROWS> rowDropOffsets{}; std::array<float, Game::ROWS> rowDropOffsets{};
@ -695,12 +804,6 @@ void GameRenderer::renderPlayingState(
lineEffect->render(renderer, blocksTex, static_cast<int>(gridX), static_cast<int>(gridY), static_cast<int>(finalBlockSize)); lineEffect->render(renderer, blocksTex, static_cast<int>(gridX), static_cast<int>(gridY), static_cast<int>(finalBlockSize));
} }
// Draw next piece preview
pixelFont->draw(renderer, nextX + 10, nextY - 20, "NEXT", 1.0f, {255, 220, 0, 255});
if (game->next().type < PIECE_COUNT) {
drawSmallPiece(renderer, blocksTex, static_cast<PieceType>(game->next().type), nextX + 10, nextY + 10, finalBlockSize * 0.6f);
}
// Draw block statistics (left panel) // Draw block statistics (left panel)
const auto& blockCounts = game->getBlockCounts(); const auto& blockCounts = game->getBlockCounts();
int totalBlocks = 0; int totalBlocks = 0;

View File

@ -53,6 +53,7 @@ private:
static void drawBlockTexture(SDL_Renderer* renderer, SDL_Texture* blocksTex, float x, float y, float size, int blockType); static void drawBlockTexture(SDL_Renderer* renderer, SDL_Texture* blocksTex, float x, float y, float size, int blockType);
static void drawPiece(SDL_Renderer* renderer, SDL_Texture* blocksTex, const Game::Piece& piece, float ox, float oy, float tileSize, bool isGhost = false, float pixelOffsetX = 0.0f, float pixelOffsetY = 0.0f); static void drawPiece(SDL_Renderer* renderer, SDL_Texture* blocksTex, const Game::Piece& piece, float ox, float oy, float tileSize, bool isGhost = false, float pixelOffsetX = 0.0f, float pixelOffsetY = 0.0f);
static void drawSmallPiece(SDL_Renderer* renderer, SDL_Texture* blocksTex, PieceType pieceType, float x, float y, float tileSize); static void drawSmallPiece(SDL_Renderer* renderer, SDL_Texture* blocksTex, PieceType pieceType, float x, float y, float tileSize);
static void renderNextPanel(SDL_Renderer* renderer, FontAtlas* pixelFont, SDL_Texture* blocksTex, const Game::Piece& nextPiece, float panelX, float panelY, float panelW, float panelH, float tileSize);
// Helper function for drawing rectangles // Helper function for drawing rectangles
static void drawRect(SDL_Renderer* renderer, float x, float y, float w, float h, SDL_Color c); static void drawRect(SDL_Renderer* renderer, float x, float y, float w, float h, SDL_Color c);