new background image
This commit is contained in:
@ -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);
|
||||
|
||||
@ -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
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user