5

キャンバス ゲームのパフォーマンスを最後の一滴まで絞り出そうとしています。最近、キャンバスをクリアするとパフォーマンスが非常に高くなることがわかったので、フレームごとにキャンバス全体をクリアする方法を見つけようとしています。ただし、各オブジェクトの境界ボックスを個別にクリアしてから更新するという、私が試みている新しい方法にはいくつかの問題があります。

問題は、要素がキャンバスを離れ、画像の一部が残るときに要素が「取り残される」ことです。問題がコードの残りの部分になく、喜びがないことを確認するために、コードを単純化しようとしました。

特にこの新しい方法ははるかに高速であるため、フレームごとにキャンバス全体をワイプすることに戻ることも望ましくありません。コードは次のとおりです(何らかの理由でフィドルとして機能しません)。

var enemyCtx = document.getElementById('enemy').getContext('2d');

var game =
{
    w: 800,
    h: 500
};
var enemies = [];
window.addEventListener('load', function()
{
    for (var i = 0; i < 200; i++)
    {
        enemies[enemies.length] = new Enemy();
    }
    update();
}, false);

var buffer = document.createElement('canvas');
    buffer.width = 42;
    buffer.height = 42;
    var bufferCtx = buffer.getContext('2d');
    drawEnemy(bufferCtx, 5, 5, 32, 32, 'red');

function update()
{
    for (var i = 0; i < enemies.length; i++)
    {
                    enemyCtx.clearRect(    enemies[i].x,
                                enemies[i].y,
                                enemies[i].x + enemies[i].width,
                                enemies[i].y + enemies[i].height);
    }
    for (var i = 0; i < enemies.length; i++)
    {
        enemies[i].x-=5;
        enemyCtx.drawImage(buffer, enemies[i].x-5, enemies[i].y-5);
    }
    requestAnimationFrame(update);
}

function drawEnemy(ctx, x, y, width, height, colour)
{
        ctx.lineWidth = 1;
        ctx.strokeStyle = colour;
        ctx.strokeRect(x + 0.5, y + 0.5, width, height);
}

function Enemy()
{
    this.x = Math.random()*game.w;
    this.y = Math.random()*game.h;
    this.width = 32;
    this.height = 32;
}
(function()
{
    // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
    var lastTime = 0;
    var vendors = ['ms', 'moz', 'webkit', 'o'];
    for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x)
    {
        window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
        window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
    }

    if (!window.requestAnimationFrame) window.requestAnimationFrame = function(callback, element)
    {
        var currTime = new Date().getTime();
        var timeToCall = Math.max(0, 16 - (currTime - lastTime));
        var id = window.setTimeout(function()
        {
            callback(currTime + timeToCall);
        }, timeToCall);
        lastTime = currTime + timeToCall;
        return id;
    };

    if (!window.cancelAnimationFrame) window.cancelAnimationFrame = function(id)
    {
        clearTimeout(id);
    };
}());

& HTML:

<canvas id="enemy" width="800" height="500"></canvas>​

皆さんが私に与えることができる洞察は非常に役に立ちます。ありがとう!

4

1 に答える 1

1

これについてもう少し考えて、解決策を思いつきました。ひょっとしたら、あなたにとって何かの役に立つかもしれません。

clearRect() メソッドは実際のキャンバス座標で動作する必要があるため、基本的に画像はキャンバス上に「取り残されます」。画像がキャンバスを離れているため、その座標は負の値になります。

function update()
{
    for (var i = 0; i < enemies.length; i++)
    {
        lx = (enemies[i].x > 0) ? enemies[i].x : 0;
        ly = (enemies[i].y > 0) ? enemies[i].y : 0;
        enemyCtx.clearRect( lx,
                            ly,
                            lx + enemies[i].width + 1,
                            ly + enemies[i].height + 1);
    }
    // ...
}

幅に 1 を追加すると、イメージが消去されるときにキャンバスがイメージの最後のピクセル列を描画するのを停止します。お役に立てれば。

于 2012-12-21T20:17:13.633 に答える