fade effect when switching states
This commit is contained in:
66
src/main.cpp
66
src/main.cpp
@ -913,6 +913,31 @@ int main(int, char **)
|
||||
running = false;
|
||||
};
|
||||
|
||||
auto beginStateFade = [&](AppState targetState, bool armGameplayCountdown) {
|
||||
if (!ctx.stateManager) {
|
||||
return;
|
||||
}
|
||||
if (state == targetState) {
|
||||
return;
|
||||
}
|
||||
if (menuFadePhase != MenuFadePhase::None) {
|
||||
return;
|
||||
}
|
||||
|
||||
menuFadePhase = MenuFadePhase::FadeOut;
|
||||
menuFadeClockMs = 0.0;
|
||||
menuFadeAlpha = 0.0f;
|
||||
menuFadeTarget = targetState;
|
||||
menuPlayCountdownArmed = armGameplayCountdown;
|
||||
gameplayCountdownActive = false;
|
||||
gameplayCountdownIndex = 0;
|
||||
gameplayCountdownElapsed = 0.0;
|
||||
|
||||
if (!armGameplayCountdown) {
|
||||
game.setPaused(false);
|
||||
}
|
||||
};
|
||||
|
||||
auto startMenuPlayTransition = [&]() {
|
||||
if (!ctx.stateManager) {
|
||||
return;
|
||||
@ -922,20 +947,22 @@ int main(int, char **)
|
||||
ctx.stateManager->setState(state);
|
||||
return;
|
||||
}
|
||||
if (menuFadePhase != MenuFadePhase::None) {
|
||||
return;
|
||||
}
|
||||
menuFadePhase = MenuFadePhase::FadeOut;
|
||||
menuFadeClockMs = 0.0;
|
||||
menuFadeAlpha = 0.0f;
|
||||
menuFadeTarget = AppState::Playing;
|
||||
menuPlayCountdownArmed = true;
|
||||
gameplayCountdownActive = false;
|
||||
gameplayCountdownIndex = 0;
|
||||
gameplayCountdownElapsed = 0.0;
|
||||
beginStateFade(AppState::Playing, true);
|
||||
};
|
||||
ctx.startPlayTransition = startMenuPlayTransition;
|
||||
|
||||
auto requestStateFade = [&](AppState targetState) {
|
||||
if (!ctx.stateManager) {
|
||||
return;
|
||||
}
|
||||
if (targetState == AppState::Playing) {
|
||||
startMenuPlayTransition();
|
||||
return;
|
||||
}
|
||||
beginStateFade(targetState, false);
|
||||
};
|
||||
ctx.requestFadeTransition = requestStateFade;
|
||||
|
||||
// Instantiate state objects
|
||||
auto loadingState = std::make_unique<LoadingState>(ctx);
|
||||
auto menuState = std::make_unique<MenuState>(ctx);
|
||||
@ -1100,11 +1127,9 @@ int main(int, char **)
|
||||
if (pointInRect(buttonRects[0])) {
|
||||
startMenuPlayTransition();
|
||||
} else if (pointInRect(buttonRects[1])) {
|
||||
state = AppState::LevelSelector;
|
||||
stateMgr.setState(state);
|
||||
requestStateFade(AppState::LevelSelector);
|
||||
} else if (pointInRect(buttonRects[2])) {
|
||||
state = AppState::Options;
|
||||
stateMgr.setState(state);
|
||||
requestStateFade(AppState::Options);
|
||||
} else if (pointInRect(buttonRects[3])) {
|
||||
showExitConfirmPopup = true;
|
||||
exitPopupSelectedButton = 1;
|
||||
@ -1461,14 +1486,23 @@ int main(int, char **)
|
||||
menuFadeClockMs += frameMs;
|
||||
menuFadeAlpha = std::min(1.0f, float(menuFadeClockMs / MENU_PLAY_FADE_DURATION_MS));
|
||||
if (menuFadeClockMs >= MENU_PLAY_FADE_DURATION_MS) {
|
||||
if (menuFadeTarget == AppState::Playing) {
|
||||
if (state != menuFadeTarget) {
|
||||
state = menuFadeTarget;
|
||||
stateMgr.setState(state);
|
||||
}
|
||||
|
||||
if (menuFadeTarget == AppState::Playing) {
|
||||
menuPlayCountdownArmed = true;
|
||||
gameplayCountdownActive = false;
|
||||
gameplayCountdownIndex = 0;
|
||||
gameplayCountdownElapsed = 0.0;
|
||||
game.setPaused(true);
|
||||
} else {
|
||||
menuPlayCountdownArmed = false;
|
||||
gameplayCountdownActive = false;
|
||||
gameplayCountdownIndex = 0;
|
||||
gameplayCountdownElapsed = 0.0;
|
||||
game.setPaused(false);
|
||||
}
|
||||
menuFadePhase = MenuFadePhase::FadeIn;
|
||||
menuFadeClockMs = MENU_PLAY_FADE_DURATION_MS;
|
||||
|
||||
@ -326,14 +326,18 @@ void LevelSelectorState::selectLevel(int level) {
|
||||
*ctx.startLevelSelection = level;
|
||||
}
|
||||
// Transition back to menu
|
||||
if (ctx.stateManager) {
|
||||
if (ctx.requestFadeTransition) {
|
||||
ctx.requestFadeTransition(AppState::Menu);
|
||||
} else if (ctx.stateManager) {
|
||||
ctx.stateManager->setState(AppState::Menu);
|
||||
}
|
||||
}
|
||||
|
||||
void LevelSelectorState::closePopup() {
|
||||
// Transition back to menu without changing level
|
||||
if (ctx.stateManager) {
|
||||
if (ctx.requestFadeTransition) {
|
||||
ctx.requestFadeTransition(AppState::Menu);
|
||||
} else if (ctx.stateManager) {
|
||||
ctx.stateManager->setState(AppState::Menu);
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,10 +126,18 @@ void MenuState::handleEvent(const SDL_Event& e) {
|
||||
triggerPlay();
|
||||
break;
|
||||
case 1:
|
||||
ctx.stateManager->setState(AppState::LevelSelector);
|
||||
if (ctx.requestFadeTransition) {
|
||||
ctx.requestFadeTransition(AppState::LevelSelector);
|
||||
} else if (ctx.stateManager) {
|
||||
ctx.stateManager->setState(AppState::LevelSelector);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
ctx.stateManager->setState(AppState::Options);
|
||||
if (ctx.requestFadeTransition) {
|
||||
ctx.requestFadeTransition(AppState::Options);
|
||||
} else if (ctx.stateManager) {
|
||||
ctx.stateManager->setState(AppState::Options);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
setExitPrompt(true);
|
||||
|
||||
@ -267,7 +267,9 @@ void OptionsState::toggleSoundFx() {
|
||||
}
|
||||
|
||||
void OptionsState::exitToMenu() {
|
||||
if (ctx.stateManager) {
|
||||
if (ctx.requestFadeTransition) {
|
||||
ctx.requestFadeTransition(AppState::Menu);
|
||||
} else if (ctx.stateManager) {
|
||||
ctx.stateManager->setState(AppState::Menu);
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ class Starfield;
|
||||
class Starfield3D;
|
||||
class FontAtlas;
|
||||
class LineEffect;
|
||||
enum class AppState;
|
||||
|
||||
// Forward declare StateManager so StateContext can hold a pointer without
|
||||
// including the StateManager header here.
|
||||
@ -58,6 +59,7 @@ struct StateContext {
|
||||
std::function<bool()> queryFullscreen; // Optional callback if fullscreenFlag is not reliable
|
||||
std::function<void()> requestQuit; // Allows menu/option states to close the app gracefully
|
||||
std::function<void()> startPlayTransition; // Optional fade hook when transitioning from menu to gameplay
|
||||
std::function<void(AppState)> requestFadeTransition; // Generic state fade requests (menu/options/level)
|
||||
// Pointer to the application's StateManager so states can request transitions
|
||||
StateManager* stateManager = nullptr;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user