JavaScript实现俄罗斯方块:软降时方块消失问题求助
俄罗斯方块软降异常问题修复方案
问题现象
方块未完全显示在网格前触发软降,会中途消失;方块完全显示后软降正常,但按住向下键仍有异常。
核心问题与修复代码
1. 移除软降函数的不必要位置限制
softDrop函数中原有的this.y >= 1判断会阻止初始位置(y=1)的方块执行软降,直接触发锁定逻辑导致方块消失。
原代码:
Piece.prototype.softDrop = function() { if (this.y >= 1 && !this.collision(0, 1, this.activeTetromino)) { this.unDraw(); this.y++; this.draw(); score += 1; // add 1 point per row for soft drop updateScoreDisplay(); } else { this.handleLockDelay(); } }
修改后:
Piece.prototype.softDrop = function() { if (!this.collision(0, 1, this.activeTetromino)) { this.unDraw(); this.y++; this.draw(); score += 1; updateScoreDisplay(); } else { this.handleLockDelay(); } }
2. 完整擦除所有位置的方块
unDraw函数原只处理可见区域的方块,导致不可见区域的方块残留,干扰碰撞检测和锁定逻辑,必须完整擦除所有位置的方块。
原代码:
Piece.prototype.unDraw = function() { for (let r = 0; r < this.activeTetromino.length; r++) { for (let c = 0; c < this.activeTetromino.length; c++) { if (this.activeTetromino[r][c]) { let drawY = this.y + r; if (drawY >= 2) { // draw only visible rows drawSquare(this.x + c, drawY - 2, VACANT); } } } } }
修改后:
Piece.prototype.unDraw = function() { for (let r = 0; r < this.activeTetromino.length; r++) { for (let c = 0; c < this.activeTetromino.length; c++) { if (this.activeTetromino[r][c]) { let drawY = this.y + r; const drawX = this.x + c; // 擦除可见区域的方块 if (drawY >= 2) { drawSquare(drawX, drawY - 2, VACANT); } // 清空board中对应位置,避免残留干扰碰撞检测 if (drawY >= 0 && drawY < ROW && drawX >= 0 && drawX < COL) { board[drawY][drawX] = VACANT; } } } } }
3. 修正错误的游戏结束判定
lock函数中原有的this.y + r < 2会在方块部分处于不可见区域时直接触发游戏结束,这不符合逻辑,应该在新方块生成时判断是否无法放置才结束游戏。
修改lock函数中的游戏结束判断:
// 原代码片段 if (this.y + r < 2) { // game over alert('Game Over'); gameOver = true; break; } board[this.y + r][this.x + c] = this.color;
替换为:
const visibleRowStart = 2; // 仅当方块进入可见区域的部分无法放置时,才标记游戏结束待确认 if (this.y + r >= visibleRowStart) { board[this.y + r][this.x + c] = this.color; } else { // 标记为待确认,后续生成新方块时检查 gameOverPending = true; }
添加新方块生成时的游戏结束检查:
function randomPiece() { // 假设你有定义pieces数组包含所有方块类型 const pieces = [/* 你的方块类型集合 */]; const randomIdx = Math.floor(Math.random() * pieces.length); const newPiece = new Piece(pieces[randomIdx].tetromino, pieces[randomIdx].color); // 检查新方块是否一开始就无法放置,才触发游戏结束 if (gameOverPending || newPiece.collision(0, 0, newPiece.activeTetromino)) { alert('Game Over'); gameOver = true; return null; } gameOverPending = false; return newPiece; }
4. 处理按住向下键的重复触发问题
通过跟踪按键状态,使用定时器实现连续软降,避免按键重复触发导致的方块异常。
添加全局按键状态与事件监听:
let softDropInterval = null; const keyStates = { arrowDown: false }; document.addEventListener('keydown', (e) => { if (e.key === 'ArrowDown' && !keyStates.arrowDown && !gameOver && p) { keyStates.arrowDown = true; // 设置定时器控制软降速度 softDropInterval = setInterval(() => { p.softDrop(); }, 60); } }); document.addEventListener('keyup', (e) => { if (e.key === 'ArrowDown') { keyStates.arrowDown = false; clearInterval(softDropInterval); } });
总结
以上修改解决了软降限制、方块擦除不完整、错误游戏结束判定以及按键重复触发四个核心问题,能让方块在未完全显示时也能正常软降,不会中途消失。
内容的提问来源于stack exchange,提问作者j k
相关产品推荐
相关产品推荐

