You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

俄罗斯方块游戏触底后报错停止运行,寻求解决方案

俄罗斯方块触底冻结&未定义属性报错解决方案

问题根源

  1. 数组越界访问:方块触底后,movedown函数仍会执行currentPosition += width,导致currentPosition + index超出squares数组的索引范围(0-199),访问undefined的classList触发TypeError。
  2. 缺失新方块生成逻辑:原freeze函数仅将当前方块标记为taken,但未触发新方块的生成,也未终止当前方块的下移循环。
  3. 选择器错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 09:15:38