fixed keybord selection for quit game play

This commit is contained in:
2025-11-22 11:14:55 +01:00
parent 0ffd801743
commit a257c5cd79
7 changed files with 39 additions and 12 deletions

View File

@ -586,6 +586,7 @@ bool ApplicationManager::initializeGame() {
m_stateContext.hoveredButton = &m_hoveredButton; m_stateContext.hoveredButton = &m_hoveredButton;
m_stateContext.showSettingsPopup = &m_showSettingsPopup; m_stateContext.showSettingsPopup = &m_showSettingsPopup;
m_stateContext.showExitConfirmPopup = &m_showExitConfirmPopup; m_stateContext.showExitConfirmPopup = &m_showExitConfirmPopup;
m_stateContext.exitPopupSelectedButton = &m_exitPopupSelectedButton;
// Create state instances // Create state instances
m_loadingState = std::make_unique<LoadingState>(m_stateContext); m_loadingState = std::make_unique<LoadingState>(m_stateContext);
@ -1048,7 +1049,8 @@ void ApplicationManager::setupStateHandlers() {
logicalScale, logicalScale,
static_cast<float>(winW), static_cast<float>(winW),
static_cast<float>(winH), static_cast<float>(winH),
m_showExitConfirmPopup m_showExitConfirmPopup,
m_exitPopupSelectedButton
); );
// Reset viewport // Reset viewport

View File

@ -94,6 +94,7 @@ private:
int m_hoveredButton = -1; int m_hoveredButton = -1;
bool m_showSettingsPopup = false; bool m_showSettingsPopup = false;
bool m_showExitConfirmPopup = false; bool m_showExitConfirmPopup = false;
int m_exitPopupSelectedButton = 1; // 0 = YES, 1 = NO
uint64_t m_loadStartTicks = 0; uint64_t m_loadStartTicks = 0;
bool m_musicStarted = false; bool m_musicStarted = false;
bool m_musicLoaded = false; bool m_musicLoaded = false;

View File

@ -277,6 +277,7 @@ static void drawSettingsPopup(SDL_Renderer* renderer, FontAtlas& font, bool musi
static double logoAnimCounter = 0.0; static double logoAnimCounter = 0.0;
static bool showSettingsPopup = false; static bool showSettingsPopup = false;
static bool showExitConfirmPopup = false; static bool showExitConfirmPopup = false;
static int exitPopupSelectedButton = 1; // 0 = YES, 1 = NO
static bool musicEnabled = true; static bool musicEnabled = true;
static int hoveredButton = -1; // -1 = none, 0 = play, 1 = level, 2 = settings static int hoveredButton = -1; // -1 = none, 0 = play, 1 = level, 2 = settings
static bool isNewHighScore = false; static bool isNewHighScore = false;
@ -650,6 +651,7 @@ int main(int, char **)
ctx.hoveredButton = &hoveredButton; ctx.hoveredButton = &hoveredButton;
ctx.showSettingsPopup = &showSettingsPopup; ctx.showSettingsPopup = &showSettingsPopup;
ctx.showExitConfirmPopup = &showExitConfirmPopup; ctx.showExitConfirmPopup = &showExitConfirmPopup;
ctx.exitPopupSelectedButton = &exitPopupSelectedButton;
// Instantiate state objects // Instantiate state objects
auto loadingState = std::make_unique<LoadingState>(ctx); auto loadingState = std::make_unique<LoadingState>(ctx);
@ -1324,7 +1326,8 @@ int main(int, char **)
logicalScale, logicalScale,
(float)winW, (float)winW,
(float)winH, (float)winH,
showExitConfirmPopup showExitConfirmPopup,
exitPopupSelectedButton
); );
break; break;
case AppState::GameOver: case AppState::GameOver:

View File

@ -276,6 +276,7 @@ static void drawSettingsPopup(SDL_Renderer* renderer, FontAtlas& font, bool musi
static double logoAnimCounter = 0.0; static double logoAnimCounter = 0.0;
static bool showSettingsPopup = false; static bool showSettingsPopup = false;
static bool showExitConfirmPopup = false; static bool showExitConfirmPopup = false;
static int exitPopupSelectedButton = 1; // 0 = YES, 1 = NO
static bool musicEnabled = true; static bool musicEnabled = true;
static int hoveredButton = -1; // -1 = none, 0 = play, 1 = level, 2 = settings static int hoveredButton = -1; // -1 = none, 0 = play, 1 = level, 2 = settings
@ -644,6 +645,7 @@ int main(int, char **)
ctx.hoveredButton = &hoveredButton; ctx.hoveredButton = &hoveredButton;
ctx.showSettingsPopup = &showSettingsPopup; ctx.showSettingsPopup = &showSettingsPopup;
ctx.showExitConfirmPopup = &showExitConfirmPopup; ctx.showExitConfirmPopup = &showExitConfirmPopup;
ctx.exitPopupSelectedButton = &exitPopupSelectedButton;
// Instantiate state objects // Instantiate state objects
auto loadingState = std::make_unique<LoadingState>(ctx); auto loadingState = std::make_unique<LoadingState>(ctx);

View File

@ -24,6 +24,17 @@ void PlayingState::handleEvent(const SDL_Event& e) {
// We keep short-circuited input here; main still owns mouse UI // We keep short-circuited input here; main still owns mouse UI
if (e.type == SDL_EVENT_KEY_DOWN && !e.key.repeat) { if (e.type == SDL_EVENT_KEY_DOWN && !e.key.repeat) {
if (!ctx.game) return; if (!ctx.game) return;
auto setExitSelection = [&](int value) {
if (ctx.exitPopupSelectedButton) {
*ctx.exitPopupSelectedButton = value;
}
};
auto getExitSelection = [&]() -> int {
return ctx.exitPopupSelectedButton ? *ctx.exitPopupSelectedButton : 1;
};
// Pause toggle (P) // Pause toggle (P)
if (e.key.scancode == SDL_SCANCODE_P) { if (e.key.scancode == SDL_SCANCODE_P) {
bool paused = ctx.game->isPaused(); bool paused = ctx.game->isPaused();
@ -35,20 +46,26 @@ void PlayingState::handleEvent(const SDL_Event& e) {
if (ctx.showExitConfirmPopup && *ctx.showExitConfirmPopup) { if (ctx.showExitConfirmPopup && *ctx.showExitConfirmPopup) {
// Navigate between YES (0) and NO (1) buttons // Navigate between YES (0) and NO (1) buttons
if (e.key.scancode == SDL_SCANCODE_LEFT || e.key.scancode == SDL_SCANCODE_UP) { if (e.key.scancode == SDL_SCANCODE_LEFT || e.key.scancode == SDL_SCANCODE_UP) {
exitPopupSelectedButton = 0; // YES setExitSelection(0);
return; return;
} }
if (e.key.scancode == SDL_SCANCODE_RIGHT || e.key.scancode == SDL_SCANCODE_DOWN) { if (e.key.scancode == SDL_SCANCODE_RIGHT || e.key.scancode == SDL_SCANCODE_DOWN) {
exitPopupSelectedButton = 1; // NO setExitSelection(1);
return; return;
} }
// Activate selected button with Enter or Space // Activate selected button with Enter or Space
if (e.key.scancode == SDL_SCANCODE_RETURN || e.key.scancode == SDL_SCANCODE_KP_ENTER || e.key.scancode == SDL_SCANCODE_SPACE) { if (e.key.scancode == SDL_SCANCODE_RETURN || e.key.scancode == SDL_SCANCODE_KP_ENTER || e.key.scancode == SDL_SCANCODE_SPACE) {
const bool confirmExit = (getExitSelection() == 0);
*ctx.showExitConfirmPopup = false; *ctx.showExitConfirmPopup = false;
if (exitPopupSelectedButton == 0) { if (confirmExit) {
// YES - Reset game and return to menu // YES - Reset game and return to menu
ctx.game->reset(false); if (ctx.startLevelSelection) {
ctx.game->reset(*ctx.startLevelSelection);
} else {
ctx.game->reset(0);
}
ctx.game->setPaused(false);
if (ctx.stateManager) ctx.stateManager->setState(AppState::Menu); if (ctx.stateManager) ctx.stateManager->setState(AppState::Menu);
} else { } else {
// NO - Just close popup and resume // NO - Just close popup and resume
@ -60,6 +77,7 @@ void PlayingState::handleEvent(const SDL_Event& e) {
if (e.key.scancode == SDL_SCANCODE_ESCAPE) { if (e.key.scancode == SDL_SCANCODE_ESCAPE) {
*ctx.showExitConfirmPopup = false; *ctx.showExitConfirmPopup = false;
ctx.game->setPaused(false); ctx.game->setPaused(false);
setExitSelection(1);
return; return;
} }
// While modal is open, suppress other gameplay keys // While modal is open, suppress other gameplay keys
@ -71,6 +89,7 @@ void PlayingState::handleEvent(const SDL_Event& e) {
if (ctx.showExitConfirmPopup) { if (ctx.showExitConfirmPopup) {
if (ctx.game) ctx.game->setPaused(true); if (ctx.game) ctx.game->setPaused(true);
*ctx.showExitConfirmPopup = true; *ctx.showExitConfirmPopup = true;
setExitSelection(1); // Default to NO for safety
} }
return; return;
} }
@ -78,7 +97,7 @@ void PlayingState::handleEvent(const SDL_Event& e) {
// Tetris controls (only when not paused) // Tetris controls (only when not paused)
if (!ctx.game->isPaused()) { if (!ctx.game->isPaused()) {
// Rotation (still event-based for precise timing) // Rotation (still event-based for precise timing)
if (e.key.scancode == SDL_SCANCODE_UP || e.key.scancode == SDL_SCANCODE_W || if (e.key.scancode == SDL_SCANCODE_UP || e.key.scancode == SDL_SCANCODE_W ||
e.key.scancode == SDL_SCANCODE_Z) { e.key.scancode == SDL_SCANCODE_Z) {
ctx.game->rotate(1); // Clockwise rotation ctx.game->rotate(1); // Clockwise rotation
return; return;
@ -87,7 +106,7 @@ void PlayingState::handleEvent(const SDL_Event& e) {
ctx.game->rotate(-1); // Counter-clockwise rotation ctx.game->rotate(-1); // Counter-clockwise rotation
return; return;
} }
// Hard drop (space) // Hard drop (space)
if (e.key.scancode == SDL_SCANCODE_SPACE) { if (e.key.scancode == SDL_SCANCODE_SPACE) {
ctx.game->hardDrop(); ctx.game->hardDrop();
@ -95,8 +114,8 @@ void PlayingState::handleEvent(const SDL_Event& e) {
} }
} }
} }
// Note: Left/Right movement and soft drop are now handled by // Note: Left/Right movement and soft drop are now handled by
// ApplicationManager's update handler for proper DAS/ARR timing // ApplicationManager's update handler for proper DAS/ARR timing
} }

View File

@ -14,5 +14,4 @@ public:
private: private:
// Local per-state variables if needed // Local per-state variables if needed
bool localPaused = false; bool localPaused = false;
int exitPopupSelectedButton = 1; // 0 = YES, 1 = NO (default to NO for safety)
}; };

View File

@ -47,6 +47,7 @@ struct StateContext {
// Menu popups (exposed from main) // Menu popups (exposed from main)
bool* showSettingsPopup = nullptr; bool* showSettingsPopup = nullptr;
bool* showExitConfirmPopup = nullptr; // If true, show "Exit game?" confirmation while playing bool* showExitConfirmPopup = nullptr; // If true, show "Exit game?" confirmation while playing
int* exitPopupSelectedButton = nullptr; // 0 = YES, 1 = NO (default)
// Pointer to the application's StateManager so states can request transitions // Pointer to the application's StateManager so states can request transitions
StateManager* stateManager = nullptr; StateManager* stateManager = nullptr;
}; };