fixed i block
This commit is contained in:
@ -1864,7 +1864,7 @@ void GameRenderer::renderCoopPlayingState(
|
||||
struct SmoothState { bool initialized{false}; uint64_t seq{0}; float visualX{0.0f}; float visualY{0.0f}; };
|
||||
static SmoothState s_leftSmooth{};
|
||||
static SmoothState s_rightSmooth{};
|
||||
struct SpawnFadeState { bool active{false}; uint64_t seq{0}; Uint32 startTick{0}; float durationMs{200.0f}; CoopGame::Piece piece; float targetX{0.0f}; float targetY{0.0f}; float tileSize{0.0f}; };
|
||||
struct SpawnFadeState { bool active{false}; uint64_t seq{0}; Uint32 startTick{0}; float durationMs{200.0f}; CoopGame::Piece piece; int spawnY{0}; float targetX{0.0f}; float targetY{0.0f}; float tileSize{0.0f}; };
|
||||
static SpawnFadeState s_leftSpawnFade{};
|
||||
static SpawnFadeState s_rightSpawnFade{};
|
||||
|
||||
@ -2281,11 +2281,15 @@ void GameRenderer::renderCoopPlayingState(
|
||||
sf.durationMs = 200.0f;
|
||||
sf.seq = seq;
|
||||
sf.piece = game->current(side);
|
||||
sf.spawnY = sf.piece.y;
|
||||
sf.tileSize = finalBlockSize;
|
||||
// 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.targetY = gridY;
|
||||
// Note: during the spawn fade we draw the live piece each frame.
|
||||
// If the piece is still above the visible grid, we temporarily pin
|
||||
// it so the topmost filled cell appears at row 0 (no spawn delay),
|
||||
// while still applying smoothing offsets so it starts moving
|
||||
// immediately.
|
||||
sf.targetX = 0.0f;
|
||||
sf.targetY = 0.0f;
|
||||
} else {
|
||||
// Reuse exact horizontal smoothing from single-player
|
||||
constexpr float HORIZONTAL_SMOOTH_MS = 55.0f;
|
||||
@ -2358,10 +2362,7 @@ void GameRenderer::renderCoopPlayingState(
|
||||
return std::pair<float, float>{ offsetX, offsetY };
|
||||
};
|
||||
|
||||
// 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
|
||||
// real position is above the grid and will not be drawn by drawPiece.
|
||||
auto drawSpawnFadeIfActive = [&](SpawnFadeState &sf, CoopGame::PlayerSide side) {
|
||||
auto drawSpawnFadeIfActive = [&](SpawnFadeState &sf, CoopGame::PlayerSide side, const std::pair<float, float>& offsets) {
|
||||
if (!sf.active) return;
|
||||
|
||||
// If the piece has already changed, stop the fade.
|
||||
@ -2377,36 +2378,56 @@ void GameRenderer::renderCoopPlayingState(
|
||||
Uint8 alpha = static_cast<Uint8>(std::lround(255.0f * t));
|
||||
if (blocksTex) SDL_SetTextureAlphaMod(blocksTex, alpha);
|
||||
|
||||
// Align the topmost filled cell to row 0 (first visible row), like classic.
|
||||
int minCy = 4;
|
||||
int maxCy = -1;
|
||||
for (int cy = 0; cy < 4; ++cy) {
|
||||
for (int cx = 0; cx < 4; ++cx) {
|
||||
if (!CoopGame::cellFilled(livePiece, cx, cy)) continue;
|
||||
minCy = std::min(minCy, cy);
|
||||
maxCy = std::max(maxCy, 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;
|
||||
if (maxCy < 0) {
|
||||
maxCy = 0;
|
||||
}
|
||||
|
||||
// Draw the live piece at the fade target.
|
||||
// Pin only when *no* filled cell is visible yet. Using maxCy avoids pinning
|
||||
// cases like vertical I where some blocks are already visible at spawn.
|
||||
const bool pinToFirstVisibleRow = (livePiece.y + maxCy) < 0;
|
||||
|
||||
const float baseX = gridX + static_cast<float>(livePiece.x) * sf.tileSize + offsets.first;
|
||||
float baseY = 0.0f;
|
||||
if (pinToFirstVisibleRow) {
|
||||
// Keep the piece visible (topmost filled cell at row 0), but also
|
||||
// incorporate real y-step progression so the fall accumulator wrapping
|
||||
// doesn't produce a one-row snap.
|
||||
const int dySteps = livePiece.y - sf.spawnY;
|
||||
baseY = (gridY - static_cast<float>(minCy) * sf.tileSize)
|
||||
+ static_cast<float>(dySteps) * sf.tileSize
|
||||
+ offsets.second;
|
||||
} else {
|
||||
baseY = gridY + static_cast<float>(livePiece.y) * sf.tileSize + offsets.second;
|
||||
}
|
||||
|
||||
// Draw the live piece (either pinned-to-row0 or at its real position).
|
||||
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 py = sf.targetY + static_cast<float>(cy) * sf.tileSize;
|
||||
int pyIdx = livePiece.y + cy;
|
||||
if (!pinToFirstVisibleRow && pyIdx < 0) continue;
|
||||
float px = baseX + static_cast<float>(cx) * sf.tileSize;
|
||||
float py = baseY + static_cast<float>(cy) * sf.tileSize;
|
||||
drawBlockTexturePublic(renderer, blocksTex, px, py, sf.tileSize, livePiece.type);
|
||||
}
|
||||
}
|
||||
if (blocksTex) SDL_SetTextureAlphaMod(blocksTex, 255);
|
||||
|
||||
// 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) {
|
||||
// End fade after duration, but never stop while we are pinning (otherwise
|
||||
// I can briefly disappear until it becomes visible in the real grid).
|
||||
if (t >= 1.0f && !pinToFirstVisibleRow) {
|
||||
sf.active = false;
|
||||
}
|
||||
};
|
||||
@ -2436,9 +2457,9 @@ void GameRenderer::renderCoopPlayingState(
|
||||
};
|
||||
const auto leftOffsets = computeOffsets(CoopGame::PlayerSide::Left, s_leftSmooth);
|
||||
const auto rightOffsets = computeOffsets(CoopGame::PlayerSide::Right, s_rightSmooth);
|
||||
// Draw transient spawn fades (if active) into the first visible row
|
||||
drawSpawnFadeIfActive(s_leftSpawnFade, CoopGame::PlayerSide::Left);
|
||||
drawSpawnFadeIfActive(s_rightSpawnFade, CoopGame::PlayerSide::Right);
|
||||
// Draw transient spawn fades (if active)
|
||||
drawSpawnFadeIfActive(s_leftSpawnFade, CoopGame::PlayerSide::Left, leftOffsets);
|
||||
drawSpawnFadeIfActive(s_rightSpawnFade, CoopGame::PlayerSide::Right, rightOffsets);
|
||||
|
||||
// Draw classic-style ghost pieces (landing position), grid-aligned.
|
||||
// This intentionally does NOT use smoothing offsets.
|
||||
|
||||
Reference in New Issue
Block a user