From 8279ccbe6db14e7655a56a20476464596136bfd8 Mon Sep 17 00:00:00 2001 From: Gregor Klevze Date: Sun, 30 Nov 2025 08:17:34 +0100 Subject: [PATCH] Line drop by pixel --- src/gameplay/effects/LineEffect.cpp | 38 +++++++++++++++++++++++++ src/gameplay/effects/LineEffect.h | 10 ++++++- src/graphics/renderers/GameRenderer.cpp | 3 +- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/gameplay/effects/LineEffect.cpp b/src/gameplay/effects/LineEffect.cpp index 21a9e08..e918210 100644 --- a/src/gameplay/effects/LineEffect.cpp +++ b/src/gameplay/effects/LineEffect.cpp @@ -194,9 +194,28 @@ void LineEffect::startLineClear(const std::vector& rows, int gridX, int gri clearingRows = rows; state = AnimationState::FLASH_WHITE; timer = 0.0f; + dropProgress = 0.0f; + dropBlockSize = blockSize; + rowDropTargets.fill(0.0f); particles.clear(); sparks.clear(); glowPulses.clear(); + + std::array rowClearing{}; + for (int row : rows) { + if (row >= 0 && row < Game::ROWS) { + rowClearing[row] = true; + } + } + + int clearedBelow = 0; + for (int row = Game::ROWS - 1; row >= 0; --row) { + if (rowClearing[row]) { + ++clearedBelow; + } else if (clearedBelow > 0) { + rowDropTargets[row] = static_cast(clearedBelow * blockSize); + } + } // Create particles for each clearing row for (int row : rows) { @@ -267,12 +286,16 @@ bool LineEffect::update(float deltaTime) { updateParticles(deltaTime); updateSparks(deltaTime); updateGlowPulses(deltaTime); + dropProgress = std::min(1.0f, timer / DROP_DURATION); if (timer >= DROP_DURATION) { state = AnimationState::IDLE; clearingRows.clear(); particles.clear(); sparks.clear(); glowPulses.clear(); + rowDropTargets.fill(0.0f); + dropProgress = 0.0f; + dropBlockSize = 0; return true; // Effect complete } break; @@ -335,6 +358,21 @@ void LineEffect::render(SDL_Renderer* renderer, SDL_Texture* blocksTex, int grid } } +float LineEffect::getRowDropOffset(int row) const { + if (state != AnimationState::BLOCKS_DROP) { + return 0.0f; + } + if (row < 0 || row >= Game::ROWS) { + return 0.0f; + } + float target = rowDropTargets[row]; + if (target <= 0.0f) { + return 0.0f; + } + float eased = dropProgress * dropProgress * dropProgress; + return target * eased; +} + void LineEffect::renderFlash(int gridX, int gridY, int blockSize) { // Create a flashing white effect with varying opacity float progress = timer / FLASH_DURATION; diff --git a/src/gameplay/effects/LineEffect.h b/src/gameplay/effects/LineEffect.h index 63c1ba1..99834ab 100644 --- a/src/gameplay/effects/LineEffect.h +++ b/src/gameplay/effects/LineEffect.h @@ -3,6 +3,9 @@ #include #include #include +#include + +#include "../core/Game.h" class LineEffect { public: @@ -71,6 +74,7 @@ public: // Update and render the effect bool update(float deltaTime); // Returns true if effect is complete void render(SDL_Renderer* renderer, SDL_Texture* blocksTex, int gridX, int gridY, int blockSize); + float getRowDropOffset(int row) const; // Audio void playLineClearSound(int lineCount); @@ -95,7 +99,7 @@ private: // Animation timing - Flash then immediate explosion effect static constexpr float FLASH_DURATION = 0.18f; // Slightly longer flash for anticipation static constexpr float EXPLODE_DURATION = 0.9f; // Extended fireworks time - static constexpr float DROP_DURATION = 0.20f; // Allow lingering sparks before collapse + static constexpr float DROP_DURATION = 0.35f; // Allow lingering sparks before collapse void createParticles(int row, int gridX, int gridY, int blockSize); void spawnShardBurst(float x, float y, SDL_Color tint); @@ -112,4 +116,8 @@ private: bool loadAudioSample(const std::string& path, std::vector& sample); void initAudio(); SDL_Color pickFireColor() const; + + std::array rowDropTargets{}; + float dropProgress = 0.0f; + int dropBlockSize = 0; }; diff --git a/src/graphics/renderers/GameRenderer.cpp b/src/graphics/renderers/GameRenderer.cpp index 50b0c54..5cb8de6 100644 --- a/src/graphics/renderers/GameRenderer.cpp +++ b/src/graphics/renderers/GameRenderer.cpp @@ -226,11 +226,12 @@ void GameRenderer::renderPlayingState( // Draw the game board const auto &board = game->boardRef(); for (int y = 0; y < Game::ROWS; ++y) { + float dropOffset = (lineEffect ? lineEffect->getRowDropOffset(y) : 0.0f); 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; + float by = gridY + y * finalBlockSize + dropOffset; drawBlockTexture(renderer, blocksTex, bx, by, finalBlockSize, v - 1); } }