fixed score display
This commit is contained in:
@ -55,6 +55,7 @@ void CoopGame::reset(int startLevel_) {
|
|||||||
gravityMs = gravityMsForLevel(_level);
|
gravityMs = gravityMsForLevel(_level);
|
||||||
gameOver = false;
|
gameOver = false;
|
||||||
pieceSequence = 0;
|
pieceSequence = 0;
|
||||||
|
elapsedMs = 0.0;
|
||||||
|
|
||||||
left = PlayerState{};
|
left = PlayerState{};
|
||||||
right = PlayerState{ PlayerSide::Right };
|
right = PlayerState{ PlayerSide::Right };
|
||||||
@ -67,6 +68,13 @@ void CoopGame::reset(int startLevel_) {
|
|||||||
ps.fallAcc = 0.0;
|
ps.fallAcc = 0.0;
|
||||||
ps.lockAcc = 0.0;
|
ps.lockAcc = 0.0;
|
||||||
ps.pieceSeq = 0;
|
ps.pieceSeq = 0;
|
||||||
|
ps.score = 0;
|
||||||
|
ps.lines = 0;
|
||||||
|
ps.level = startLevel_;
|
||||||
|
ps.tetrisesMade = 0;
|
||||||
|
ps.currentCombo = 0;
|
||||||
|
ps.maxCombo = 0;
|
||||||
|
ps.comboCount = 0;
|
||||||
ps.bag.clear();
|
ps.bag.clear();
|
||||||
ps.next.type = PIECE_COUNT;
|
ps.next.type = PIECE_COUNT;
|
||||||
refillBag(ps);
|
refillBag(ps);
|
||||||
@ -169,6 +177,7 @@ void CoopGame::hardDrop(PlayerSide side) {
|
|||||||
}
|
}
|
||||||
if (moved) {
|
if (moved) {
|
||||||
_score += dropped; // 1 point per cell, matches single-player hard drop
|
_score += dropped; // 1 point per cell, matches single-player hard drop
|
||||||
|
ps.score += dropped;
|
||||||
hardDropShakeTimerMs = HARD_DROP_SHAKE_DURATION_MS;
|
hardDropShakeTimerMs = HARD_DROP_SHAKE_DURATION_MS;
|
||||||
hardDropFxId++;
|
hardDropFxId++;
|
||||||
}
|
}
|
||||||
@ -198,6 +207,8 @@ void CoopGame::holdCurrent(PlayerSide side) {
|
|||||||
void CoopGame::tickGravity(double frameMs) {
|
void CoopGame::tickGravity(double frameMs) {
|
||||||
if (gameOver) return;
|
if (gameOver) return;
|
||||||
|
|
||||||
|
elapsedMs += frameMs;
|
||||||
|
|
||||||
auto stepPlayer = [&](PlayerState& ps) {
|
auto stepPlayer = [&](PlayerState& ps) {
|
||||||
if (ps.toppedOut) return;
|
if (ps.toppedOut) return;
|
||||||
double step = ps.softDropping ? std::max(5.0, gravityMs / 5.0) : gravityMs;
|
double step = ps.softDropping ? std::max(5.0, gravityMs / 5.0) : gravityMs;
|
||||||
@ -214,6 +225,7 @@ void CoopGame::tickGravity(double frameMs) {
|
|||||||
// Award soft drop points when actively holding down
|
// Award soft drop points when actively holding down
|
||||||
if (ps.softDropping) {
|
if (ps.softDropping) {
|
||||||
_score += 1;
|
_score += 1;
|
||||||
|
ps.score += 1;
|
||||||
}
|
}
|
||||||
ps.lockAcc = 0.0;
|
ps.lockAcc = 0.0;
|
||||||
}
|
}
|
||||||
@ -349,13 +361,14 @@ void CoopGame::lock(PlayerState& ps) {
|
|||||||
findCompletedLines();
|
findCompletedLines();
|
||||||
if (!completedLines.empty()) {
|
if (!completedLines.empty()) {
|
||||||
int cleared = static_cast<int>(completedLines.size());
|
int cleared = static_cast<int>(completedLines.size());
|
||||||
applyLineClearRewards(cleared);
|
applyLineClearRewards(ps, cleared);
|
||||||
// Notify audio layer if present (matches single-player behavior)
|
// Notify audio layer if present (matches single-player behavior)
|
||||||
if (soundCallback) soundCallback(cleared);
|
if (soundCallback) soundCallback(cleared);
|
||||||
// Leave `completedLines` populated; `clearCompletedLines()` will be
|
// Leave `completedLines` populated; `clearCompletedLines()` will be
|
||||||
// invoked by the state when the LineEffect finishes.
|
// invoked by the state when the LineEffect finishes.
|
||||||
} else {
|
} else {
|
||||||
_currentCombo = 0;
|
_currentCombo = 0;
|
||||||
|
ps.currentCombo = 0;
|
||||||
}
|
}
|
||||||
spawn(ps);
|
spawn(ps);
|
||||||
}
|
}
|
||||||
@ -379,7 +392,7 @@ void CoopGame::findCompletedLines() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoopGame::applyLineClearRewards(int cleared) {
|
void CoopGame::applyLineClearRewards(PlayerState& creditPlayer, int cleared) {
|
||||||
if (cleared <= 0) return;
|
if (cleared <= 0) return;
|
||||||
|
|
||||||
// Base NES scoring scaled by shared level (level 0 => 1x multiplier)
|
// Base NES scoring scaled by shared level (level 0 => 1x multiplier)
|
||||||
@ -392,8 +405,10 @@ void CoopGame::applyLineClearRewards(int cleared) {
|
|||||||
default: base = 0; break;
|
default: base = 0; break;
|
||||||
}
|
}
|
||||||
_score += base * (_level + 1);
|
_score += base * (_level + 1);
|
||||||
|
creditPlayer.score += base * (creditPlayer.level + 1);
|
||||||
|
|
||||||
_lines += cleared;
|
_lines += cleared;
|
||||||
|
creditPlayer.lines += cleared;
|
||||||
|
|
||||||
_currentCombo += 1;
|
_currentCombo += 1;
|
||||||
if (_currentCombo > _maxCombo) _maxCombo = _currentCombo;
|
if (_currentCombo > _maxCombo) _maxCombo = _currentCombo;
|
||||||
@ -404,6 +419,15 @@ void CoopGame::applyLineClearRewards(int cleared) {
|
|||||||
_tetrisesMade += 1;
|
_tetrisesMade += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
creditPlayer.currentCombo += 1;
|
||||||
|
if (creditPlayer.currentCombo > creditPlayer.maxCombo) creditPlayer.maxCombo = creditPlayer.currentCombo;
|
||||||
|
if (cleared > 1) {
|
||||||
|
creditPlayer.comboCount += 1;
|
||||||
|
}
|
||||||
|
if (cleared == 4) {
|
||||||
|
creditPlayer.tetrisesMade += 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Level progression mirrors single-player: threshold after (startLevel+1)*10 then every 10 lines
|
// Level progression mirrors single-player: threshold after (startLevel+1)*10 then every 10 lines
|
||||||
int targetLevel = startLevel;
|
int targetLevel = startLevel;
|
||||||
int firstThreshold = (startLevel + 1) * 10;
|
int firstThreshold = (startLevel + 1) * 10;
|
||||||
@ -414,6 +438,17 @@ void CoopGame::applyLineClearRewards(int cleared) {
|
|||||||
_level = targetLevel;
|
_level = targetLevel;
|
||||||
gravityMs = gravityMsForLevel(_level);
|
gravityMs = gravityMsForLevel(_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Per-player level progression mirrors the shared rules but is driven by
|
||||||
|
// that player's credited line clears.
|
||||||
|
{
|
||||||
|
int pTargetLevel = startLevel;
|
||||||
|
int pFirstThreshold = (startLevel + 1) * 10;
|
||||||
|
if (creditPlayer.lines >= pFirstThreshold) {
|
||||||
|
pTargetLevel = startLevel + 1 + (creditPlayer.lines - pFirstThreshold) / 10;
|
||||||
|
}
|
||||||
|
creditPlayer.level = std::max(creditPlayer.level, pTargetLevel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoopGame::clearLinesInternal() {
|
void CoopGame::clearLinesInternal() {
|
||||||
|
|||||||
@ -44,6 +44,13 @@ public:
|
|||||||
bool toppedOut{false};
|
bool toppedOut{false};
|
||||||
double fallAcc{0.0};
|
double fallAcc{0.0};
|
||||||
double lockAcc{0.0};
|
double lockAcc{0.0};
|
||||||
|
int score{0};
|
||||||
|
int lines{0};
|
||||||
|
int level{0};
|
||||||
|
int tetrisesMade{0};
|
||||||
|
int currentCombo{0};
|
||||||
|
int maxCombo{0};
|
||||||
|
int comboCount{0};
|
||||||
std::vector<PieceType> bag{}; // 7-bag queue
|
std::vector<PieceType> bag{}; // 7-bag queue
|
||||||
std::mt19937 rng{ std::random_device{}() };
|
std::mt19937 rng{ std::random_device{}() };
|
||||||
};
|
};
|
||||||
@ -71,11 +78,17 @@ public:
|
|||||||
bool canHold(PlayerSide s) const { return player(s).canHold; }
|
bool canHold(PlayerSide s) const { return player(s).canHold; }
|
||||||
bool isGameOver() const { return gameOver; }
|
bool isGameOver() const { return gameOver; }
|
||||||
int score() const { return _score; }
|
int score() const { return _score; }
|
||||||
|
int score(PlayerSide s) const { return player(s).score; }
|
||||||
int lines() const { return _lines; }
|
int lines() const { return _lines; }
|
||||||
|
int lines(PlayerSide s) const { return player(s).lines; }
|
||||||
int level() const { return _level; }
|
int level() const { return _level; }
|
||||||
|
int level(PlayerSide s) const { return player(s).level; }
|
||||||
int comboCount() const { return _comboCount; }
|
int comboCount() const { return _comboCount; }
|
||||||
int maxCombo() const { return _maxCombo; }
|
int maxCombo() const { return _maxCombo; }
|
||||||
int tetrisesMade() const { return _tetrisesMade; }
|
int tetrisesMade() const { return _tetrisesMade; }
|
||||||
|
int elapsed() const { return static_cast<int>(elapsedMs / 1000.0); }
|
||||||
|
int elapsed(PlayerSide) const { return elapsed(); }
|
||||||
|
int startLevelBase() const { return startLevel; }
|
||||||
double getGravityMs() const { return gravityMs; }
|
double getGravityMs() const { return gravityMs; }
|
||||||
double getFallAccumulator(PlayerSide s) const { return player(s).fallAcc; }
|
double getFallAccumulator(PlayerSide s) const { return player(s).fallAcc; }
|
||||||
bool isSoftDropping(PlayerSide s) const { return player(s).softDropping; }
|
bool isSoftDropping(PlayerSide s) const { return player(s).softDropping; }
|
||||||
@ -113,6 +126,8 @@ private:
|
|||||||
double gravityGlobalMultiplier{1.0};
|
double gravityGlobalMultiplier{1.0};
|
||||||
bool gameOver{false};
|
bool gameOver{false};
|
||||||
|
|
||||||
|
double elapsedMs{0.0};
|
||||||
|
|
||||||
std::vector<int> completedLines;
|
std::vector<int> completedLines;
|
||||||
|
|
||||||
// Impact FX
|
// Impact FX
|
||||||
@ -136,7 +151,7 @@ private:
|
|||||||
void findCompletedLines();
|
void findCompletedLines();
|
||||||
void clearLinesInternal();
|
void clearLinesInternal();
|
||||||
void updateRowStates();
|
void updateRowStates();
|
||||||
void applyLineClearRewards(int cleared);
|
void applyLineClearRewards(PlayerState& creditPlayer, int cleared);
|
||||||
double gravityMsForLevel(int level) const;
|
double gravityMsForLevel(int level) const;
|
||||||
int columnMin(PlayerSide s) const { return s == PlayerSide::Left ? 0 : 10; }
|
int columnMin(PlayerSide s) const { return s == PlayerSide::Left ? 0 : 10; }
|
||||||
int columnMax(PlayerSide s) const { return s == PlayerSide::Left ? 9 : 19; }
|
int columnMax(PlayerSide s) const { return s == PlayerSide::Left ? 9 : 19; }
|
||||||
|
|||||||
@ -1369,6 +1369,7 @@ void GameRenderer::renderPlayingState(
|
|||||||
double sp_gravityMs = game->getGravityMs();
|
double sp_gravityMs = game->getGravityMs();
|
||||||
double sp_fallAcc = game->getFallAccumulator();
|
double sp_fallAcc = game->getFallAccumulator();
|
||||||
int sp_soft = game->isSoftDropping() ? 1 : 0;
|
int sp_soft = game->isSoftDropping() ? 1 : 0;
|
||||||
|
/*
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "SP OFFSETS: seq=%llu visX=%.3f targX=%.3f offX=%.2f offY=%.2f gravMs=%.2f fallAcc=%.2f soft=%d",
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "SP OFFSETS: seq=%llu visX=%.3f targX=%.3f offX=%.2f offY=%.2f gravMs=%.2f fallAcc=%.2f soft=%d",
|
||||||
(unsigned long long)s_activePieceSmooth.sequence,
|
(unsigned long long)s_activePieceSmooth.sequence,
|
||||||
s_activePieceSmooth.visualX,
|
s_activePieceSmooth.visualX,
|
||||||
@ -1379,6 +1380,7 @@ void GameRenderer::renderPlayingState(
|
|||||||
sp_fallAcc,
|
sp_fallAcc,
|
||||||
sp_soft
|
sp_soft
|
||||||
);
|
);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw ghost piece (where current piece will land)
|
// Draw ghost piece (where current piece will land)
|
||||||
@ -1910,19 +1912,13 @@ void GameRenderer::renderCoopPlayingState(
|
|||||||
const float gridX = layoutStartX + PANEL_WIDTH + PANEL_SPACING + contentOffsetX;
|
const float gridX = layoutStartX + PANEL_WIDTH + PANEL_SPACING + contentOffsetX;
|
||||||
const float gridY = contentStartY + NEXT_PANEL_HEIGHT + contentOffsetY;
|
const float gridY = contentStartY + NEXT_PANEL_HEIGHT + contentOffsetY;
|
||||||
|
|
||||||
|
const float rightPanelX = gridX + GRID_W + PANEL_SPACING;
|
||||||
|
|
||||||
const float statsY = gridY;
|
const float statsY = gridY;
|
||||||
const float statsW = PANEL_WIDTH;
|
const float statsW = PANEL_WIDTH;
|
||||||
const float statsH = GRID_H;
|
const float statsH = GRID_H;
|
||||||
|
|
||||||
// Shared score panel (reuse existing art)
|
// (Score panels are drawn per-player below using scorePanelTex and classic sizing.)
|
||||||
SDL_FRect scorePanelBg{ statsX - 20.0f, gridY - 26.0f, statsW + 40.0f, GRID_H + 52.0f };
|
|
||||||
if (statisticsPanelTex) {
|
|
||||||
SDL_RenderTexture(renderer, statisticsPanelTex, nullptr, &scorePanelBg);
|
|
||||||
} else if (scorePanelTex) {
|
|
||||||
SDL_RenderTexture(renderer, scorePanelTex, nullptr, &scorePanelBg);
|
|
||||||
} else {
|
|
||||||
drawRectWithOffset(scorePanelBg.x - contentOffsetX, scorePanelBg.y - contentOffsetY, scorePanelBg.w, scorePanelBg.h, SDL_Color{12,18,32,205});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle line clearing effects (defer to LineEffect like single-player)
|
// Handle line clearing effects (defer to LineEffect like single-player)
|
||||||
if (game->hasCompletedLines() && lineEffect && !lineEffect->isActive()) {
|
if (game->hasCompletedLines() && lineEffect && !lineEffect->isActive()) {
|
||||||
@ -2357,7 +2353,8 @@ void GameRenderer::renderCoopPlayingState(
|
|||||||
double gMsDbg = game->getGravityMs();
|
double gMsDbg = game->getGravityMs();
|
||||||
double accDbg = game->getFallAccumulator(side);
|
double accDbg = game->getFallAccumulator(side);
|
||||||
int softDbg = game->isSoftDropping(side) ? 1 : 0;
|
int softDbg = game->isSoftDropping(side) ? 1 : 0;
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "COOP %s OFFSETS: seq=%llu visX=%.3f targX=%.3f offX=%.2f offY=%.2f gravMs=%.2f fallAcc=%.2f soft=%d",
|
/*
|
||||||
|
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "COOP %s OFFSETS: seq=%llu visX=%.3f targX=%.3f offX=%.2f offY=%.2f gravMs=%.2f fallAcc=%.2f soft=%d",
|
||||||
(side == CoopGame::PlayerSide::Left) ? "L" : "R",
|
(side == CoopGame::PlayerSide::Left) ? "L" : "R",
|
||||||
(unsigned long long)ss.seq,
|
(unsigned long long)ss.seq,
|
||||||
ss.visualX,
|
ss.visualX,
|
||||||
@ -2368,6 +2365,7 @@ void GameRenderer::renderCoopPlayingState(
|
|||||||
accDbg,
|
accDbg,
|
||||||
softDbg
|
softDbg
|
||||||
);
|
);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
return std::pair<float, float>{ offsetX, offsetY };
|
return std::pair<float, float>{ offsetX, offsetY };
|
||||||
};
|
};
|
||||||
@ -2517,10 +2515,120 @@ void GameRenderer::renderCoopPlayingState(
|
|||||||
drawNextPanel(nextLeftX, nextY, game->next(CoopGame::PlayerSide::Left));
|
drawNextPanel(nextLeftX, nextY, game->next(CoopGame::PlayerSide::Left));
|
||||||
drawNextPanel(nextRightX, nextY, game->next(CoopGame::PlayerSide::Right));
|
drawNextPanel(nextRightX, nextY, game->next(CoopGame::PlayerSide::Right));
|
||||||
|
|
||||||
// Simple shared score text
|
// Per-player scoreboards (left and right)
|
||||||
char buf[128];
|
auto drawPlayerScoreboard = [&](CoopGame::PlayerSide side, float columnLeftX, float columnRightX, const char* title) {
|
||||||
std::snprintf(buf, sizeof(buf), "SCORE %d LINES %d LEVEL %d", game->score(), game->lines(), game->level());
|
const SDL_Color labelColor{255, 220, 0, 255};
|
||||||
pixelFont->draw(renderer, gridX + GRID_W * 0.5f - 140.0f, gridY + GRID_H + 24.0f, buf, 1.2f, SDL_Color{220, 230, 255, 255});
|
const SDL_Color valueColor{255, 255, 255, 255};
|
||||||
|
const SDL_Color nextColor{80, 255, 120, 255};
|
||||||
|
|
||||||
|
// Match classic vertical placement feel
|
||||||
|
const float contentTopOffset = 0.0f;
|
||||||
|
const float contentBottomOffset = 290.0f;
|
||||||
|
const float contentPad = 36.0f;
|
||||||
|
float scoreContentH = (contentBottomOffset - contentTopOffset) + contentPad;
|
||||||
|
float baseY = gridY + (GRID_H - scoreContentH) * 0.5f;
|
||||||
|
|
||||||
|
const float statsPanelPadLeft = 40.0f;
|
||||||
|
const float statsPanelPadRight = 34.0f;
|
||||||
|
const float statsPanelPadY = 28.0f;
|
||||||
|
|
||||||
|
const float textX = columnLeftX + statsPanelPadLeft;
|
||||||
|
|
||||||
|
char scoreStr[32];
|
||||||
|
std::snprintf(scoreStr, sizeof(scoreStr), "%d", game->score(side));
|
||||||
|
|
||||||
|
char linesStr[16];
|
||||||
|
std::snprintf(linesStr, sizeof(linesStr), "%03d", game->lines(side));
|
||||||
|
|
||||||
|
char levelStr[16];
|
||||||
|
std::snprintf(levelStr, sizeof(levelStr), "%02d", game->level(side));
|
||||||
|
|
||||||
|
// Next level progression (per-player lines)
|
||||||
|
int startLv = game->startLevelBase();
|
||||||
|
int linesDone = game->lines(side);
|
||||||
|
int firstThreshold = (startLv + 1) * 10;
|
||||||
|
int nextThreshold = 0;
|
||||||
|
if (linesDone < firstThreshold) {
|
||||||
|
nextThreshold = firstThreshold;
|
||||||
|
} else {
|
||||||
|
int blocksPast = linesDone - firstThreshold;
|
||||||
|
nextThreshold = firstThreshold + ((blocksPast / 10) + 1) * 10;
|
||||||
|
}
|
||||||
|
int linesForNext = std::max(0, nextThreshold - linesDone);
|
||||||
|
char nextStr[32];
|
||||||
|
std::snprintf(nextStr, sizeof(nextStr), "%d LINES", linesForNext);
|
||||||
|
|
||||||
|
// Time display (shared session time)
|
||||||
|
int totalSecs = game->elapsed(side);
|
||||||
|
int mins = totalSecs / 60;
|
||||||
|
int secs = totalSecs % 60;
|
||||||
|
char timeStr[16];
|
||||||
|
std::snprintf(timeStr, sizeof(timeStr), "%02d:%02d", mins, secs);
|
||||||
|
|
||||||
|
struct StatLine {
|
||||||
|
const char* text;
|
||||||
|
float offsetY;
|
||||||
|
float scale;
|
||||||
|
SDL_Color color;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Keep offsets aligned with classic spacing
|
||||||
|
std::vector<StatLine> statLines;
|
||||||
|
statLines.reserve(12);
|
||||||
|
statLines.push_back({title, 0.0f, 0.95f, SDL_Color{200, 220, 235, 220}});
|
||||||
|
statLines.push_back({"SCORE", 30.0f, 1.0f, labelColor});
|
||||||
|
statLines.push_back({scoreStr, 55.0f, 0.9f, valueColor});
|
||||||
|
statLines.push_back({"LINES", 100.0f, 1.0f, labelColor});
|
||||||
|
statLines.push_back({linesStr, 125.0f, 0.9f, valueColor});
|
||||||
|
statLines.push_back({"LEVEL", 170.0f, 1.0f, labelColor});
|
||||||
|
statLines.push_back({levelStr, 195.0f, 0.9f, valueColor});
|
||||||
|
statLines.push_back({"NEXT LVL", 230.0f, 1.0f, labelColor});
|
||||||
|
statLines.push_back({nextStr, 255.0f, 0.9f, nextColor});
|
||||||
|
statLines.push_back({"TIME", 295.0f, 1.0f, labelColor});
|
||||||
|
statLines.push_back({timeStr, 320.0f, 0.9f, valueColor});
|
||||||
|
|
||||||
|
// Size the panel like classic: measure the text block and fit the background.
|
||||||
|
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 + static_cast<float>(textH));
|
||||||
|
statsContentMaxWidth = std::max(statsContentMaxWidth, static_cast<float>(textW));
|
||||||
|
}
|
||||||
|
|
||||||
|
float panelW = statsPanelPadLeft + statsContentMaxWidth + statsPanelPadRight;
|
||||||
|
float panelH = (statsContentBottom - statsContentTop) + statsPanelPadY * 2.0f;
|
||||||
|
float panelY = statsContentTop - statsPanelPadY;
|
||||||
|
// Left player is left-aligned in its column; right player is right-aligned.
|
||||||
|
float panelX = (side == CoopGame::PlayerSide::Right) ? (columnRightX - panelW) : columnLeftX;
|
||||||
|
SDL_FRect panelBg{ panelX, panelY, panelW, panelH };
|
||||||
|
if (scorePanelTex) {
|
||||||
|
SDL_RenderTexture(renderer, scorePanelTex, nullptr, &panelBg);
|
||||||
|
} else {
|
||||||
|
SDL_SetRenderDrawColor(renderer, 12, 18, 32, 205);
|
||||||
|
SDL_RenderFillRect(renderer, &panelBg);
|
||||||
|
}
|
||||||
|
|
||||||
|
float textDrawX = panelX + statsPanelPadLeft;
|
||||||
|
for (const auto& line : statLines) {
|
||||||
|
pixelFont->draw(renderer, textDrawX, baseY + line.offsetY, line.text, line.scale, line.color);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Nudge panels toward the window edges for tighter symmetry.
|
||||||
|
const float scorePanelEdgeNudge = 20.0f;
|
||||||
|
const float leftColumnLeftX = statsX - scorePanelEdgeNudge;
|
||||||
|
const float leftColumnRightX = leftColumnLeftX + statsW;
|
||||||
|
const float rightColumnLeftX = rightPanelX;
|
||||||
|
const float rightColumnRightX = rightColumnLeftX + statsW + scorePanelEdgeNudge;
|
||||||
|
|
||||||
|
drawPlayerScoreboard(CoopGame::PlayerSide::Left, leftColumnLeftX, leftColumnRightX, "PLAYER 1");
|
||||||
|
drawPlayerScoreboard(CoopGame::PlayerSide::Right, rightColumnLeftX, rightColumnRightX, "PLAYER 2");
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameRenderer::renderExitPopup(
|
void GameRenderer::renderExitPopup(
|
||||||
|
|||||||
Reference in New Issue
Block a user