gameplay score board

This commit is contained in:
2025-12-06 21:07:17 +01:00
parent 1355ce49fe
commit ec9eb45cc3
14 changed files with 123 additions and 45 deletions

View File

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 1.9 MiB

View File

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

View File

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 KiB

View File

@ -12,7 +12,7 @@ Sound=1
SmoothScroll=1
[Player]
Name=GREGOR
Name=PLAYER
[Debug]
Enabled=1

View File

@ -1131,6 +1131,7 @@ void ApplicationManager::setupStateHandlers() {
m_stateContext.pixelFont,
m_stateContext.lineEffect,
m_stateContext.blocksTex,
m_stateContext.scorePanelTex,
LOGICAL_W,
LOGICAL_H,
logicalScale,

View File

@ -198,10 +198,19 @@ void GameRenderer::renderPlayingState(
lineEffect->startLineClear(completedLines, static_cast<int>(gridX), static_cast<int>(gridY), static_cast<int>(finalBlockSize));
}
// Draw game grid border
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});
drawRectWithOffset(gridX - contentOffsetX, gridY - contentOffsetY, GRID_W, GRID_H, {20, 25, 35, 255});
// Draw styled game grid border and semi-transparent background so the scene shows through.
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
// Outer glow layers (subtle, increasing spread, decreasing alpha)
drawRectWithOffset(gridX - 8 - contentOffsetX, gridY - 8 - contentOffsetY, GRID_W + 16, GRID_H + 16, {100, 120, 200, 28});
drawRectWithOffset(gridX - 6 - contentOffsetX, gridY - 6 - contentOffsetY, GRID_W + 12, GRID_H + 12, {100, 120, 200, 40});
// Accent border (brighter, thin)
drawRectWithOffset(gridX - 3 - contentOffsetX, gridY - 3 - contentOffsetY, GRID_W + 6, GRID_H + 6, {100, 120, 200, 220});
drawRectWithOffset(gridX - 1 - contentOffsetX, gridY - 1 - contentOffsetY, GRID_W + 2, GRID_H + 2, {60, 80, 160, 200});
// Do NOT fill the interior of the grid so the background shows through.
// (Intentionally leave the playfield interior transparent.)
// Draw panel backgrounds
SDL_SetRenderDrawColor(renderer, 10, 15, 25, 160);
@ -211,7 +220,7 @@ void GameRenderer::renderPlayingState(
SDL_FRect rbg{scoreX - 16, gridY - 16, statsW + 32, GRID_H + 32};
SDL_RenderFillRect(renderer, &rbg);
// Draw grid lines
// Draw grid lines (solid so grid remains legible over background)
SDL_SetRenderDrawColor(renderer, 40, 45, 60, 255);
for (int x = 1; x < Game::COLS; ++x) {
float lineX = gridX + x * finalBlockSize;

View File

@ -7,6 +7,7 @@
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <limits>
#include <random>
#include <vector>
#include "../../core/Settings.h"
@ -147,6 +148,7 @@ void GameRenderer::renderPlayingState(
FontAtlas* pixelFont,
LineEffect* lineEffect,
SDL_Texture* blocksTex,
SDL_Texture* scorePanelTex,
float logicalW,
float logicalH,
float logicalScale,
@ -212,7 +214,6 @@ void GameRenderer::renderPlayingState(
const float statsX = layoutStartX + contentOffsetX;
const float gridX = layoutStartX + PANEL_WIDTH + PANEL_SPACING + contentOffsetX;
const float scoreX = layoutStartX + PANEL_WIDTH + PANEL_SPACING + GRID_W + PANEL_SPACING + contentOffsetX;
const float gridY = contentStartY + NEXT_PIECE_HEIGHT + contentOffsetY;
const float statsY = gridY;
@ -241,9 +242,6 @@ void GameRenderer::renderPlayingState(
SDL_FRect lbg{statsX - 16, gridY - 10, statsW + 32, GRID_H + 20};
SDL_RenderFillRect(renderer, &lbg);
SDL_FRect rbg{scoreX - 16, gridY - 16, statsW + 32, GRID_H + 32};
SDL_RenderFillRect(renderer, &rbg);
// Draw grid lines
SDL_SetRenderDrawColor(renderer, 40, 45, 60, 255);
for (int x = 1; x < Game::COLS; ++x) {
@ -650,22 +648,27 @@ void GameRenderer::renderPlayingState(
const float contentPad = 36.0f;
float scoreContentH = (contentBottomOffset - contentTopOffset) + contentPad;
float baseY = gridY + (GRID_H - scoreContentH) * 0.5f;
pixelFont->draw(renderer, scoreX, baseY + 0, "SCORE", 1.0f, {255, 220, 0, 255});
const float statsPanelGap = 12.0f;
const float statsPanelLeft = gridX + GRID_W + statsPanelGap;
const float statsPanelPadLeft = 40.0f;
const float statsPanelPadRight = 34.0f;
const float statsPanelPadY = 28.0f;
const float statsTextX = statsPanelLeft + statsPanelPadLeft;
const SDL_Color labelColor{255, 220, 0, 255};
const SDL_Color valueColor{255, 255, 255, 255};
const SDL_Color nextColor{80, 255, 120, 255};
char scoreStr[32];
snprintf(scoreStr, sizeof(scoreStr), "%d", game->score());
pixelFont->draw(renderer, scoreX, baseY + 25, scoreStr, 0.9f, {255, 255, 255, 255});
pixelFont->draw(renderer, scoreX, baseY + 70, "LINES", 1.0f, {255, 220, 0, 255});
char linesStr[16];
snprintf(linesStr, sizeof(linesStr), "%03d", game->lines());
pixelFont->draw(renderer, scoreX, baseY + 95, linesStr, 0.9f, {255, 255, 255, 255});
pixelFont->draw(renderer, scoreX, baseY + 140, "LEVEL", 1.0f, {255, 220, 0, 255});
char levelStr[16];
snprintf(levelStr, sizeof(levelStr), "%02d", game->level());
pixelFont->draw(renderer, scoreX, baseY + 165, levelStr, 0.9f, {255, 255, 255, 255});
// Next level progress
int startLv = game->startLevelBase();
int firstThreshold = (startLv + 1) * 10;
@ -678,46 +681,98 @@ void GameRenderer::renderPlayingState(
nextThreshold = firstThreshold + ((blocksPast / 10) + 1) * 10;
}
int linesForNext = std::max(0, nextThreshold - linesDone);
pixelFont->draw(renderer, scoreX, baseY + 200, "NEXT LVL", 1.0f, {255, 220, 0, 255});
char nextStr[32];
snprintf(nextStr, sizeof(nextStr), "%d LINES", linesForNext);
pixelFont->draw(renderer, scoreX, baseY + 225, nextStr, 0.9f, {80, 255, 120, 255});
// Time display
pixelFont->draw(renderer, scoreX, baseY + 265, "TIME", 1.0f, {255, 220, 0, 255});
int totalSecs = static_cast<int>(game->elapsed());
int mins = totalSecs / 60;
int secs = totalSecs % 60;
char timeStr[16];
snprintf(timeStr, sizeof(timeStr), "%02d:%02d", mins, secs);
pixelFont->draw(renderer, scoreX, baseY + 290, timeStr, 0.9f, {255, 255, 255, 255});
// Debug: Gravity timing info
if (Settings::instance().isDebugEnabled()) {
pixelFont->draw(renderer, scoreX, baseY + 330, "GRAVITY", 0.8f, {150, 150, 150, 255});
const bool debugEnabled = Settings::instance().isDebugEnabled();
char gravityStr[32] = "";
char dropStr[32] = "";
char gravityHud[64] = "";
SDL_Color dropColor{100, 255, 100, 255};
if (debugEnabled) {
double gravityMs = game->getGravityMs();
double fallAcc = game->getFallAccumulator();
// Calculate effective gravity (accounting for soft drop)
bool isSoftDrop = game->isSoftDropping();
double effectiveGravityMs = isSoftDrop ? (gravityMs / 2.0) : gravityMs;
double timeUntilDrop = std::max(0.0, effectiveGravityMs - fallAcc);
char gravityStr[32];
snprintf(gravityStr, sizeof(gravityStr), "%.0f ms%s", gravityMs, isSoftDrop ? " (SD)" : "");
pixelFont->draw(renderer, scoreX, baseY + 350, gravityStr, 0.7f, {180, 180, 180, 255});
char dropStr[32];
snprintf(dropStr, sizeof(dropStr), "Drop: %.0f", timeUntilDrop);
SDL_Color dropColor = isSoftDrop ? SDL_Color{255, 200, 100, 255} : SDL_Color{100, 255, 100, 255};
pixelFont->draw(renderer, scoreX, baseY + 370, dropStr, 0.7f, dropColor);
// Gravity HUD (Top)
char gms[64];
double gms_val = game->getGravityMs();
double gfps = gms_val > 0.0 ? (1000.0 / gms_val) : 0.0;
snprintf(gms, sizeof(gms), "GRAV: %.0f ms (%.2f fps)", gms_val, gfps);
pixelFont->draw(renderer, logicalW - 260, 10, gms, 0.9f, {200, 200, 220, 255});
dropColor = isSoftDrop ? SDL_Color{255, 200, 100, 255} : SDL_Color{100, 255, 100, 255};
double gfps = gravityMs > 0.0 ? (1000.0 / gravityMs) : 0.0;
snprintf(gravityHud, sizeof(gravityHud), "GRAV: %.0f ms (%.2f fps)", gravityMs, gfps);
}
struct StatLine {
const char* text;
float offsetY;
float scale;
SDL_Color color;
};
std::vector<StatLine> statLines;
statLines.reserve(debugEnabled ? 13 : 10);
statLines.push_back({"SCORE", 0.0f, 1.0f, labelColor});
statLines.push_back({scoreStr, 25.0f, 0.9f, valueColor});
statLines.push_back({"LINES", 70.0f, 1.0f, labelColor});
statLines.push_back({linesStr, 95.0f, 0.9f, valueColor});
statLines.push_back({"LEVEL", 140.0f, 1.0f, labelColor});
statLines.push_back({levelStr, 165.0f, 0.9f, valueColor});
statLines.push_back({"NEXT LVL", 200.0f, 1.0f, labelColor});
statLines.push_back({nextStr, 225.0f, 0.9f, nextColor});
statLines.push_back({"TIME", 265.0f, 1.0f, labelColor});
statLines.push_back({timeStr, 290.0f, 0.9f, valueColor});
if (debugEnabled) {
SDL_Color debugLabelColor{150, 150, 150, 255};
SDL_Color debugValueColor{180, 180, 180, 255};
statLines.push_back({"GRAVITY", 330.0f, 0.8f, debugLabelColor});
statLines.push_back({gravityStr, 350.0f, 0.7f, debugValueColor});
statLines.push_back({dropStr, 370.0f, 0.7f, dropColor});
}
if (!statLines.empty()) {
float statsContentTop = std::numeric_limits<float>::max();
float statsContentBottom = std::numeric_limits<float>::lowest();
float statsContentMaxWidth = 0.0f;
for (const auto& line : statLines) {
int textW = 0;
int textH = 0;
pixelFont->measure(line.text, line.scale, textW, textH);
float y = baseY + line.offsetY;
statsContentTop = std::min(statsContentTop, y);
statsContentBottom = std::max(statsContentBottom, y + textH);
statsContentMaxWidth = std::max(statsContentMaxWidth, static_cast<float>(textW));
}
float statsPanelWidth = statsPanelPadLeft + statsContentMaxWidth + statsPanelPadRight;
float statsPanelHeight = (statsContentBottom - statsContentTop) + statsPanelPadY * 2.0f;
float statsPanelTop = statsContentTop - statsPanelPadY;
SDL_FRect statsBg{statsPanelLeft, statsPanelTop, statsPanelWidth, statsPanelHeight};
if (scorePanelTex) {
SDL_RenderTexture(renderer, scorePanelTex, nullptr, &statsBg);
} else {
SDL_SetRenderDrawColor(renderer, 12, 18, 32, 205);
SDL_RenderFillRect(renderer, &statsBg);
}
}
for (const auto& line : statLines) {
pixelFont->draw(renderer, statsTextX, baseY + line.offsetY, line.text, line.scale, line.color);
}
if (debugEnabled) {
pixelFont->draw(renderer, logicalW - 260, 10, gravityHud, 0.9f, {200, 200, 220, 255});
}
// Hold piece (if implemented)

View File

@ -21,6 +21,7 @@ public:
FontAtlas* pixelFont,
LineEffect* lineEffect,
SDL_Texture* blocksTex,
SDL_Texture* scorePanelTex,
float logicalW,
float logicalH,
float logicalScale,

View File

@ -673,6 +673,11 @@ int main(int, char **)
SDL_SetRenderTarget(renderer, nullptr);
}
SDL_Texture* scorePanelTex = loadTextureFromImage(renderer, "assets/images/panel_score.png");
if (scorePanelTex) {
SDL_SetTextureBlendMode(scorePanelTex, SDL_BLENDMODE_BLEND);
}
Game game(startLevelSelection);
// Apply global gravity speed multiplier from config
@ -819,6 +824,7 @@ int main(int, char **)
ctx.logoSmallH = logoSmallH;
ctx.backgroundTex = backgroundTex;
ctx.blocksTex = blocksTex;
ctx.scorePanelTex = scorePanelTex;
ctx.mainScreenTex = mainScreenTex;
ctx.mainScreenW = mainScreenW;
ctx.mainScreenH = mainScreenH;
@ -1717,6 +1723,7 @@ int main(int, char **)
&pixelFont,
&lineEffect,
blocksTex,
scorePanelTex,
(float)LOGICAL_W,
(float)LOGICAL_H,
logicalScale,
@ -1956,6 +1963,8 @@ int main(int, char **)
resetLevelBackgrounds(levelBackgrounds);
if (blocksTex)
SDL_DestroyTexture(blocksTex);
if (scorePanelTex)
SDL_DestroyTexture(scorePanelTex);
if (logoSmallTex)
SDL_DestroyTexture(logoSmallTex);

View File

@ -189,6 +189,7 @@ void PlayingState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect l
ctx.pixelFont,
ctx.lineEffect,
ctx.blocksTex,
ctx.scorePanelTex,
1200.0f, // LOGICAL_W
1000.0f, // LOGICAL_H
logicalScale,
@ -269,6 +270,7 @@ void PlayingState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect l
ctx.pixelFont,
ctx.lineEffect,
ctx.blocksTex,
ctx.scorePanelTex,
1200.0f,
1000.0f,
logicalScale,

View File

@ -40,6 +40,7 @@ struct StateContext {
// backgroundTex is set once in `main.cpp` and passed to states via this context.
// Prefer reading this field instead of relying on any `extern SDL_Texture*` globals.
SDL_Texture* blocksTex = nullptr;
SDL_Texture* scorePanelTex = nullptr;
SDL_Texture* mainScreenTex = nullptr;
int mainScreenW = 0;
int mainScreenH = 0;