added clear line effect
This commit is contained in:
@ -188,10 +188,11 @@ void LineEffect::initAudio() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineEffect::startLineClear(const std::vector<int>& rows, int gridX, int gridY, int blockSize) {
|
void LineEffect::startLineClear(const std::vector<int>& rows, int gridX, int gridY, int blockSize, int gridCols) {
|
||||||
if (rows.empty()) return;
|
if (rows.empty()) return;
|
||||||
|
|
||||||
clearingRows = rows;
|
clearingRows = rows;
|
||||||
|
effectGridCols = std::max(1, gridCols);
|
||||||
state = AnimationState::FLASH_WHITE;
|
state = AnimationState::FLASH_WHITE;
|
||||||
timer = 0.0f;
|
timer = 0.0f;
|
||||||
dropProgress = 0.0f;
|
dropProgress = 0.0f;
|
||||||
@ -228,7 +229,7 @@ void LineEffect::startLineClear(const std::vector<int>& rows, int gridX, int gri
|
|||||||
|
|
||||||
void LineEffect::createParticles(int row, int gridX, int gridY, int blockSize) {
|
void LineEffect::createParticles(int row, int gridX, int gridY, int blockSize) {
|
||||||
const float centerY = gridY + row * blockSize + blockSize * 0.5f;
|
const float centerY = gridY + row * blockSize + blockSize * 0.5f;
|
||||||
for (int col = 0; col < Game::COLS; ++col) {
|
for (int col = 0; col < effectGridCols; ++col) {
|
||||||
float centerX = gridX + col * blockSize + blockSize * 0.5f;
|
float centerX = gridX + col * blockSize + blockSize * 0.5f;
|
||||||
SDL_Color tint = pickFireColor();
|
SDL_Color tint = pickFireColor();
|
||||||
spawnGlowPulse(centerX, centerY, static_cast<float>(blockSize), tint);
|
spawnGlowPulse(centerX, centerY, static_cast<float>(blockSize), tint);
|
||||||
@ -386,7 +387,7 @@ void LineEffect::renderFlash(int gridX, int gridY, int blockSize) {
|
|||||||
SDL_FRect flashRect = {
|
SDL_FRect flashRect = {
|
||||||
static_cast<float>(gridX - 4),
|
static_cast<float>(gridX - 4),
|
||||||
static_cast<float>(gridY + row * blockSize - 4),
|
static_cast<float>(gridY + row * blockSize - 4),
|
||||||
static_cast<float>(10 * blockSize + 8),
|
static_cast<float>(effectGridCols * blockSize + 8),
|
||||||
static_cast<float>(blockSize + 8)
|
static_cast<float>(blockSize + 8)
|
||||||
};
|
};
|
||||||
SDL_RenderFillRect(renderer, &flashRect);
|
SDL_RenderFillRect(renderer, &flashRect);
|
||||||
|
|||||||
@ -69,7 +69,7 @@ public:
|
|||||||
void shutdown();
|
void shutdown();
|
||||||
|
|
||||||
// Start line clear effect for the specified rows
|
// Start line clear effect for the specified rows
|
||||||
void startLineClear(const std::vector<int>& rows, int gridX, int gridY, int blockSize);
|
void startLineClear(const std::vector<int>& rows, int gridX, int gridY, int blockSize, int gridCols = Game::COLS);
|
||||||
|
|
||||||
// Update and render the effect
|
// Update and render the effect
|
||||||
bool update(float deltaTime); // Returns true if effect is complete
|
bool update(float deltaTime); // Returns true if effect is complete
|
||||||
@ -120,4 +120,5 @@ private:
|
|||||||
std::array<float, Game::ROWS> rowDropTargets{};
|
std::array<float, Game::ROWS> rowDropTargets{};
|
||||||
float dropProgress = 0.0f;
|
float dropProgress = 0.0f;
|
||||||
int dropBlockSize = 0;
|
int dropBlockSize = 0;
|
||||||
|
int effectGridCols = Game::COLS;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1926,12 +1926,18 @@ void GameRenderer::renderCoopPlayingState(
|
|||||||
// Handle line clearing effects (defer to LineEffect like single-player)
|
// Handle line clearing effects (defer to LineEffect like single-player)
|
||||||
if (game->hasCompletedLines() && lineEffect && !lineEffect->isActive()) {
|
if (game->hasCompletedLines() && lineEffect && !lineEffect->isActive()) {
|
||||||
auto completedLines = game->getCompletedLines();
|
auto completedLines = game->getCompletedLines();
|
||||||
lineEffect->startLineClear(completedLines, static_cast<int>(gridX), static_cast<int>(gridY), static_cast<int>(finalBlockSize));
|
lineEffect->startLineClear(completedLines, static_cast<int>(gridX), static_cast<int>(gridY), static_cast<int>(finalBlockSize), CoopGame::COLS);
|
||||||
if (completedLines.size() == 4) {
|
if (completedLines.size() == 4) {
|
||||||
AppFireworks::spawn(gridX + GRID_W * 0.5f, gridY + GRID_H * 0.5f);
|
AppFireworks::spawn(gridX + GRID_W * 0.5f, gridY + GRID_H * 0.5f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Precompute row drop offsets (line collapse effect)
|
||||||
|
std::array<float, CoopGame::ROWS> rowDropOffsets{};
|
||||||
|
for (int y = 0; y < CoopGame::ROWS; ++y) {
|
||||||
|
rowDropOffsets[y] = (lineEffect ? lineEffect->getRowDropOffset(y) : 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
// Grid backdrop and border
|
// Grid backdrop and border
|
||||||
drawRectWithOffset(gridX - 3 - contentOffsetX, gridY - 3 - contentOffsetY, GRID_W + 6, GRID_H + 6, {100, 120, 200, 255});
|
drawRectWithOffset(gridX - 3 - contentOffsetX, gridY - 3 - contentOffsetY, GRID_W + 6, GRID_H + 6, {100, 120, 200, 255});
|
||||||
drawRectWithOffset(gridX - contentOffsetX, gridY - contentOffsetY, GRID_W, GRID_H, {20, 25, 35, 255});
|
drawRectWithOffset(gridX - contentOffsetX, gridY - contentOffsetY, GRID_W, GRID_H, {20, 25, 35, 255});
|
||||||
@ -1980,11 +1986,12 @@ void GameRenderer::renderCoopPlayingState(
|
|||||||
// Draw settled blocks
|
// Draw settled blocks
|
||||||
const auto& board = game->boardRef();
|
const auto& board = game->boardRef();
|
||||||
for (int y = 0; y < CoopGame::ROWS; ++y) {
|
for (int y = 0; y < CoopGame::ROWS; ++y) {
|
||||||
|
float dropOffset = rowDropOffsets[y];
|
||||||
for (int x = 0; x < CoopGame::COLS; ++x) {
|
for (int x = 0; x < CoopGame::COLS; ++x) {
|
||||||
const auto& cell = board[y * CoopGame::COLS + x];
|
const auto& cell = board[y * CoopGame::COLS + x];
|
||||||
if (!cell.occupied || cell.value <= 0) continue;
|
if (!cell.occupied || cell.value <= 0) continue;
|
||||||
float px = gridX + x * finalBlockSize;
|
float px = gridX + x * finalBlockSize;
|
||||||
float py = gridY + y * finalBlockSize;
|
float py = gridY + y * finalBlockSize + dropOffset;
|
||||||
drawBlockTexturePublic(renderer, blocksTex, px, py, finalBlockSize, cell.value - 1);
|
drawBlockTexturePublic(renderer, blocksTex, px, py, finalBlockSize, cell.value - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2012,7 +2019,20 @@ void GameRenderer::renderCoopPlayingState(
|
|||||||
sf.tileSize = finalBlockSize;
|
sf.tileSize = finalBlockSize;
|
||||||
// Target to first visible row (row 0)
|
// Target to first visible row (row 0)
|
||||||
sf.targetX = gridX + static_cast<float>(sf.piece.x) * finalBlockSize;
|
sf.targetX = gridX + static_cast<float>(sf.piece.x) * finalBlockSize;
|
||||||
sf.targetY = gridY + 0.0f * finalBlockSize;
|
// IMPORTANT: In classic mode, pieces can spawn with their first filled
|
||||||
|
// cell not at cy=0 within the 4x4. To avoid appearing one row too low
|
||||||
|
// (and then jumping up), align the topmost filled cell to row 0.
|
||||||
|
int minCy = 4;
|
||||||
|
for (int cy = 0; cy < 4; ++cy) {
|
||||||
|
for (int cx = 0; cx < 4; ++cx) {
|
||||||
|
if (!CoopGame::cellFilled(sf.piece, cx, cy)) continue;
|
||||||
|
minCy = std::min(minCy, cy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (minCy == 4) {
|
||||||
|
minCy = 0;
|
||||||
|
}
|
||||||
|
sf.targetY = gridY - static_cast<float>(minCy) * finalBlockSize;
|
||||||
} else {
|
} else {
|
||||||
// Reuse exact horizontal smoothing from single-player
|
// Reuse exact horizontal smoothing from single-player
|
||||||
constexpr float HORIZONTAL_SMOOTH_MS = 55.0f;
|
constexpr float HORIZONTAL_SMOOTH_MS = 55.0f;
|
||||||
@ -2177,6 +2197,11 @@ void GameRenderer::renderCoopPlayingState(
|
|||||||
drawPiece(game->current(CoopGame::PlayerSide::Right), rightOffsets, false);
|
drawPiece(game->current(CoopGame::PlayerSide::Right), rightOffsets, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw line clearing effects above pieces (matches single-player)
|
||||||
|
if (lineEffect && lineEffect->isActive()) {
|
||||||
|
lineEffect->render(renderer, blocksTex, static_cast<int>(gridX), static_cast<int>(gridY), static_cast<int>(finalBlockSize));
|
||||||
|
}
|
||||||
|
|
||||||
// Next panels (two)
|
// Next panels (two)
|
||||||
const float nextPanelPad = 12.0f;
|
const float nextPanelPad = 12.0f;
|
||||||
const float nextPanelW = (GRID_W * 0.5f) - finalBlockSize * 1.5f;
|
const float nextPanelW = (GRID_W * 0.5f) - finalBlockSize * 1.5f;
|
||||||
|
|||||||
Reference in New Issue
Block a user