requestanimationframe drawing with for loop 问题

requestanimationframe drawing with for loop issue

我正在开发俄罗斯方块游戏 - 仍然 - 并且正在尝试使用 requestAnimationFrame 在黑板上绘制我的 T 块。

这就是问题所在。 requestAnimationFrame 绘制了 2 次,然后停止绘制,即使 for 循环仍然是 运行。也就是说,两次之后,我只看到黑色背景。当我注释掉黑色背景时,该作品显示 up/animates 就好了。

我真的很困惑为什么会这样。

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

const T = [
        [
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0],
            [0, 1, 1, 1, 0],
            [0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0]
        ],

       [
            [0, 0, 0, 0, 0],
            [0, 0, 1, 0, 0],
            [0, 1, 1, 0, 0],
            [0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0]
        ],

       [
            [0, 0, 0, 0, 0],
            [0, 0, 1, 0, 0],
            [0, 1, 1, 1, 0],
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0]
        ],

        [
            [0, 0, 0, 0, 0],
            [0, 0, 1, 0, 0],
            [0, 0, 1, 1, 0],
            [0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0]
        ],
    ]

    var piece = T[0];

    const player = {
        position: {x: 5, y: -1},
        piece: piece,
    }

function colorPiece(piece, offset) {
    for(y = 0; y < piece.length; y++) {
        for(x = 0; x < piece.length; x++) {
            if (piece[y][x] !== 0) {
                ctx.fillStyle = "red";
                ctx.fillRect(x + offset.x, y + offset.y, 1, 1);
            }
        }
    }
}

function drawCanvas() {
    ctx.fillStyle = "black";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.scale(20, 20);
    colorPiece(player.piece, player.position);
}

function update() {
        drawCanvas();
        requestAnimationFrame(update);
}

update();

OK - 工作版本,fiddle here。一些变化。最大的是:

  • 不要使用 canvas.scale(),因为它是按 this 累积的(参见 "More Examples")。相反,对 20x20 块使用 20*x20*y

    编辑 基于 further test,看起来这是最重要的更改。

  • 重命名,使piece不用作变量的全部,player中的字段名,colorPiece[=41=的参数]

  • 根据 this fiddle examplectx 创作移动到 update()(现在称为 doUpdate())。将 ctx 作为参数传递给其他函数。

  • 将红色的fillStyle赋值移出循环,因为你只需要做一次,然后你就可以在不改变它的情况下绘制所有的矩形。

  • 在循环中:

    for(var y = 0; y < thePiece.length; ++y) {
        for(var x = 0; x < thePiece[y].length; ++x) { ... } }
    

    保留 xy in the local scope,使用 var

    当您准备好跨越一行时,即 thePiece[y].length,即行的长度。使用 thePiece.length 会破坏 T.

  • 的非正方形元素
  • 添加了一个 <p id="log"/> 和一个 javascript framenum 这样我就可以看到 doUpdate() 确实被调用了。

如果还没有,请确保在测试时打开控制台,以便查看错误消息。如果 drawCanvas 导致错误,它将阻止 requestAnimationFrame 再次被调用。我认为这就是为什么 the fiddle I linked above 在帧绘制函数的 beginning 而不是 end 调用 requestAnimationFrame 的原因。

希望对您有所帮助!

代码

const T = [
        [
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0],
            [0, 1, 1, 1, 0],
            [0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0]
        ],

       [
            [0, 0, 0, 0, 0],
            [0, 0, 1, 0, 0],
            [0, 1, 1, 0, 0],
            [0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0]
        ],

       [
            [0, 0, 0, 0, 0],
            [0, 0, 1, 0, 0],
            [0, 1, 1, 1, 0],
            [0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0]
        ],

        [
            [0, 0, 0, 0, 0],
            [0, 0, 1, 0, 0],
            [0, 0, 1, 1, 0],
            [0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0]
        ],
    ]

    const player = {
        position: {x: 5, y: -1},
        piece: T[0]
    }

function colorPiece(ctx, thePiece, offset) {
    ctx.fillStyle = "red";
    for(var y = 0; y < thePiece.length; ++y) {
        for(var x = 0; x < thePiece[y].length; ++x) {
            if (thePiece[y][x] !== 0) {
                ctx.fillRect(20*(x + offset.x), 20*(y + offset.y), 20, 20);
            }
        }
    }
}

function drawCanvas(ctx) {
    ctx.fillStyle = "#000000";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    colorPiece(ctx, player.piece, player.position);
}

var framenum=0;

function doUpdate(timestamp) {
        document.getElementById("log").innerHTML = framenum.toString();
        ++framenum;
        var canvas = document.getElementById("canvas");
        var ctx = canvas.getContext("2d");

        drawCanvas(ctx);
        window.requestAnimationFrame(doUpdate);
}

doUpdate();