smooth scroll left / right
This commit is contained in:
@ -12,7 +12,7 @@ Sound=1
|
|||||||
SmoothScroll=1
|
SmoothScroll=1
|
||||||
|
|
||||||
[Player]
|
[Player]
|
||||||
Name=GREGOR
|
Name=PLAYER
|
||||||
|
|
||||||
[Debug]
|
[Debug]
|
||||||
Enabled=1
|
Enabled=1
|
||||||
|
|||||||
@ -64,7 +64,9 @@ void Game::reset(int startLevel_) {
|
|||||||
_pausedTime = 0;
|
_pausedTime = 0;
|
||||||
_lastPauseStart = 0;
|
_lastPauseStart = 0;
|
||||||
hold = Piece{}; hold.type = PIECE_COUNT; canHold=true;
|
hold = Piece{}; hold.type = PIECE_COUNT; canHold=true;
|
||||||
refillBag(); spawn();
|
refillBag();
|
||||||
|
pieceSequence = 0;
|
||||||
|
spawn();
|
||||||
}
|
}
|
||||||
|
|
||||||
double Game::elapsed() const {
|
double Game::elapsed() const {
|
||||||
@ -166,6 +168,7 @@ void Game::spawn() {
|
|||||||
PieceType nextType = bag.back();
|
PieceType nextType = bag.back();
|
||||||
int nextSpawnY = (nextType == I) ? -2 : -1;
|
int nextSpawnY = (nextType == I) ? -2 : -1;
|
||||||
nextPiece = Piece{ nextType, 0, 3, nextSpawnY };
|
nextPiece = Piece{ nextType, 0, 3, nextSpawnY };
|
||||||
|
++pieceSequence;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Game::cellFilled(const Piece& p, int cx, int cy) {
|
bool Game::cellFilled(const Piece& p, int cx, int cy) {
|
||||||
|
|||||||
@ -80,6 +80,7 @@ public:
|
|||||||
double hardDropShakeStrength() const;
|
double hardDropShakeStrength() const;
|
||||||
const std::vector<SDL_Point>& getHardDropCells() const { return hardDropCells; }
|
const std::vector<SDL_Point>& getHardDropCells() const { return hardDropCells; }
|
||||||
uint32_t getHardDropFxId() const { return hardDropFxId; }
|
uint32_t getHardDropFxId() const { return hardDropFxId; }
|
||||||
|
uint64_t getCurrentPieceSequence() const { return pieceSequence; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::array<int, COLS*ROWS> board{}; // 0 empty else color index
|
std::array<int, COLS*ROWS> board{}; // 0 empty else color index
|
||||||
@ -121,6 +122,7 @@ private:
|
|||||||
static constexpr double HARD_DROP_SHAKE_DURATION_MS = 320.0;
|
static constexpr double HARD_DROP_SHAKE_DURATION_MS = 320.0;
|
||||||
std::vector<SDL_Point> hardDropCells;
|
std::vector<SDL_Point> hardDropCells;
|
||||||
uint32_t hardDropFxId{0};
|
uint32_t hardDropFxId{0};
|
||||||
|
uint64_t pieceSequence{0};
|
||||||
|
|
||||||
// Internal helpers ----------------------------------------------------
|
// Internal helpers ----------------------------------------------------
|
||||||
void refillBag();
|
void refillBag();
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -21,6 +22,14 @@ struct ImpactSpark {
|
|||||||
float size = 0.0f;
|
float size = 0.0f;
|
||||||
SDL_Color color{255, 255, 255, 255};
|
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)
|
// 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);
|
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;
|
if (piece.type >= PIECE_COUNT) return;
|
||||||
|
|
||||||
for (int cy = 0; cy < 4; ++cy) {
|
for (int cy = 0; cy < 4; ++cy) {
|
||||||
for (int cx = 0; cx < 4; ++cx) {
|
for (int cx = 0; cx < 4; ++cx) {
|
||||||
if (Game::cellFilled(piece, cx, cy)) {
|
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;
|
float py = oy + (piece.y + cy) * tileSize + pixelOffsetY;
|
||||||
|
|
||||||
if (isGhost) {
|
if (isGhost) {
|
||||||
@ -380,6 +389,28 @@ void GameRenderer::renderPlayingState(
|
|||||||
bool allowActivePieceRender = true;
|
bool allowActivePieceRender = true;
|
||||||
const bool smoothScrollEnabled = Settings::instance().isSmoothScrollEnabled();
|
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<float>(game->current().x);
|
||||||
|
s_activePieceSmooth.initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float targetX = static_cast<float>(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<float>(game->current().x);
|
||||||
|
s_activePieceSmooth.initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto computeFallOffset = [&]() -> float {
|
auto computeFallOffset = [&]() -> float {
|
||||||
if (game->isPaused()) {
|
if (game->isPaused()) {
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
@ -398,8 +429,8 @@ void GameRenderer::renderPlayingState(
|
|||||||
return progress * finalBlockSize;
|
return progress * finalBlockSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
float activePieceOffset = (!game->isPaused() && smoothScrollEnabled) ? computeFallOffset() : 0.0f;
|
float activePiecePixelOffsetY = (!game->isPaused() && smoothScrollEnabled) ? computeFallOffset() : 0.0f;
|
||||||
if (activePieceOffset > 0.0f) {
|
if (activePiecePixelOffsetY > 0.0f) {
|
||||||
const auto& boardRef = game->boardRef();
|
const auto& boardRef = game->boardRef();
|
||||||
const Game::Piece& piece = game->current();
|
const Game::Piece& piece = game->current();
|
||||||
float maxAllowed = finalBlockSize;
|
float maxAllowed = finalBlockSize;
|
||||||
@ -430,7 +461,7 @@ void GameRenderer::renderPlayingState(
|
|||||||
maxAllowed = std::min(maxAllowed, cellLimit);
|
maxAllowed = std::min(maxAllowed, cellLimit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
activePieceOffset = std::min(activePieceOffset, maxAllowed);
|
activePiecePixelOffsetY = std::min(activePiecePixelOffsetY, maxAllowed);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw ghost piece (where current piece will land)
|
// Draw ghost piece (where current piece will land)
|
||||||
@ -468,7 +499,7 @@ void GameRenderer::renderPlayingState(
|
|||||||
|
|
||||||
// Draw the falling piece
|
// Draw the falling piece
|
||||||
if (allowActivePieceRender) {
|
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
|
// Draw line clearing effects
|
||||||
|
|||||||
@ -50,7 +50,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
// Helper functions for drawing game elements
|
// 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 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);
|
static void drawSmallPiece(SDL_Renderer* renderer, SDL_Texture* blocksTex, PieceType pieceType, float x, float y, float tileSize);
|
||||||
|
|
||||||
// Helper function for drawing rectangles
|
// Helper function for drawing rectangles
|
||||||
|
|||||||
Reference in New Issue
Block a user