used tileset sprite sheet for asteroids

This commit is contained in:
2025-12-20 13:50:56 +01:00
parent 34447f0245
commit 970259e3d6
10 changed files with 178 additions and 31 deletions

View File

@ -137,6 +137,7 @@ struct TetrisApp::Impl {
int mainScreenH = 0;
SDL_Texture* blocksTex = nullptr;
SDL_Texture* asteroidsTex = nullptr;
SDL_Texture* scorePanelTex = nullptr;
SDL_Texture* statisticsPanelTex = nullptr;
SDL_Texture* nextPanelTex = nullptr;
@ -163,6 +164,7 @@ struct TetrisApp::Impl {
std::vector<std::string> tripleSounds;
std::vector<std::string> tetrisSounds;
bool suppressLineVoiceForLevelUp = false;
bool skipNextLevelUpJingle = false;
AppState state = AppState::Loading;
double loadingProgress = 0.0;
@ -184,12 +186,18 @@ struct TetrisApp::Impl {
float menuFadeAlpha = 0.0f;
double MENU_PLAY_FADE_DURATION_MS = 450.0;
AppState menuFadeTarget = AppState::Menu;
enum class CountdownSource { MenuStart, ChallengeLevel };
bool menuPlayCountdownArmed = false;
bool gameplayCountdownActive = false;
double gameplayCountdownElapsed = 0.0;
int gameplayCountdownIndex = 0;
double GAMEPLAY_COUNTDOWN_STEP_MS = 400.0;
std::array<const char*, 4> GAMEPLAY_COUNTDOWN_LABELS = { "3", "2", "1", "START" };
CountdownSource gameplayCountdownSource = CountdownSource::MenuStart;
int countdownLevel = 0;
int countdownGoalAsteroids = 0;
bool countdownAdvancesChallenge = false;
double gameplayBackgroundClockMs = 0.0;
std::unique_ptr<StateManager> stateMgr;
@ -369,8 +377,12 @@ int TetrisApp::Impl::init()
});
game->setLevelUpCallback([this](int /*newLevel*/) {
SoundEffectManager::instance().playSound("new_level", 1.0f);
SoundEffectManager::instance().playSound("lets_go", 1.0f);
if (skipNextLevelUpJingle) {
skipNextLevelUpJingle = false;
} else {
SoundEffectManager::instance().playSound("new_level", 1.0f);
SoundEffectManager::instance().playSound("lets_go", 1.0f);
}
suppressLineVoiceForLevelUp = true;
});
@ -419,6 +431,7 @@ int TetrisApp::Impl::init()
ctx.logoSmallW = logoSmallW;
ctx.logoSmallH = logoSmallH;
ctx.backgroundTex = nullptr;
ctx.asteroidsTex = asteroidsTex;
ctx.blocksTex = blocksTex;
ctx.scorePanelTex = scorePanelTex;
ctx.statisticsPanelTex = statisticsPanelTex;
@ -989,7 +1002,8 @@ void TetrisApp::Impl::runLoop()
Assets::PANEL_SCORE,
Assets::PANEL_STATS,
Assets::NEXT_PANEL,
Assets::HOLD_PANEL
Assets::HOLD_PANEL,
Assets::ASTEROID_SPRITE
};
for (auto &p : queuedPaths) {
loadingManager->queueTexture(p);
@ -1024,6 +1038,7 @@ void TetrisApp::Impl::runLoop()
logoSmallTex = assetLoader.getTexture(Assets::LOGO);
mainScreenTex = assetLoader.getTexture(Assets::MAIN_SCREEN);
blocksTex = assetLoader.getTexture(Assets::BLOCKS_SPRITE);
asteroidsTex = assetLoader.getTexture(Assets::ASTEROID_SPRITE);
scorePanelTex = assetLoader.getTexture(Assets::PANEL_SCORE);
statisticsPanelTex = assetLoader.getTexture(Assets::PANEL_STATS);
nextPanelTex = assetLoader.getTexture(Assets::NEXT_PANEL);
@ -1056,6 +1071,7 @@ void TetrisApp::Impl::runLoop()
legacyLoad(Assets::LOGO, logoSmallTex, &logoSmallW, &logoSmallH);
legacyLoad(Assets::MAIN_SCREEN, mainScreenTex, &mainScreenW, &mainScreenH);
legacyLoad(Assets::BLOCKS_SPRITE, blocksTex);
legacyLoad(Assets::ASTEROID_SPRITE, asteroidsTex);
legacyLoad(Assets::PANEL_SCORE, scorePanelTex);
legacyLoad(Assets::PANEL_STATS, statisticsPanelTex);
legacyLoad(Assets::NEXT_PANEL, nextPanelTex);
@ -1208,12 +1224,30 @@ void TetrisApp::Impl::runLoop()
break;
}
if (state == AppState::Playing && game && game->getMode() == GameMode::Challenge && !gameplayCountdownActive) {
int queuedLevel = game->consumeQueuedChallengeLevel();
if (queuedLevel > 0) {
gameplayCountdownSource = CountdownSource::ChallengeLevel;
countdownLevel = queuedLevel;
countdownGoalAsteroids = queuedLevel;
countdownAdvancesChallenge = true;
gameplayCountdownActive = true;
menuPlayCountdownArmed = false;
gameplayCountdownElapsed = 0.0;
gameplayCountdownIndex = 0;
game->setPaused(true);
SoundEffectManager::instance().playSound("new_level", 1.0f);
skipNextLevelUpJingle = true;
}
}
ctx.logoTex = logoTex;
ctx.logoSmallTex = logoSmallTex;
ctx.logoSmallW = logoSmallW;
ctx.logoSmallH = logoSmallH;
ctx.backgroundTex = backgroundTex;
ctx.blocksTex = blocksTex;
ctx.asteroidsTex = asteroidsTex;
ctx.scorePanelTex = scorePanelTex;
ctx.statisticsPanelTex = statisticsPanelTex;
ctx.nextPanelTex = nextPanelTex;
@ -1232,6 +1266,12 @@ void TetrisApp::Impl::runLoop()
}
if (menuFadeTarget == AppState::Playing) {
gameplayCountdownSource = (game && game->getMode() == GameMode::Challenge)
? CountdownSource::ChallengeLevel
: CountdownSource::MenuStart;
countdownLevel = game ? game->challengeLevel() : 1;
countdownGoalAsteroids = countdownLevel;
countdownAdvancesChallenge = false;
menuPlayCountdownArmed = true;
gameplayCountdownActive = false;
gameplayCountdownIndex = 0;
@ -1259,6 +1299,12 @@ void TetrisApp::Impl::runLoop()
}
if (menuFadePhase == MenuFadePhase::None && menuPlayCountdownArmed && !gameplayCountdownActive && state == AppState::Playing) {
gameplayCountdownSource = (game && game->getMode() == GameMode::Challenge)
? CountdownSource::ChallengeLevel
: CountdownSource::MenuStart;
countdownLevel = game ? game->challengeLevel() : 1;
countdownGoalAsteroids = countdownLevel;
countdownAdvancesChallenge = false;
gameplayCountdownActive = true;
menuPlayCountdownArmed = false;
gameplayCountdownElapsed = 0.0;
@ -1275,6 +1321,10 @@ void TetrisApp::Impl::runLoop()
gameplayCountdownActive = false;
gameplayCountdownElapsed = 0.0;
gameplayCountdownIndex = 0;
if (gameplayCountdownSource == CountdownSource::ChallengeLevel && countdownAdvancesChallenge && game) {
game->beginNextChallengeLevel();
}
countdownAdvancesChallenge = false;
game->setPaused(false);
}
}
@ -1285,6 +1335,7 @@ void TetrisApp::Impl::runLoop()
menuPlayCountdownArmed = false;
gameplayCountdownElapsed = 0.0;
gameplayCountdownIndex = 0;
countdownAdvancesChallenge = false;
game->setPaused(false);
}
@ -1520,6 +1571,7 @@ void TetrisApp::Impl::runLoop()
&pixelFont,
&lineEffect,
blocksTex,
asteroidsTex,
ctx.statisticsPanelTex,
scorePanelTex,
nextPanelTex,
@ -1674,6 +1726,27 @@ void TetrisApp::Impl::runLoop()
float textX = (winW - static_cast<float>(textW)) * 0.5f;
float textY = (winH - static_cast<float>(textH)) * 0.5f;
if (gameplayCountdownSource == CountdownSource::ChallengeLevel) {
char levelBuf[32];
std::snprintf(levelBuf, sizeof(levelBuf), "LEVEL %d", countdownLevel);
int lvlW = 0, lvlH = 0;
float lvlScale = 2.5f;
pixelFont.measure(levelBuf, lvlScale, lvlW, lvlH);
float levelX = (winW - static_cast<float>(lvlW)) * 0.5f;
float levelY = winH * 0.32f;
pixelFont.draw(renderer, levelX, levelY, levelBuf, lvlScale, SDL_Color{140, 210, 255, 255});
char goalBuf[64];
std::snprintf(goalBuf, sizeof(goalBuf), "ASTEROIDS: %d", countdownGoalAsteroids);
int goalW = 0, goalH = 0;
float goalScale = 1.7f;
pixelFont.measure(goalBuf, goalScale, goalW, goalH);
float goalX = (winW - static_cast<float>(goalW)) * 0.5f;
float goalY = levelY + static_cast<float>(lvlH) + 14.0f;
pixelFont.draw(renderer, goalX, goalY, goalBuf, goalScale, SDL_Color{220, 245, 255, 255});
textY = goalY + static_cast<float>(goalH) + 38.0f;
}
SDL_Color textColor = isFinalCue ? SDL_Color{255, 230, 90, 255} : SDL_Color{255, 255, 255, 255};
pixelFont.draw(renderer, textX, textY, label, textScale, textColor);