From 5fd77fdaf0f724ad478355ac73697099260954d1 Mon Sep 17 00:00:00 2001 From: Gregor Klevze Date: Sun, 30 Nov 2025 10:37:35 +0100 Subject: [PATCH] Added new level sound --- assets/music/hard_drop_001.mp3 | Bin 0 -> 35108 bytes assets/music/new_level.mp3 | Bin 0 -> 32968 bytes src/gameplay/core/Game.cpp | 51 ++++++++- src/gameplay/core/Game.h | 13 +++ src/graphics/renderers/GameRenderer.cpp | 142 +++++++++++++++++++++++- src/main.cpp | 14 ++- src/states/PlayingState.cpp | 4 + 7 files changed, 219 insertions(+), 5 deletions(-) create mode 100644 assets/music/hard_drop_001.mp3 create mode 100644 assets/music/new_level.mp3 diff --git a/assets/music/hard_drop_001.mp3 b/assets/music/hard_drop_001.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..7b6f1fa6e517b154460d06123530d66a9f9bd806 GIT binary patch literal 35108 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 literal 0 HcmV?d00001 diff --git a/assets/music/new_level.mp3 b/assets/music/new_level.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..d8d4522d2a884c36ae4c9a271c148c53f5eb1748 GIT binary patch literal 32968 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 R&sQ4%{dWKV=KpyF{s$B5-Sz+g literal 0 HcmV?d00001 diff --git a/src/gameplay/core/Game.cpp b/src/gameplay/core/Game.cpp index 2196648..8342ce0 100644 --- a/src/gameplay/core/Game.cpp +++ b/src/gameplay/core/Game.cpp @@ -57,6 +57,9 @@ void Game::reset(int startLevel_) { // Initialize gravity using NES timing table (ms per cell by level) gravityMs = gravityMsForLevel(_level, gravityGlobalMultiplier); fallAcc = 0; gameOver=false; paused=false; + hardDropShakeTimerMs = 0.0; + hardDropCells.clear(); + hardDropFxId = 0; _startTime = SDL_GetPerformanceCounter(); _pausedTime = 0; _lastPauseStart = 0; @@ -328,6 +331,25 @@ void Game::softDropBoost(double frameMs) { (void)frameMs; } +void Game::updateVisualEffects(double frameMs) { + if (frameMs <= 0.0) { + return; + } + + if (hardDropShakeTimerMs <= 0.0) { + hardDropShakeTimerMs = 0.0; + if (!hardDropCells.empty()) { + hardDropCells.clear(); + } + return; + } + + hardDropShakeTimerMs = std::max(0.0, hardDropShakeTimerMs - frameMs); + if (hardDropShakeTimerMs <= 0.0 && !hardDropCells.empty()) { + hardDropCells.clear(); + } +} + void Game::hardDrop() { if (paused) return; // Count how many rows we drop for scoring parity with JS @@ -337,7 +359,34 @@ void Game::hardDrop() { if (rows > 0) { _score += rows * 1; } - lockPiece(); + hardDropCells.clear(); + hardDropCells.reserve(8); + for (int cy = 0; cy < 4; ++cy) { + for (int cx = 0; cx < 4; ++cx) { + if (!cellFilled(cur, cx, cy)) { + continue; + } + int gx = cur.x + cx; + int gy = cur.y + cy; + if (gx < 0 || gx >= COLS || gy >= ROWS) { + continue; + } + if (gy >= 0) { + hardDropCells.push_back(SDL_Point{gx, gy}); + } + } + } + + ++hardDropFxId; + lockPiece(); + hardDropShakeTimerMs = HARD_DROP_SHAKE_DURATION_MS; +} + +double Game::hardDropShakeStrength() const { + if (hardDropShakeTimerMs <= 0.0) { + return 0.0; + } + return std::clamp(hardDropShakeTimerMs / HARD_DROP_SHAKE_DURATION_MS, 0.0, 1.0); } void Game::rotate(int dir) { diff --git a/src/gameplay/core/Game.h b/src/gameplay/core/Game.h index 48de705..8fd26b1 100644 --- a/src/gameplay/core/Game.h +++ b/src/gameplay/core/Game.h @@ -74,6 +74,13 @@ public: double getFallAccumulator() const { return fallAcc; } // Debug: time accumulated toward next drop void setLevelGravityMultiplier(int level, double m); + // Visual effect hooks + void updateVisualEffects(double frameMs); + bool hasHardDropShake() const { return hardDropShakeTimerMs > 0.0; } + double hardDropShakeStrength() const; + const std::vector& getHardDropCells() const { return hardDropCells; } + uint32_t getHardDropFxId() const { return hardDropFxId; } + private: std::array board{}; // 0 empty else color index Piece cur{}, hold{}, nextPiece{}; // current, held & next piece @@ -109,6 +116,12 @@ private: // Backwards-compatible accessors (delegate to gravityMgr) double computeGravityMsForLevel(int level) const; + // Impact FX timers + double hardDropShakeTimerMs{0.0}; + static constexpr double HARD_DROP_SHAKE_DURATION_MS = 320.0; + std::vector hardDropCells; + uint32_t hardDropFxId{0}; + // Internal helpers ---------------------------------------------------- void refillBag(); void spawn(); diff --git a/src/graphics/renderers/GameRenderer.cpp b/src/graphics/renderers/GameRenderer.cpp index 074d586..b280d37 100644 --- a/src/graphics/renderers/GameRenderer.cpp +++ b/src/graphics/renderers/GameRenderer.cpp @@ -6,8 +6,23 @@ #include #include #include +#include +#include #include "../../core/Settings.h" +namespace { +struct ImpactSpark { + float x = 0.0f; + float y = 0.0f; + float vx = 0.0f; + float vy = 0.0f; + float lifeMs = 0.0f; + float maxLifeMs = 0.0f; + float size = 0.0f; + SDL_Color color{255, 255, 255, 255}; +}; +} + // Color constants (copied from main.cpp) static const SDL_Color COLORS[] = { {0, 0, 0, 255}, // 0: BLACK (empty) @@ -126,6 +141,18 @@ void GameRenderer::renderPlayingState( float winH ) { if (!game || !pixelFont) return; + + static std::vector s_impactSparks; + static uint32_t s_lastImpactFxId = 0; + static Uint32 s_lastImpactTick = SDL_GetTicks(); + static std::mt19937 s_impactRng{ std::random_device{}() }; + + Uint32 nowTicks = SDL_GetTicks(); + float sparkDeltaMs = static_cast(nowTicks - s_lastImpactTick); + s_lastImpactTick = nowTicks; + if (sparkDeltaMs < 0.0f || sparkDeltaMs > 100.0f) { + sparkDeltaMs = 16.0f; + } // Calculate actual content area (centered within the window) float contentScale = logicalScale; @@ -223,19 +250,132 @@ void GameRenderer::renderPlayingState( drawRectWithOffset(nextX - 3 - contentOffsetX, nextY - 3 - contentOffsetY, nextW + 6, nextH + 6, {100, 120, 200, 255}); drawRectWithOffset(nextX - contentOffsetX, nextY - contentOffsetY, nextW, nextH, {30, 35, 50, 255}); + // Precompute row drop offsets (line collapse effect) + std::array rowDropOffsets{}; + for (int y = 0; y < Game::ROWS; ++y) { + rowDropOffsets[y] = (lineEffect ? lineEffect->getRowDropOffset(y) : 0.0f); + } + // Draw the game board const auto &board = game->boardRef(); + float impactStrength = 0.0f; + float impactEased = 0.0f; + std::array impactMask{}; + std::array impactWeight{}; + if (game->hasHardDropShake()) { + impactStrength = static_cast(game->hardDropShakeStrength()); + impactStrength = std::clamp(impactStrength, 0.0f, 1.0f); + impactEased = impactStrength * impactStrength; + const auto& impactCells = game->getHardDropCells(); + for (const auto& cell : impactCells) { + if (cell.x < 0 || cell.x >= Game::COLS || cell.y < 0 || cell.y >= Game::ROWS) { + continue; + } + int idx = cell.y * Game::COLS + cell.x; + impactMask[idx] = 1; + impactWeight[idx] = 1.0f; + + int depth = 0; + for (int ny = cell.y + 1; ny < Game::ROWS && depth < 4; ++ny) { + if (board[ny * Game::COLS + cell.x] == 0) { + break; + } + ++depth; + int nidx = ny * Game::COLS + cell.x; + impactMask[nidx] = 1; + float weight = std::max(0.15f, 1.0f - depth * 0.35f); + impactWeight[nidx] = std::max(impactWeight[nidx], weight); + } + } + } + + bool shouldSpawnCrackles = game->hasHardDropShake() && !game->getHardDropCells().empty() && game->getHardDropFxId() != s_lastImpactFxId; + if (shouldSpawnCrackles) { + s_lastImpactFxId = game->getHardDropFxId(); + std::uniform_real_distribution jitter(-finalBlockSize * 0.2f, finalBlockSize * 0.2f); + std::uniform_real_distribution velX(-0.04f, 0.04f); + std::uniform_real_distribution velY(0.035f, 0.07f); + std::uniform_real_distribution lifespan(210.0f, 320.0f); + std::uniform_real_distribution sizeDist(finalBlockSize * 0.08f, finalBlockSize * 0.14f); + + const auto& impactCells = game->getHardDropCells(); + for (const auto& cell : impactCells) { + if (cell.x < 0 || cell.x >= Game::COLS || cell.y < 0 || cell.y >= Game::ROWS) { + continue; + } + int idx = cell.y * Game::COLS + cell.x; + int v = (cell.y >= 0) ? board[idx] : 0; + SDL_Color baseColor = (v > 0 && v < PIECE_COUNT + 1) ? COLORS[v] : SDL_Color{255, 220, 180, 255}; + float cellX = gridX + (cell.x + 0.5f) * finalBlockSize; + float cellY = gridY + (cell.y + 0.85f) * finalBlockSize + rowDropOffsets[cell.y]; + for (int i = 0; i < 4; ++i) { + ImpactSpark spark; + spark.x = cellX + jitter(s_impactRng); + spark.y = cellY + jitter(s_impactRng) * 0.25f; + spark.vx = velX(s_impactRng); + spark.vy = velY(s_impactRng); + spark.lifeMs = lifespan(s_impactRng); + spark.maxLifeMs = spark.lifeMs; + spark.size = sizeDist(s_impactRng); + spark.color = SDL_Color{ + static_cast(std::min(255, baseColor.r + 30)), + static_cast(std::min(255, baseColor.g + 30)), + static_cast(std::min(255, baseColor.b + 30)), + 255 + }; + s_impactSparks.push_back(spark); + } + } + } + for (int y = 0; y < Game::ROWS; ++y) { - float dropOffset = (lineEffect ? lineEffect->getRowDropOffset(y) : 0.0f); + float dropOffset = rowDropOffsets[y]; for (int x = 0; x < Game::COLS; ++x) { int v = board[y * Game::COLS + x]; if (v > 0) { float bx = gridX + x * finalBlockSize; float by = gridY + y * finalBlockSize + dropOffset; + const int cellIdx = y * Game::COLS + x; + float weight = impactWeight[cellIdx]; + if (impactStrength > 0.0f && weight > 0.0f && impactMask[cellIdx]) { + float cellSeed = static_cast((x * 37 + y * 61) % 113); + float t = static_cast(nowTicks % 10000) * 0.018f + cellSeed; + float amplitude = 6.0f * impactEased * weight; + float freq = 2.0f + weight * 1.3f; + bx += amplitude * std::sin(t * freq); + by += amplitude * 0.75f * std::cos(t * (freq + 1.1f)); + } drawBlockTexture(renderer, blocksTex, bx, by, finalBlockSize, v - 1); } } } + + if (!s_impactSparks.empty()) { + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); + auto it = s_impactSparks.begin(); + while (it != s_impactSparks.end()) { + ImpactSpark& spark = *it; + spark.vy += 0.00045f * sparkDeltaMs; + spark.x += spark.vx * sparkDeltaMs; + spark.y += spark.vy * sparkDeltaMs; + spark.lifeMs -= sparkDeltaMs; + if (spark.lifeMs <= 0.0f) { + it = s_impactSparks.erase(it); + continue; + } + float lifeRatio = spark.lifeMs / spark.maxLifeMs; + Uint8 alpha = static_cast(std::clamp(lifeRatio, 0.0f, 1.0f) * 160.0f); + SDL_SetRenderDrawColor(renderer, spark.color.r, spark.color.g, spark.color.b, alpha); + SDL_FRect sparkRect{ + spark.x - spark.size * 0.5f, + spark.y - spark.size * 0.5f, + spark.size, + spark.size * 1.4f + }; + SDL_RenderFillRect(renderer, &sparkRect); + ++it; + } + } bool allowActivePieceRender = true; const bool smoothScrollEnabled = Settings::instance().isSmoothScrollEnabled(); diff --git a/src/main.cpp b/src/main.cpp index b77bf4e..a79d599 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -807,7 +807,11 @@ int main(int, char **) loadSoundWithFallback("boom_tetris", "boom_tetris"); loadSoundWithFallback("wonderful", "wonderful"); loadSoundWithFallback("lets_go", "lets_go"); // For level up + loadSoundWithFallback("hard_drop", "hard_drop_001"); + loadSoundWithFallback("new_level", "new_level"); + bool suppressLineVoiceForLevelUp = false; + auto playVoiceCue = [&](int linesCleared) { const std::vector* bank = nullptr; switch (linesCleared) { @@ -835,12 +839,16 @@ int main(int, char **) SoundEffectManager::instance().playSound("clear_line", 1.0f); // Layer a voiced callout based on the number of cleared lines - playVoiceCue(linesCleared); + if (!suppressLineVoiceForLevelUp) { + playVoiceCue(linesCleared); + } + suppressLineVoiceForLevelUp = false; }); game.setLevelUpCallback([&](int newLevel) { - // Play level up sound - SoundEffectManager::instance().playSound("lets_go", 1.0f); // Increased volume + SoundEffectManager::instance().playSound("new_level", 1.0f); + SoundEffectManager::instance().playSound("lets_go", 1.0f); // Existing voice line + suppressLineVoiceForLevelUp = true; }); AppState state = AppState::Loading; diff --git a/src/states/PlayingState.cpp b/src/states/PlayingState.cpp index 37ef13e..35e7a0d 100644 --- a/src/states/PlayingState.cpp +++ b/src/states/PlayingState.cpp @@ -4,6 +4,7 @@ #include "../gameplay/effects/LineEffect.h" #include "../persistence/Scores.h" #include "../audio/Audio.h" +#include "../audio/SoundEffect.h" #include "../graphics/renderers/GameRenderer.h" #include "../core/Config.h" #include @@ -115,6 +116,7 @@ void PlayingState::handleEvent(const SDL_Event& e) { // Hard drop (space) if (e.key.scancode == SDL_SCANCODE_SPACE) { + SoundEffectManager::instance().playSound("hard_drop", 0.7f); ctx.game->hardDrop(); return; } @@ -128,6 +130,8 @@ void PlayingState::handleEvent(const SDL_Event& e) { void PlayingState::update(double frameMs) { if (!ctx.game) return; + ctx.game->updateVisualEffects(frameMs); + // forward per-frame gameplay updates (gravity, line effects) if (!ctx.game->isPaused()) { ctx.game->tickGravity(frameMs);