Рисование requestanimationframe с циклом for

Я все еще работаю над игрой в тетрис и пытаюсь использовать requestAnimationFrame, чтобы нарисовать свою фигуру T на черной доске.

Это проблема. requestAnimationFrame рисует кусок 2 раза, затем прекращает рисовать, хотя цикл for все еще работает. То есть после двух раз я вижу только черный фон. Когда я комментирую черный фон, часть появляется/анимируется просто отлично.

Я действительно в недоумении, почему это происходит.

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();

person Community    schedule 30.06.2017    source источник
comment
Не могли бы вы отредактировать свой вопрос, чтобы показать код, создающий ctx? Я не вижу этого в этом фрагменте. Спасибо! Кроме того объясните, пожалуйста, остановки рисования по сравнению с анимацией --- я не вижу в этом коде ничего, что заставляло бы фигуру двигаться. Вы имеете в виду, что после двух кадров вы получаете только черный прямоугольник?   -  person cxw    schedule 30.06.2017
comment
Мое ОКР мешает мне указать, что эта часть написана I-E, а не E-I ... но пока вы не исправите написание на полпути к коду, все в порядке.   -  person Patrick Roberts    schedule 30.06.2017
comment
Патрик, твой комментарий меня рассмешил. Извиняюсь. Я думаю, что я, по крайней мере, постоянно пишу это неправильно.   -  person    schedule 30.06.2017
comment
Да, cxw, я вижу черный фон только после того, как красная буква t повторяется дважды.   -  person    schedule 30.06.2017
comment
Да, я все еще изучаю чистый код. Я попробовал кусок: T [0], и возникла та же проблема.   -  person    schedule 30.06.2017


Ответы (1)


ОК - рабочая версия, со скриптой здесь. Ряд изменений. Самые большие:

  • Не используйте canvas.scale(), так как он суммируется для этого (см. "Дополнительные примеры"). . Вместо этого используйте 20*x и 20*y для блоков 20x20.

    Изменить Судя по дополнительному тесту, это было наиболее существенное изменение.

  • Переименуйте так, чтобы piece не использовалось как вся переменная, имя поля в player и параметр colorPiece

  • Переместите творение ctx в update() (теперь называемое doUpdate()) согласно этому примеру скрипта. Передайте ctx в качестве параметра другим функциям.

  • Вынесите из цикла присваивание красного цвета fillStyle, так как вам нужно сделать это только один раз, и тогда вы сможете рисовать все прямоугольники, не меняя его.

  • В петлях:

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

    Оставьте x и y в локальной области, используя var.

    Когда вы готовы пройти через ряд, это thePiece[y].length, т. е. длина ряда. Использование thePiece.length было бы нарушено для неквадратных элементов T.

  • Добавил <p id="log"/> и javascript framenum, чтобы я мог видеть, что doUpdate() действительно вызывается.

Если вы еще этого не сделали, обязательно откройте консоль во время тестирования, чтобы видеть сообщения об ошибках. Если drawCanvas вызывает ошибку, это предотвратит повторный вызов requestAnimationFrame. Думаю, именно поэтому скрипт, на который я ссылался выше, вызывает 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();
person cxw    schedule 30.06.2017
comment
Да! Мне даже не пришло в голову, что fillStyle необходим для продолжения fillRect. Я немного подправил свой код в соответствии с вашими предложениями с помощью отладчика, и как только я поставил fillStyle перед fillRect, проблема была устранена. Большое спасибо за помощь!!! - person ; 01.07.2017