Added challenge mode

This commit is contained in:
2025-12-20 13:08:16 +01:00
parent fd29ae271e
commit 34447f0245
15 changed files with 535 additions and 1227 deletions

View File

@ -22,11 +22,12 @@ BottomMenu buildBottomMenu(const MenuLayoutParams& params, int startLevel) {
std::snprintf(levelBtnText, sizeof(levelBtnText), "LEVEL %d", startLevel);
menu.buttons[0] = Button{ BottomMenuItem::Play, rects[0], "PLAY", false };
menu.buttons[1] = Button{ BottomMenuItem::Level, rects[1], levelBtnText, true };
menu.buttons[2] = Button{ BottomMenuItem::Options, rects[2], "OPTIONS", true };
menu.buttons[3] = Button{ BottomMenuItem::Help, rects[3], "HELP", true };
menu.buttons[4] = Button{ BottomMenuItem::About, rects[4], "ABOUT", true };
menu.buttons[5] = Button{ BottomMenuItem::Exit, rects[5], "EXIT", true };
menu.buttons[1] = Button{ BottomMenuItem::Challenge, rects[1], "CHALLENGE", false };
menu.buttons[2] = Button{ BottomMenuItem::Level, rects[2], levelBtnText, true };
menu.buttons[3] = Button{ BottomMenuItem::Options, rects[3], "OPTIONS", true };
menu.buttons[4] = Button{ BottomMenuItem::Help, rects[4], "HELP", true };
menu.buttons[5] = Button{ BottomMenuItem::About, rects[5], "ABOUT", true };
menu.buttons[6] = Button{ BottomMenuItem::Exit, rects[6], "EXIT", true };
return menu;
}
@ -60,8 +61,15 @@ void renderBottomMenu(SDL_Renderer* renderer,
const double aMul = std::clamp(baseMul + (playIsActive ? flashMul : 0.0), 0.0, 1.0);
if (!b.textOnly) {
const bool isPlay = (i == 0);
const bool isChallenge = (i == 1);
SDL_Color bgCol{ 18, 22, 28, static_cast<Uint8>(std::round(180.0 * aMul)) };
SDL_Color bdCol{ 255, 200, 70, static_cast<Uint8>(std::round(220.0 * aMul)) };
if (isChallenge) {
// Give Challenge a teal accent to distinguish from Play
bgCol = SDL_Color{ 18, 36, 36, static_cast<Uint8>(std::round(190.0 * aMul)) };
bdCol = SDL_Color{ 120, 255, 220, static_cast<Uint8>(std::round(230.0 * aMul)) };
}
UIRenderer::drawButton(renderer, font, cx, cy, r.w, r.h,
b.label, isHovered, isSelected,
bgCol, bdCol, false, nullptr);
@ -74,14 +82,14 @@ void renderBottomMenu(SDL_Renderer* renderer,
}
}
// '+' separators between the bottom HUD buttons (indices 1..last)
// '+' separators between the bottom HUD buttons (indices 2..last)
{
SDL_BlendMode prevBlend = SDL_BLENDMODE_NONE;
SDL_GetRenderDrawBlendMode(renderer, &prevBlend);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer, 120, 220, 255, static_cast<Uint8>(std::round(180.0 * baseMul)));
const int firstSmall = 1;
const int firstSmall = 2;
const int lastSmall = MENU_BTN_COUNT - 1;
float y = menu.buttons[firstSmall].rect.y + menu.buttons[firstSmall].rect.h * 0.5f;
for (int i = firstSmall; i < lastSmall; ++i) {

View File

@ -15,11 +15,12 @@ namespace ui {
enum class BottomMenuItem : int {
Play = 0,
Level = 1,
Options = 2,
Help = 3,
About = 4,
Exit = 5,
Challenge = 1,
Level = 2,
Options = 3,
Help = 4,
About = 5,
Exit = 6,
};
struct Button {

View File

@ -12,28 +12,32 @@ std::array<SDL_FRect, MENU_BTN_COUNT> computeMenuButtonRects(const MenuLayoutPar
float contentOffsetY = (p.winH - LOGICAL_H * p.logicalScale) * 0.5f / p.logicalScale;
// Cockpit HUD layout (matches main_screen art):
// - A big centered PLAY button
// - A second row of 5 smaller buttons: LEVEL / OPTIONS / HELP / ABOUT / EXIT
// - Top row: PLAY and CHALLENGE (big buttons)
// - Second row: LEVEL / OPTIONS / HELP / ABOUT / EXIT (smaller buttons)
const float marginX = std::max(24.0f, LOGICAL_W * 0.03f);
const float marginBottom = std::max(26.0f, LOGICAL_H * 0.03f);
const float availableW = std::max(120.0f, LOGICAL_W - marginX * 2.0f);
float playW = std::min(230.0f, availableW * 0.27f);
float playH = 35.0f;
float smallW = std::min(220.0f, availableW * 0.23f);
float playW = std::min(220.0f, availableW * 0.25f);
float playH = 36.0f;
float bigGap = 28.0f;
float smallW = std::min(210.0f, availableW * 0.22f);
float smallH = 34.0f;
float smallSpacing = 28.0f;
float smallSpacing = 26.0f;
// Scale down for narrow windows so nothing goes offscreen.
const int smallCount = MENU_BTN_COUNT - 1;
const int smallCount = MENU_BTN_COUNT - 2;
float smallTotal = smallW * static_cast<float>(smallCount) + smallSpacing * static_cast<float>(smallCount - 1);
if (smallTotal > availableW) {
float s = availableW / smallTotal;
float topRowTotal = playW * 2.0f + bigGap;
if (smallTotal > availableW || topRowTotal > availableW) {
float s = availableW / std::max(std::max(smallTotal, topRowTotal), 1.0f);
smallW *= s;
smallH *= s;
smallSpacing *= s;
playW *= s;
playH = std::max(26.0f, playH * std::max(0.75f, s));
bigGap *= s;
playW = std::min(playW, availableW);
playH *= std::max(0.75f, s);
}
float centerX = LOGICAL_W * 0.5f + contentOffsetX;
@ -44,7 +48,11 @@ std::array<SDL_FRect, MENU_BTN_COUNT> computeMenuButtonRects(const MenuLayoutPar
float playCY = smallCY - smallH * 0.5f - rowGap - playH * 0.5f;
std::array<SDL_FRect, MENU_BTN_COUNT> rects{};
rects[0] = SDL_FRect{ centerX - playW * 0.5f, playCY - playH * 0.5f, playW, playH };
// Top row big buttons
float playLeft = centerX - (playW + bigGap * 0.5f);
float challengeLeft = centerX + bigGap * 0.5f;
rects[0] = SDL_FRect{ playLeft, playCY - playH * 0.5f, playW, playH };
rects[1] = SDL_FRect{ challengeLeft, playCY - playH * 0.5f, playW, playH };
float rowW = smallW * static_cast<float>(smallCount) + smallSpacing * static_cast<float>(smallCount - 1);
float left = centerX - rowW * 0.5f;
@ -55,7 +63,7 @@ std::array<SDL_FRect, MENU_BTN_COUNT> computeMenuButtonRects(const MenuLayoutPar
for (int i = 0; i < smallCount; ++i) {
float x = left + i * (smallW + smallSpacing);
rects[i + 1] = SDL_FRect{ x, smallCY - smallH * 0.5f, smallW, smallH };
rects[i + 2] = SDL_FRect{ x, smallCY - smallH * 0.5f, smallW, smallH };
}
return rects;
}

View File

@ -1,6 +1,6 @@
#pragma once
static constexpr int MENU_BTN_COUNT = 6;
static constexpr int MENU_BTN_COUNT = 7;
static constexpr float MENU_SMALL_THRESHOLD = 700.0f;
static constexpr float MENU_BTN_WIDTH_LARGE = 300.0f;
static constexpr float MENU_BTN_WIDTH_SMALL_FACTOR = 0.4f; // multiplied by LOGICAL_W