diff --git a/settings.ini b/settings.ini index 200523e..384ce2a 100644 --- a/settings.ini +++ b/settings.ini @@ -12,7 +12,7 @@ Sound=1 SmoothScroll=1 [Player] -Name=GREGOR +Name=PLAYER [Debug] Enabled=1 diff --git a/src/gameplay/core/Game.cpp b/src/gameplay/core/Game.cpp index 8342ce0..ce174db 100644 --- a/src/gameplay/core/Game.cpp +++ b/src/gameplay/core/Game.cpp @@ -64,7 +64,9 @@ void Game::reset(int startLevel_) { _pausedTime = 0; _lastPauseStart = 0; hold = Piece{}; hold.type = PIECE_COUNT; canHold=true; - refillBag(); spawn(); + refillBag(); + pieceSequence = 0; + spawn(); } double Game::elapsed() const { @@ -166,6 +168,7 @@ void Game::spawn() { PieceType nextType = bag.back(); int nextSpawnY = (nextType == I) ? -2 : -1; nextPiece = Piece{ nextType, 0, 3, nextSpawnY }; + ++pieceSequence; } bool Game::cellFilled(const Piece& p, int cx, int cy) { diff --git a/src/gameplay/core/Game.h b/src/gameplay/core/Game.h index 8fd26b1..63774bc 100644 --- a/src/gameplay/core/Game.h +++ b/src/gameplay/core/Game.h @@ -80,6 +80,7 @@ public: double hardDropShakeStrength() const; const std::vector& getHardDropCells() const { return hardDropCells; } uint32_t getHardDropFxId() const { return hardDropFxId; } + uint64_t getCurrentPieceSequence() const { return pieceSequence; } private: std::array board{}; // 0 empty else color index @@ -121,6 +122,7 @@ private: static constexpr double HARD_DROP_SHAKE_DURATION_MS = 320.0; std::vector hardDropCells; uint32_t hardDropFxId{0}; + uint64_t pieceSequence{0}; // Internal helpers ---------------------------------------------------- void refillBag(); diff --git a/src/graphics/renderers/GameRenderer.cpp b/src/graphics/renderers/GameRenderer.cpp index b280d37..52bdd9d 100644 --- a/src/graphics/renderers/GameRenderer.cpp +++ b/src/graphics/renderers/GameRenderer.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,14 @@ struct ImpactSpark { float size = 0.0f; SDL_Color color{255, 255, 255, 255}; }; + +struct ActivePieceSmoothState { + uint64_t sequence = 0; + float visualX = 0.0f; + bool initialized = false; +}; + +ActivePieceSmoothState s_activePieceSmooth; } // Color constants (copied from main.cpp) @@ -62,13 +71,13 @@ void GameRenderer::drawBlockTexture(SDL_Renderer* renderer, SDL_Texture* blocksT SDL_RenderTexture(renderer, blocksTex, &srcRect, &dstRect); } -void GameRenderer::drawPiece(SDL_Renderer* renderer, SDL_Texture* blocksTex, const Game::Piece& piece, float ox, float oy, float tileSize, bool isGhost, float pixelOffsetY) { +void GameRenderer::drawPiece(SDL_Renderer* renderer, SDL_Texture* blocksTex, const Game::Piece& piece, float ox, float oy, float tileSize, bool isGhost, float pixelOffsetX, float pixelOffsetY) { if (piece.type >= PIECE_COUNT) return; for (int cy = 0; cy < 4; ++cy) { for (int cx = 0; cx < 4; ++cx) { if (Game::cellFilled(piece, cx, cy)) { - float px = ox + (piece.x + cx) * tileSize; + float px = ox + (piece.x + cx) * tileSize + pixelOffsetX; float py = oy + (piece.y + cy) * tileSize + pixelOffsetY; if (isGhost) { @@ -380,6 +389,28 @@ void GameRenderer::renderPlayingState( bool allowActivePieceRender = true; const bool smoothScrollEnabled = Settings::instance().isSmoothScrollEnabled(); + float activePiecePixelOffsetX = 0.0f; + if (allowActivePieceRender) { + if (smoothScrollEnabled && !game->isPaused()) { + const uint64_t pieceSeq = game->getCurrentPieceSequence(); + if (!s_activePieceSmooth.initialized || s_activePieceSmooth.sequence != pieceSeq) { + s_activePieceSmooth.sequence = pieceSeq; + s_activePieceSmooth.visualX = static_cast(game->current().x); + s_activePieceSmooth.initialized = true; + } + + const float targetX = static_cast(game->current().x); + constexpr float HORIZONTAL_SMOOTH_MS = 55.0f; + const float lerpFactor = std::clamp(sparkDeltaMs / HORIZONTAL_SMOOTH_MS, 0.0f, 1.0f); + s_activePieceSmooth.visualX = std::lerp(s_activePieceSmooth.visualX, targetX, lerpFactor); + activePiecePixelOffsetX = (s_activePieceSmooth.visualX - targetX) * finalBlockSize; + } else { + s_activePieceSmooth.sequence = game->getCurrentPieceSequence(); + s_activePieceSmooth.visualX = static_cast(game->current().x); + s_activePieceSmooth.initialized = true; + } + } + auto computeFallOffset = [&]() -> float { if (game->isPaused()) { return 0.0f; @@ -398,8 +429,8 @@ void GameRenderer::renderPlayingState( return progress * finalBlockSize; }; - float activePieceOffset = (!game->isPaused() && smoothScrollEnabled) ? computeFallOffset() : 0.0f; - if (activePieceOffset > 0.0f) { + float activePiecePixelOffsetY = (!game->isPaused() && smoothScrollEnabled) ? computeFallOffset() : 0.0f; + if (activePiecePixelOffsetY > 0.0f) { const auto& boardRef = game->boardRef(); const Game::Piece& piece = game->current(); float maxAllowed = finalBlockSize; @@ -430,7 +461,7 @@ void GameRenderer::renderPlayingState( maxAllowed = std::min(maxAllowed, cellLimit); } } - activePieceOffset = std::min(activePieceOffset, maxAllowed); + activePiecePixelOffsetY = std::min(activePiecePixelOffsetY, maxAllowed); } // Draw ghost piece (where current piece will land) @@ -468,7 +499,7 @@ void GameRenderer::renderPlayingState( // Draw the falling piece if (allowActivePieceRender) { - drawPiece(renderer, blocksTex, game->current(), gridX, gridY, finalBlockSize, false, activePieceOffset); + drawPiece(renderer, blocksTex, game->current(), gridX, gridY, finalBlockSize, false, activePiecePixelOffsetX, activePiecePixelOffsetY); } // Draw line clearing effects diff --git a/src/graphics/renderers/GameRenderer.h b/src/graphics/renderers/GameRenderer.h index 77e55a2..96422cf 100644 --- a/src/graphics/renderers/GameRenderer.h +++ b/src/graphics/renderers/GameRenderer.h @@ -50,7 +50,7 @@ public: private: // Helper functions for drawing game elements static void drawBlockTexture(SDL_Renderer* renderer, SDL_Texture* blocksTex, float x, float y, float size, int blockType); - static void drawPiece(SDL_Renderer* renderer, SDL_Texture* blocksTex, const Game::Piece& piece, float ox, float oy, float tileSize, bool isGhost = false, float pixelOffsetY = 0.0f); + static void drawPiece(SDL_Renderer* renderer, SDL_Texture* blocksTex, const Game::Piece& piece, float ox, float oy, float tileSize, bool isGhost = false, float pixelOffsetX = 0.0f, float pixelOffsetY = 0.0f); static void drawSmallPiece(SDL_Renderer* renderer, SDL_Texture* blocksTex, PieceType pieceType, float x, float y, float tileSize); // Helper function for drawing rectangles