updated gameplay
This commit is contained in:
Binary file not shown.
Binary file not shown.
@ -267,6 +267,7 @@ struct TetrisApp::Impl {
|
||||
int countdownLevel = 0;
|
||||
int countdownGoalAsteroids = 0;
|
||||
bool countdownAdvancesChallenge = false;
|
||||
bool challengeCountdownWaitingForSpace = false;
|
||||
double gameplayBackgroundClockMs = 0.0;
|
||||
std::string challengeStoryText;
|
||||
int challengeStoryLevel = 0;
|
||||
@ -1001,6 +1002,28 @@ void TetrisApp::Impl::runLoop()
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (e.type == SDL_EVENT_KEY_DOWN && !e.key.repeat) {
|
||||
if (gameplayCountdownActive && gameplayCountdownSource == CountdownSource::ChallengeLevel && challengeCountdownWaitingForSpace) {
|
||||
if (e.key.scancode == SDL_SCANCODE_SPACE) {
|
||||
challengeCountdownWaitingForSpace = false;
|
||||
gameplayCountdownElapsed = 0.0;
|
||||
gameplayCountdownIndex = 0;
|
||||
} else if (e.key.scancode == SDL_SCANCODE_ESCAPE) {
|
||||
// Show quit popup, keep game paused, cancel countdown
|
||||
if (!showExitConfirmPopup) {
|
||||
showExitConfirmPopup = true;
|
||||
exitPopupSelectedButton = 1; // default to NO
|
||||
}
|
||||
gameplayCountdownActive = false;
|
||||
menuPlayCountdownArmed = false;
|
||||
gameplayCountdownElapsed = 0.0;
|
||||
gameplayCountdownIndex = 0;
|
||||
countdownAdvancesChallenge = false;
|
||||
challengeCountdownWaitingForSpace = false;
|
||||
if (game) game->setPaused(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1017,8 +1040,12 @@ void TetrisApp::Impl::runLoop()
|
||||
challengeStoryClockMs = 0.0;
|
||||
};
|
||||
|
||||
// Update challenge story fade/timeout
|
||||
// Update challenge story fade/timeout; during countdown wait we keep it fully visible
|
||||
if (state == AppState::Playing && game && game->getMode() == GameMode::Challenge && !challengeStoryText.empty()) {
|
||||
if (gameplayCountdownActive && gameplayCountdownSource == CountdownSource::ChallengeLevel && challengeCountdownWaitingForSpace) {
|
||||
// Locked-visible while waiting
|
||||
challengeStoryAlpha = 1.0f;
|
||||
} else {
|
||||
const double fadeInMs = 320.0;
|
||||
const double holdMs = 3200.0;
|
||||
const double fadeOutMs = 900.0;
|
||||
@ -1036,6 +1063,7 @@ void TetrisApp::Impl::runLoop()
|
||||
}
|
||||
challengeStoryAlpha = static_cast<float>(std::clamp(a, 0.0, 1.0));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
clearChallengeStory();
|
||||
}
|
||||
@ -1057,6 +1085,7 @@ void TetrisApp::Impl::runLoop()
|
||||
captureChallengeStory(countdownLevel);
|
||||
countdownAdvancesChallenge = false; // already advanced
|
||||
gameplayCountdownActive = true;
|
||||
challengeCountdownWaitingForSpace = true;
|
||||
menuPlayCountdownArmed = false;
|
||||
gameplayCountdownElapsed = 0.0;
|
||||
gameplayCountdownIndex = 0;
|
||||
@ -1460,9 +1489,11 @@ void TetrisApp::Impl::runLoop()
|
||||
countdownGoalAsteroids = countdownLevel;
|
||||
if (gameplayCountdownSource == CountdownSource::ChallengeLevel) {
|
||||
captureChallengeStory(countdownLevel);
|
||||
challengeCountdownWaitingForSpace = true;
|
||||
} else {
|
||||
challengeStoryText.clear();
|
||||
challengeStoryLevel = 0;
|
||||
challengeCountdownWaitingForSpace = false;
|
||||
}
|
||||
countdownAdvancesChallenge = false;
|
||||
menuPlayCountdownArmed = true;
|
||||
@ -1475,6 +1506,7 @@ void TetrisApp::Impl::runLoop()
|
||||
gameplayCountdownActive = false;
|
||||
gameplayCountdownIndex = 0;
|
||||
gameplayCountdownElapsed = 0.0;
|
||||
challengeCountdownWaitingForSpace = false;
|
||||
game->setPaused(false);
|
||||
}
|
||||
menuFadePhase = MenuFadePhase::FadeIn;
|
||||
@ -1499,9 +1531,11 @@ void TetrisApp::Impl::runLoop()
|
||||
countdownGoalAsteroids = countdownLevel;
|
||||
if (gameplayCountdownSource == CountdownSource::ChallengeLevel) {
|
||||
captureChallengeStory(countdownLevel);
|
||||
challengeCountdownWaitingForSpace = true;
|
||||
} else {
|
||||
challengeStoryText.clear();
|
||||
challengeStoryLevel = 0;
|
||||
challengeCountdownWaitingForSpace = false;
|
||||
}
|
||||
countdownAdvancesChallenge = false;
|
||||
gameplayCountdownActive = true;
|
||||
@ -1512,6 +1546,7 @@ void TetrisApp::Impl::runLoop()
|
||||
}
|
||||
|
||||
if (gameplayCountdownActive && state == AppState::Playing) {
|
||||
if (!challengeCountdownWaitingForSpace || gameplayCountdownSource != CountdownSource::ChallengeLevel) {
|
||||
gameplayCountdownElapsed += frameMs;
|
||||
if (gameplayCountdownElapsed >= GAMEPLAY_COUNTDOWN_STEP_MS) {
|
||||
gameplayCountdownElapsed -= GAMEPLAY_COUNTDOWN_STEP_MS;
|
||||
@ -1528,6 +1563,7 @@ void TetrisApp::Impl::runLoop()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state != AppState::Playing && gameplayCountdownActive) {
|
||||
gameplayCountdownActive = false;
|
||||
@ -1535,6 +1571,7 @@ void TetrisApp::Impl::runLoop()
|
||||
gameplayCountdownElapsed = 0.0;
|
||||
gameplayCountdownIndex = 0;
|
||||
countdownAdvancesChallenge = false;
|
||||
challengeCountdownWaitingForSpace = false;
|
||||
game->setPaused(false);
|
||||
}
|
||||
|
||||
@ -1953,10 +1990,82 @@ void TetrisApp::Impl::runLoop()
|
||||
float goalY = levelY + static_cast<float>(lvlH) + 14.0f;
|
||||
pixelFont.draw(renderer, goalX, goalY, goalBuf, goalScale, SDL_Color{220, 245, 255, 255});
|
||||
|
||||
// Optional story/briefing line
|
||||
if (!challengeStoryText.empty() && challengeStoryAlpha > 0.0f) {
|
||||
SDL_Color storyColor{170, 230, 255, static_cast<Uint8>(std::lround(255.0f * challengeStoryAlpha))};
|
||||
SDL_Color shadowColor{0, 0, 0, static_cast<Uint8>(std::lround(160.0f * challengeStoryAlpha))};
|
||||
|
||||
auto drawCenteredWrapped = [&](const std::string& text, float y, float maxWidth, float scale) {
|
||||
std::istringstream iss(text);
|
||||
std::string word;
|
||||
std::string line;
|
||||
float cursorY = y;
|
||||
int lastH = 0;
|
||||
while (iss >> word) {
|
||||
std::string candidate = line.empty() ? word : (line + " " + word);
|
||||
int candidateW = 0, candidateH = 0;
|
||||
pixelFont.measure(candidate, scale, candidateW, candidateH);
|
||||
if (candidateW > maxWidth && !line.empty()) {
|
||||
int lineW = 0, lineH = 0;
|
||||
pixelFont.measure(line, scale, lineW, lineH);
|
||||
float lineX = (winW - static_cast<float>(lineW)) * 0.5f;
|
||||
pixelFont.draw(renderer, lineX + 1.0f, cursorY + 1.0f, line, scale, shadowColor);
|
||||
pixelFont.draw(renderer, lineX, cursorY, line, scale, storyColor);
|
||||
cursorY += lineH + 6.0f;
|
||||
line = word;
|
||||
lastH = lineH;
|
||||
} else {
|
||||
line = candidate;
|
||||
lastH = candidateH;
|
||||
}
|
||||
}
|
||||
if (!line.empty()) {
|
||||
int w = 0, h = 0;
|
||||
pixelFont.measure(line, scale, w, h);
|
||||
float lineX = (winW - static_cast<float>(w)) * 0.5f;
|
||||
pixelFont.draw(renderer, lineX + 1.0f, cursorY + 1.0f, line, scale, shadowColor);
|
||||
pixelFont.draw(renderer, lineX, cursorY, line, scale, storyColor);
|
||||
cursorY += h + 6.0f;
|
||||
}
|
||||
return cursorY;
|
||||
};
|
||||
|
||||
float storyStartY = goalY + static_cast<float>(goalH) + 22.0f;
|
||||
float usedY = drawCenteredWrapped(challengeStoryText, storyStartY, std::min<float>(winW * 0.7f, 720.0f), 1.0f);
|
||||
float promptY = usedY + 10.0f;
|
||||
if (challengeCountdownWaitingForSpace) {
|
||||
const char* prompt = "PRESS SPACE";
|
||||
int pW = 0, pH = 0;
|
||||
float pScale = 1.35f;
|
||||
pixelFont.measure(prompt, pScale, pW, pH);
|
||||
float px = (winW - static_cast<float>(pW)) * 0.5f;
|
||||
pixelFont.draw(renderer, px + 2.0f, promptY + 2.0f, prompt, pScale, SDL_Color{0, 0, 0, 200});
|
||||
pixelFont.draw(renderer, px, promptY, prompt, pScale, SDL_Color{255, 220, 40, 255});
|
||||
promptY += pH + 14.0f;
|
||||
}
|
||||
textY = promptY + 10.0f;
|
||||
} else {
|
||||
if (challengeCountdownWaitingForSpace) {
|
||||
const char* prompt = "PRESS SPACE";
|
||||
int pW = 0, pH = 0;
|
||||
float pScale = 1.35f;
|
||||
pixelFont.measure(prompt, pScale, pW, pH);
|
||||
float px = (winW - static_cast<float>(pW)) * 0.5f;
|
||||
float py = goalY + static_cast<float>(goalH) + 18.0f;
|
||||
pixelFont.draw(renderer, px + 2.0f, py + 2.0f, prompt, pScale, SDL_Color{0, 0, 0, 200});
|
||||
pixelFont.draw(renderer, px, py, prompt, pScale, SDL_Color{255, 220, 40, 255});
|
||||
textY = py + pH + 24.0f;
|
||||
} else {
|
||||
textY = goalY + static_cast<float>(goalH) + 38.0f;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
textY = winH * 0.38f;
|
||||
}
|
||||
if (!(gameplayCountdownSource == CountdownSource::ChallengeLevel && challengeCountdownWaitingForSpace)) {
|
||||
SDL_Color textColor = isFinalCue ? SDL_Color{255, 230, 90, 255} : SDL_Color{255, 255, 255, 255};
|
||||
pixelFont.draw(renderer, textX, textY, label, textScale, textColor);
|
||||
}
|
||||
|
||||
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
|
||||
}
|
||||
|
||||
@ -46,7 +46,6 @@ bool SoundEffect::load(const std::string& filePath) {
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
//std::printf("[SoundEffect] Loaded: %s (%d channels, %d Hz, %zu samples)\n", filePath.c_str(), channels, sampleRate, pcmData.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -56,8 +55,6 @@ void SoundEffect::play(float volume) {
|
||||
return;
|
||||
}
|
||||
|
||||
//std::printf("[SoundEffect] Playing sound with %zu samples at volume %.2f\n", pcmData.size(), volume);
|
||||
|
||||
// Calculate final volume
|
||||
float finalVolume = defaultVolume * volume;
|
||||
finalVolume = (std::max)(0.0f, (std::min)(1.0f, finalVolume));
|
||||
|
||||
@ -270,8 +270,8 @@ void PlayingState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect l
|
||||
challengeClearOrder,
|
||||
challengeClearElapsed,
|
||||
challengeClearDuration,
|
||||
ctx.challengeStoryText,
|
||||
ctx.challengeStoryAlpha ? *ctx.challengeStoryAlpha : 0.0f
|
||||
countdown ? nullptr : ctx.challengeStoryText,
|
||||
countdown ? 0.0f : (ctx.challengeStoryAlpha ? *ctx.challengeStoryAlpha : 0.0f)
|
||||
);
|
||||
|
||||
// Reset to screen
|
||||
@ -366,8 +366,8 @@ void PlayingState::render(SDL_Renderer* renderer, float logicalScale, SDL_Rect l
|
||||
challengeClearOrder,
|
||||
challengeClearElapsed,
|
||||
challengeClearDuration,
|
||||
ctx.challengeStoryText,
|
||||
ctx.challengeStoryAlpha ? *ctx.challengeStoryAlpha : 0.0f
|
||||
countdown ? nullptr : ctx.challengeStoryText,
|
||||
countdown ? 0.0f : (ctx.challengeStoryAlpha ? *ctx.challengeStoryAlpha : 0.0f)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user