俄罗斯方块游戏触底后报错停止运行,寻求解决方案
俄罗斯方块触底冻结&未定义属性报错解决方案
问题根源
- 数组越界访问:方块触底后,
movedown函数仍会执行currentPosition += width,导致currentPosition + index超出squares数组的索引范围(0-199),访问undefined的classList触发TypeError。 - 缺失新方块生成逻辑:原
freeze函数仅将当前方块标记为taken,但未触发新方块的生成,也未终止当前方块的下移循环。 - 选择器错误:
StartBtn的选择器缺少符号,应为.start-button或#start-button(根据实际HTML结构调整)。
修复步骤
1. 完善freeze函数,添加新方块生成逻辑
当方块触底或碰到已存在的taken方块时,标记当前方块为taken,然后生成新的随机方块,并重置位置和旋转状态。同时添加游戏结束判断(新方块初始位置无法放置则游戏结束):
function freeze() { // 标记当前方块为已固定 current.forEach(index => squares[currentPosition + index].classList.add('taken')) // 生成新的随机方块 random = Math.floor(Math.random()*theTetrominoes.length) currentRotation = 0 current = theTetrominoes[random][currentRotation] currentPosition = 4 // 游戏结束判断:新方块初始位置已被占用 if(current.some(index => squares[currentPosition + index].classList.contains('taken'))){ clearInterval(timeID) alert('游戏结束!') return } draw() }
2. 修改movedown函数,避免无效下移
在执行下移前,先判断是否可以下移,若不能则回退位置并触发冻结逻辑,避免越界访问:
function movedown(){ undraw() const nextPosition = currentPosition + width // 判断下一个位置是否可以放置 const canMoveDown = !current.some(index => nextPosition + index >= squares.length || (squares[nextPosition + index] && squares[nextPosition + index].classList.contains('taken')) ) if(canMoveDown){ currentPosition = nextPosition draw() } else { // 回退位置并冻结当前方块 draw() freeze() } }
3. 修复StartBtn选择器错误
原代码中选择器缺少符号,根据HTML结构修改为:
// 若按钮是类名定义 const StartBtn = document.querySelector('.start-button') // 若按钮是ID定义 const StartBtn = document.querySelector('#start-button')
4. 清理无用代码
移除无意义的变量和空日志:
// 移除以下两行无用代码 let array = [1, 3, 4, 5] console.log()
5. 给draw/undraw添加存在性判断
防止极端情况下的越界访问:
function draw(){ current.forEach(index => { if(squares[currentPosition + index]){ squares[currentPosition + index].classList.add('tetromino') } }) } function undraw(){ current.forEach(index => { if(squares[currentPosition + index]){ squares[currentPosition + index].classList.remove('tetromino') } }) }
完整修复后代码
document.addEventListener('DOMContentLoaded', () => { const grid = document.querySelector('.grid') let squares = Array.from(document.querySelectorAll('.grid div')) const ScoreDisplay = document.querySelector('#score') // 修复选择器,根据实际HTML调整 const StartBtn = document.querySelector('.start-button') let width = 10 // 定义各类型方块 const lTetromino =[ [1, width + 1, width* 2 + 1, 2], [width , width + 1 , width + 2 , width * 2 + 2 ], [1 , width + 1 , width * 2 , width * 2 + 1], [width, width * 2 , width * 2 + 1 , width * 2 + 2] ] const zTetromino =[ [width * 2 , width + 1 , width * 2 + 1 , width + 2], [0 , width , width + 1 , width * 2 + 1], [width * 2 , width + 1 , width * 2 + 1 , width + 2], [0 , width , width + 1 , width * 2 + 1] ] const tTetromino = [ [width, 1 , width + 1 , width + 2], [1 , width + 1 , width + 2 , width * 2 + 1 ], [width , width + 1 , width + 2 , width * 2 + 1], [width, 1 , width + 1 , width * 2 + 1] ] const oTetromino = [ [0, 1 , width , width + 1], [0, 1 , width , width + 1], [0, 1 , width , width + 1], [0, 1 , width , width + 1] ] const iTetromino = [ [1, width + 1 , width * 2 + 1, width * 3 + 1], [width, width + 1 , width + 2 , width + 3], [1, width + 1 , width * 2 + 1, width * 3 + 1 ], [width, width + 1 , width + 2 , width + 3] ] const theTetrominoes = [lTetromino, zTetromino, tTetromino, oTetromino, iTetromino] let currentPosition = 4 let currentRotation = 0 // 随机选择初始方块 let random = Math.floor(Math.random()*theTetrominoes.length) let current = theTetrominoes[random][currentRotation] // 绘制方块 function draw(){ current.forEach(index => { if(squares[currentPosition + index]){ squares[currentPosition + index].classList.add('tetromino') } }) } draw() // 清除方块 function undraw(){ current.forEach(index => { if(squares[currentPosition + index]){ squares[currentPosition + index].classList.remove('tetromino') } }) } // 冻结方块并生成新方块 function freeze() { current.forEach(index => squares[currentPosition + index].classList.add('taken')) // 生成新方块 random = Math.floor(Math.random()*theTetrominoes.length) currentRotation = 0 current = theTetrominoes[random][currentRotation] currentPosition = 4 // 游戏结束判断 if(current.some(index => squares[currentPosition + index].classList.contains('taken'))){ clearInterval(timeID) alert('游戏结束!') return } draw() } let timeID = setInterval(movedown, 500) // 下移函数 function movedown(){ undraw() const nextPosition = currentPosition + width // 判断是否可以下移 const canMoveDown = !current.some(index => nextPosition + index >= squares.length || (squares[nextPosition + index] && squares[nextPosition + index].classList.contains('taken')) ) if(canMoveDown){ currentPosition = nextPosition draw() } else { draw() freeze() } } })
内容的提问来源于stack exchange,提问作者black fire
相关产品推荐
相关产品推荐

