new background image

This commit is contained in:
2025-12-18 07:20:20 +01:00
parent 0ab7121c5b
commit 989b98002c
11 changed files with 233 additions and 27 deletions

View File

@ -112,6 +112,11 @@ MenuState::MenuState(StateContext& ctx) : State(ctx) {}
void MenuState::showHelpPanel(bool show) {
if (show) {
if (!helpPanelVisible && !helpPanelAnimating) {
// Avoid overlapping panels
if (aboutPanelVisible && !aboutPanelAnimating) {
aboutPanelAnimating = true;
aboutDirection = -1;
}
helpPanelAnimating = true;
helpDirection = 1;
helpScroll = 0.0;
@ -124,6 +129,38 @@ void MenuState::showHelpPanel(bool show) {
}
}
void MenuState::showAboutPanel(bool show) {
if (show) {
if (!aboutPanelVisible && !aboutPanelAnimating) {
// Avoid overlapping panels
if (helpPanelVisible && !helpPanelAnimating) {
helpPanelAnimating = true;
helpDirection = -1;
}
if (optionsVisible && !optionsAnimating) {
optionsAnimating = true;
optionsDirection = -1;
}
if (levelPanelVisible && !levelPanelAnimating) {
levelPanelAnimating = true;
levelDirection = -1;
}
if (exitPanelVisible && !exitPanelAnimating) {
exitPanelAnimating = true;
exitDirection = -1;
if (ctx.showExitConfirmPopup) *ctx.showExitConfirmPopup = false;
}
aboutPanelAnimating = true;
aboutDirection = 1;
}
} else {
if (aboutPanelVisible && !aboutPanelAnimating) {
aboutPanelAnimating = true;
aboutDirection = -1;
}
}
}
void MenuState::onEnter() {
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "MenuState::onEnter called");
if (ctx.showExitConfirmPopup) {
@ -349,6 +386,26 @@ void MenuState::handleEvent(const SDL_Event& e) {
}
}
// If the inline about HUD is visible and not animating, capture navigation
if (aboutPanelVisible && !aboutPanelAnimating) {
switch (e.key.scancode) {
case SDL_SCANCODE_ESCAPE:
case SDL_SCANCODE_RETURN:
case SDL_SCANCODE_KP_ENTER:
case SDL_SCANCODE_SPACE:
aboutPanelAnimating = true; aboutDirection = -1;
return;
case SDL_SCANCODE_LEFT:
case SDL_SCANCODE_RIGHT:
case SDL_SCANCODE_UP:
case SDL_SCANCODE_DOWN:
aboutPanelAnimating = true; aboutDirection = -1;
break;
default:
return;
}
}
// If inline level HUD visible and not animating, capture navigation
if (levelPanelVisible && !levelPanelAnimating) {
// Start navigation from tentative hover if present, otherwise from committed selection
@ -385,7 +442,7 @@ void MenuState::handleEvent(const SDL_Event& e) {
case SDL_SCANCODE_LEFT:
case SDL_SCANCODE_UP:
{
const int total = 5;
const int total = 6;
selectedButton = (selectedButton + total - 1) % total;
// brief bright flash on navigation
buttonFlash = 1.0;
@ -394,7 +451,7 @@ void MenuState::handleEvent(const SDL_Event& e) {
case SDL_SCANCODE_RIGHT:
case SDL_SCANCODE_DOWN:
{
const int total = 5;
const int total = 6;
selectedButton = (selectedButton + 1) % total;
// brief bright flash on navigation
buttonFlash = 1.0;
@ -444,6 +501,16 @@ void MenuState::handleEvent(const SDL_Event& e) {
}
break;
case 4:
// Toggle the inline ABOUT HUD (show/hide)
if (!aboutPanelVisible && !aboutPanelAnimating) {
aboutPanelAnimating = true;
aboutDirection = 1;
} else if (aboutPanelVisible && !aboutPanelAnimating) {
aboutPanelAnimating = true;
aboutDirection = -1;
}
break;
case 5:
// Show the inline exit HUD
if (!exitPanelVisible && !exitPanelAnimating) {
exitPanelAnimating = true;
@ -540,6 +607,21 @@ void MenuState::update(double frameMs) {
}
}
// Advance about panel animation if active
if (aboutPanelAnimating) {
double delta = (frameMs / aboutTransitionDurationMs) * static_cast<double>(aboutDirection);
aboutTransition += delta;
if (aboutTransition >= 1.0) {
aboutTransition = 1.0;
aboutPanelVisible = true;
aboutPanelAnimating = false;
} else if (aboutTransition <= 0.0) {
aboutTransition = 0.0;
aboutPanelVisible = false;
aboutPanelAnimating = false;
}
}
// Animate level selection highlight position toward the selected cell center
if (levelTransition > 0.0 && (lastLogicalScale > 0.0f)) {
// Recompute same grid geometry used in render to find target center
@ -665,14 +747,18 @@ void MenuState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logi
const float moveAmount = 420.0f; // increased so lower score rows slide further up
// Compute eased transition and delta to shift highscores when either options, level, or exit HUD is shown.
float combinedTransition = static_cast<float>(std::max(std::max(std::max(optionsTransition, levelTransition), exitTransition), helpTransition));
float combinedTransition = static_cast<float>(std::max(
std::max(std::max(optionsTransition, levelTransition), exitTransition),
std::max(helpTransition, aboutTransition)
));
float eased = combinedTransition * combinedTransition * (3.0f - 2.0f * combinedTransition); // cubic smoothstep
float panelDelta = eased * moveAmount;
// Draw a larger centered logo above the highscores area, then a small "TOP PLAYER" label
// Move logo a bit lower for better spacing
// Move the whole block slightly up to better match the main screen overlay framing.
float menuYOffset = LOGICAL_H * 0.03f; // same offset used for buttons
float topPlayersY = LOGICAL_H * 0.20f + contentOffsetY - panelDelta + menuYOffset;
float scoresYOffset = -LOGICAL_H * 0.05f;
float topPlayersY = LOGICAL_H * 0.20f + contentOffsetY - panelDelta + menuYOffset + scoresYOffset;
float scoresStartY = topPlayersY;
if (useFont) {
// Preferred logo texture (full) if present, otherwise the small logo
@ -1185,8 +1271,47 @@ void MenuState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect logi
int w=0,h=0; f->measure(entry.description, 0.62f, w, h);
cursorY += static_cast<float>(h) + 16.0f;
}
// (rest of help render continues below)
// Add a larger gap between sections
cursorY += 22.0f;
// Draw inline ABOUT HUD (no boxed background) — simple main info
if (aboutTransition > 0.0) {
float easedA = static_cast<float>(aboutTransition);
easedA = easedA * easedA * (3.0f - 2.0f * easedA);
const float PW = std::min(520.0f, LOGICAL_W * 0.65f);
const float PH = std::min(320.0f, LOGICAL_H * 0.60f);
float panelBaseX = (LOGICAL_W - PW) * 0.5f + contentOffsetX;
float panelBaseY = (LOGICAL_H - PH) * 0.5f + contentOffsetY - (LOGICAL_H * 0.10f);
float slideAmount = LOGICAL_H * 0.42f;
float panelY = panelBaseY + (1.0f - easedA) * slideAmount;
FontAtlas* f = ctx.pixelFont ? ctx.pixelFont : ctx.font;
if (f) {
f->draw(renderer, panelBaseX + 12.0f, panelY + 6.0f, "ABOUT", 1.25f, SDL_Color{255,220,0,255});
float x = panelBaseX + 16.0f;
float y = panelY + 52.0f;
const float lineGap = 30.0f;
const SDL_Color textCol{200, 210, 230, 255};
const SDL_Color keyCol{255, 255, 255, 255};
f->draw(renderer, x, y, "SDL3 TETRIS", 1.05f, keyCol); y += lineGap;
f->draw(renderer, x, y, "C++20 / SDL3 / SDL3_ttf", 0.80f, textCol); y += lineGap + 6.0f;
f->draw(renderer, x, y, "GAMEPLAY", 0.85f, SDL_Color{180,200,255,255}); y += lineGap;
f->draw(renderer, x, y, "H Hold / swap current piece", 0.78f, textCol); y += lineGap;
f->draw(renderer, x, y, "SPACE Hard drop", 0.78f, textCol); y += lineGap;
f->draw(renderer, x, y, "P Pause", 0.78f, textCol); y += lineGap + 6.0f;
f->draw(renderer, x, y, "UI", 0.85f, SDL_Color{180,200,255,255}); y += lineGap;
f->draw(renderer, x, y, "F1 Toggle help overlay", 0.78f, textCol); y += lineGap;
f->draw(renderer, x, y, "ESC Back / exit prompt", 0.78f, textCol); y += lineGap + 10.0f;
f->draw(renderer, x, y, "PRESS ESC OR ARROW KEYS TO RETURN", 0.75f, SDL_Color{215,220,240,255});
}
}
};
float leftCursor = panelY + 48.0f - static_cast<float>(helpScroll);

View File

@ -17,9 +17,11 @@ public:
void renderMainButtonTop(SDL_Renderer* renderer, float logicalScale, SDL_Rect logicalVP);
// Show or hide the inline HELP panel (menu-style)
void showHelpPanel(bool show);
// Show or hide the inline ABOUT panel (menu-style)
void showAboutPanel(bool show);
private:
int selectedButton = 0; // 0 = PLAY, 1 = LEVEL, 2 = OPTIONS, 3 = HELP, 4 = EXIT
int selectedButton = 0; // 0 = PLAY, 1 = LEVEL, 2 = OPTIONS, 3 = HELP, 4 = ABOUT, 5 = EXIT
// Button icons (optional - will use text if nullptr)
SDL_Texture* playIcon = nullptr;
@ -85,4 +87,11 @@ private:
double helpTransitionDurationMs = 360.0;
int helpDirection = 1; // 1 show, -1 hide
double helpScroll = 0.0; // vertical scroll offset for content
// About submenu (inline HUD like Help)
bool aboutPanelVisible = false;
bool aboutPanelAnimating = false;
double aboutTransition = 0.0; // 0..1
double aboutTransitionDurationMs = 360.0;
int aboutDirection = 1; // 1 show, -1 hide
};