Fix mobile view: next piece display, game board scaling, and visibility issues

This commit is contained in:
cmclark00 2025-03-25 16:49:10 -04:00
parent 6285492580
commit 40700d1636
2 changed files with 112 additions and 21 deletions

115
script.js
View file

@ -381,11 +381,11 @@ class Firework {
// The Piece class
class Piece {
constructor(tetromino, color) {
constructor(tetromino, tetrominoN, color) {
this.tetromino = tetromino;
this.color = color;
this.tetrominoN = 0; // Default rotation state
this.tetrominoN = tetrominoN || 0; // Rotation state
this.activeTetromino = this.tetromino[this.tetrominoN];
this.shadowTetromino = this.activeTetromino; // For shadow calculation
@ -1510,8 +1510,11 @@ function drawBoard() {
// Generate random piece
function randomPiece() {
let r = Math.floor(Math.random() * PIECES.length);
return new Piece(PIECES[r], COLORS[r]);
let randomN = Math.floor(Math.random() * PIECES.length);
let randomTetromino = PIECES[randomN];
let randomIndex = Math.floor(Math.random() * randomTetromino.length);
return new Piece(randomTetromino, randomIndex, COLORS[randomN]);
}
// Play piece movement sounds
@ -1620,7 +1623,26 @@ function draw() {
// Drop the piece - called by interval
function dropPiece() {
if (gameOver || paused) return;
let now = Date.now();
let delta = now - dropStart;
// Drop speed depends on level
let speed = 1000 * (1 - (level - 1) * 0.1);
speed = Math.max(speed, 100); // Don't allow too fast drops (minimum 100ms)
if (delta > speed) {
p.moveDown();
dropStart = now;
// If we can't move down and we're still at the top, game over
if (p.collision(0, 1) && p.y < 1) {
gameOver = true;
showGameOver();
}
}
if (!gameOver) requestAnimationFrame(draw);
}
// Show game over modal
@ -1752,9 +1774,11 @@ function init() {
// Draw the board
drawBoard();
// Generate pieces
// Generate initial pieces
p = randomPiece();
nextPiece = randomPiece();
// Draw initial next piece
nextPiece.drawNextPiece();
// Set up game interval
@ -1836,13 +1860,13 @@ function handleResize() {
// For portrait: maximize width, maintain aspect ratio
if (isPortrait) {
// Use 95% of viewport width
const targetWidth = viewportWidth * 0.95;
// Use 90% of viewport width
const targetWidth = viewportWidth * 0.9;
const targetHeight = (targetWidth / COLS) * ROWS;
// If height is too tall, scale down
if (targetHeight > availableHeight * 0.9) {
const scaleFactor = (availableHeight * 0.9) / targetHeight;
if (targetHeight > availableHeight * 0.8) {
const scaleFactor = (availableHeight * 0.8) / targetHeight;
canvas.style.width = `${targetWidth * scaleFactor}px`;
canvas.style.height = `${targetHeight * scaleFactor}px`;
} else {
@ -1852,8 +1876,8 @@ function handleResize() {
}
// For landscape: maximize height, maintain aspect ratio
else {
// Use 80% of available height
const targetHeight = availableHeight * 0.8;
// Use 75% of available height
const targetHeight = availableHeight * 0.75;
const targetWidth = (targetHeight / ROWS) * COLS;
// If width is too wide, scale down
@ -1867,11 +1891,12 @@ function handleResize() {
}
}
// Scale next piece preview to match
if (nextPieceCanvas) {
const scale = parseInt(canvas.style.width) / (COLS * BLOCK_SIZE);
nextPieceCanvas.style.transform = `scale(${scale})`;
nextPieceCanvas.style.transformOrigin = 'top left';
// Force a redraw of the nextPiece preview to fix rendering issues
if (nextPiece) {
setTimeout(() => {
nextPieceCtx.clearRect(0, 0, nextPieceCanvas.width, nextPieceCanvas.height);
nextPiece.drawNextPiece();
}, 100);
}
// Show touch controls mode
@ -2303,6 +2328,64 @@ function createTouchControlButtons() {
}, 5000);
}
// Set active piece to next piece and create new next piece
function getNextPiece() {
// Current piece becomes the next piece
p = nextPiece;
// Generate a new next piece
nextPiece = randomPiece();
// Draw the next piece in preview
nextPiece.drawNextPiece();
// Force redraw for mobile to ensure it renders
if (isMobile || forceMobileControls) {
setTimeout(() => {
nextPieceCtx.clearRect(0, 0, nextPieceCanvas.width, nextPieceCanvas.height);
nextPiece.drawNextPiece();
}, 50);
}
}
// Lock the piece in the board and get the next piece
function lockPiece() {
// Add piece to board
for (let r = 0; r < p.activeTetromino.length; r++) {
for (let c = 0; c < p.activeTetromino[r].length; c++) {
// Skip empty squares
if (!p.activeTetromino[r][c]) {
continue;
}
// Game over when piece is locked at the top
if (p.y + r < 0) {
gameOver = true;
showGameOver();
return;
}
// Lock piece
board[p.y + r][p.x + c] = p.color;
}
}
// Check for completed rows
checkRows();
// Update the score
updateScore();
// Get next piece
getNextPiece();
// Reset drop timer
dropStart = Date.now();
// Play drop sound
playSound(dropSound);
}
// Start the game
window.onload = function() {
init();

View file

@ -516,15 +516,20 @@ input[type=range]::-moz-range-thumb {
flex-direction: column;
align-items: center;
margin: 0 auto;
position: relative;
margin-bottom: 20px; /* Add bottom margin to make room for next piece */
}
.mobile-mode #next-piece-preview {
position: absolute;
top: -50px; /* Position above the game board */
top: auto;
bottom: -70px; /* Position below the game board */
left: 50%;
transform: translateX(-50%);
margin: 0;
background: rgba(0, 0, 0, 0.7);
z-index: 10;
border-color: rgba(0, 255, 255, 0.5);
}
.mobile-mode .score-container {
@ -589,10 +594,12 @@ input[type=range]::-moz-range-thumb {
@media (orientation: portrait) {
.mobile-mode .game-container {
padding-top: 40px;
padding-bottom: 80px; /* Add bottom padding for next piece */
}
.mobile-mode canvas#tetris {
width: 90vw;
max-height: 75vh; /* Ensure game board doesn't take too much height */
height: auto;
object-fit: contain;
}
@ -623,13 +630,14 @@ input[type=range]::-moz-range-thumb {
.mobile-mode #next-piece-preview {
position: absolute;
top: 0;
bottom: auto;
left: 100%;
margin-left: 10px;
transform: none;
margin-left: 10px;
}
.mobile-mode canvas#tetris {
height: 80vh;
height: 75vh; /* Slightly reduced to ensure full visibility */
width: auto;
object-fit: contain;
}