fixed I block in coop mode
This commit is contained in:
@ -2282,22 +2282,10 @@ void GameRenderer::renderCoopPlayingState(
|
|||||||
sf.seq = seq;
|
sf.seq = seq;
|
||||||
sf.piece = game->current(side);
|
sf.piece = game->current(side);
|
||||||
sf.tileSize = finalBlockSize;
|
sf.tileSize = finalBlockSize;
|
||||||
// Target to first visible row (row 0)
|
// Note: targetX/targetY are recomputed during drawing using the live
|
||||||
|
// current piece so movement/rotation during the fade stays correct.
|
||||||
sf.targetX = gridX + static_cast<float>(sf.piece.x) * finalBlockSize;
|
sf.targetX = gridX + static_cast<float>(sf.piece.x) * finalBlockSize;
|
||||||
// IMPORTANT: In classic mode, pieces can spawn with their first filled
|
sf.targetY = gridY;
|
||||||
// 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;
|
||||||
@ -2373,24 +2361,54 @@ void GameRenderer::renderCoopPlayingState(
|
|||||||
// Draw any active spawn fades (alpha ramp into first row). Draw before
|
// Draw any active spawn fades (alpha ramp into first row). Draw before
|
||||||
// the regular active pieces; while the spawn fade is active the piece's
|
// the regular active pieces; while the spawn fade is active the piece's
|
||||||
// real position is above the grid and will not be drawn by drawPiece.
|
// real position is above the grid and will not be drawn by drawPiece.
|
||||||
auto drawSpawnFadeIfActive = [&](SpawnFadeState &sf) {
|
auto drawSpawnFadeIfActive = [&](SpawnFadeState &sf, CoopGame::PlayerSide side) {
|
||||||
if (!sf.active) return;
|
if (!sf.active) return;
|
||||||
Uint32 now = SDL_GetTicks();
|
|
||||||
float elapsed = static_cast<float>(now - sf.startTick);
|
// If the piece has already changed, stop the fade.
|
||||||
|
const uint64_t currentSeq = game->currentPieceSequence(side);
|
||||||
|
if (sf.seq != currentSeq) {
|
||||||
|
sf.active = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CoopGame::Piece& livePiece = game->current(side);
|
||||||
|
float elapsed = static_cast<float>(nowTicks - sf.startTick);
|
||||||
float t = sf.durationMs <= 0.0f ? 1.0f : std::clamp(elapsed / sf.durationMs, 0.0f, 1.0f);
|
float t = sf.durationMs <= 0.0f ? 1.0f : std::clamp(elapsed / sf.durationMs, 0.0f, 1.0f);
|
||||||
Uint8 alpha = static_cast<Uint8>(std::lround(255.0f * t));
|
Uint8 alpha = static_cast<Uint8>(std::lround(255.0f * t));
|
||||||
if (blocksTex) SDL_SetTextureAlphaMod(blocksTex, alpha);
|
if (blocksTex) SDL_SetTextureAlphaMod(blocksTex, alpha);
|
||||||
// Draw piece at target (first row)
|
|
||||||
|
// Align the topmost filled cell to row 0 (first visible row), like classic.
|
||||||
|
int minCy = 4;
|
||||||
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 (!CoopGame::cellFilled(sf.piece, cx, cy)) continue;
|
if (!CoopGame::cellFilled(livePiece, cx, cy)) continue;
|
||||||
|
minCy = std::min(minCy, cy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (minCy == 4) {
|
||||||
|
minCy = 0;
|
||||||
|
}
|
||||||
|
sf.targetX = gridX + static_cast<float>(livePiece.x) * sf.tileSize;
|
||||||
|
sf.targetY = gridY - static_cast<float>(minCy) * sf.tileSize;
|
||||||
|
|
||||||
|
// Draw the live piece at the fade target.
|
||||||
|
for (int cy = 0; cy < 4; ++cy) {
|
||||||
|
for (int cx = 0; cx < 4; ++cx) {
|
||||||
|
if (!CoopGame::cellFilled(livePiece, cx, cy)) continue;
|
||||||
float px = sf.targetX + static_cast<float>(cx) * sf.tileSize;
|
float px = sf.targetX + static_cast<float>(cx) * sf.tileSize;
|
||||||
float py = sf.targetY + static_cast<float>(cy) * sf.tileSize;
|
float py = sf.targetY + static_cast<float>(cy) * sf.tileSize;
|
||||||
drawBlockTexturePublic(renderer, blocksTex, px, py, sf.tileSize, sf.piece.type);
|
drawBlockTexturePublic(renderer, blocksTex, px, py, sf.tileSize, livePiece.type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (blocksTex) SDL_SetTextureAlphaMod(blocksTex, 255);
|
if (blocksTex) SDL_SetTextureAlphaMod(blocksTex, 255);
|
||||||
if (t >= 1.0f) sf.active = false;
|
|
||||||
|
// Critical: only deactivate once the real piece is actually drawable.
|
||||||
|
// Otherwise (notably for I spawning at y=-2) there can be a brief gap where
|
||||||
|
// the fade ends but the real piece is still fully above the visible grid.
|
||||||
|
const bool pieceHasAnyVisibleCell = (livePiece.y + minCy) >= 0;
|
||||||
|
if (t >= 1.0f && pieceHasAnyVisibleCell) {
|
||||||
|
sf.active = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
auto drawPiece = [&](const CoopGame::Piece& p, const std::pair<float, float>& offsets, bool isGhost) {
|
auto drawPiece = [&](const CoopGame::Piece& p, const std::pair<float, float>& offsets, bool isGhost) {
|
||||||
@ -2419,8 +2437,8 @@ void GameRenderer::renderCoopPlayingState(
|
|||||||
const auto leftOffsets = computeOffsets(CoopGame::PlayerSide::Left, s_leftSmooth);
|
const auto leftOffsets = computeOffsets(CoopGame::PlayerSide::Left, s_leftSmooth);
|
||||||
const auto rightOffsets = computeOffsets(CoopGame::PlayerSide::Right, s_rightSmooth);
|
const auto rightOffsets = computeOffsets(CoopGame::PlayerSide::Right, s_rightSmooth);
|
||||||
// Draw transient spawn fades (if active) into the first visible row
|
// Draw transient spawn fades (if active) into the first visible row
|
||||||
drawSpawnFadeIfActive(s_leftSpawnFade);
|
drawSpawnFadeIfActive(s_leftSpawnFade, CoopGame::PlayerSide::Left);
|
||||||
drawSpawnFadeIfActive(s_rightSpawnFade);
|
drawSpawnFadeIfActive(s_rightSpawnFade, CoopGame::PlayerSide::Right);
|
||||||
|
|
||||||
// Draw classic-style ghost pieces (landing position), grid-aligned.
|
// Draw classic-style ghost pieces (landing position), grid-aligned.
|
||||||
// This intentionally does NOT use smoothing offsets.
|
// This intentionally does NOT use smoothing offsets.
|
||||||
|
|||||||
Reference in New Issue
Block a user