gameplay score board
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
BIN
assets/images/panel_score.png
Normal file
|
After Width: | Height: | Size: 275 KiB |
@ -12,7 +12,7 @@ Sound=1
|
||||
SmoothScroll=1
|
||||
|
||||
[Player]
|
||||
Name=GREGOR
|
||||
Name=PLAYER
|
||||
|
||||
[Debug]
|
||||
Enabled=1
|
||||
|
||||
@ -1131,6 +1131,7 @@ void ApplicationManager::setupStateHandlers() {
|
||||
m_stateContext.pixelFont,
|
||||
m_stateContext.lineEffect,
|
||||
m_stateContext.blocksTex,
|
||||
m_stateContext.scorePanelTex,
|
||||
LOGICAL_W,
|
||||
LOGICAL_H,
|
||||
logicalScale,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -21,6 +21,7 @@ public:
|
||||
FontAtlas* pixelFont,
|
||||
LineEffect* lineEffect,
|
||||
SDL_Texture* blocksTex,
|
||||
SDL_Texture* scorePanelTex,
|
||||
float logicalW,
|
||||
float logicalH,
|
||||
float logicalScale,
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||