4

HTML5 キャンバスを使い始めたばかりで、それを使っていくつかのゲームを作りたいと思っていました。ただし、マウス座標のレンダリングを開始するとすぐに、ほぼ停止しました。

http://jsfiddle.net/mnpenner/zHpgV/

私がしたことは、38 行といくつかのテキストをレンダリングすることだけでした。それを処理できるはずですよね?

私は何か間違ったことをしていますか?少なくとも 30 FPS でレンダリングできるようにしたいのですが、このようなものでは、何千回も描画できると予想されます。

それとも、仕事に間違ったツールを使用しているだけですか? WebGL はタスクに適していますか? 一方が他方よりもはるかに遅いのはなぜですか?

String.prototype.format = function() {
    var args = arguments;
    return this.replace(/\{(\d+)\}/g, function(m, n) {
        return args[n];
    });
};
var $canvas = $('#canvas');
var c = $canvas[0].getContext('2d');
var scale = 20;
var xMult = $canvas.width() / scale;
var yMult = $canvas.height() / scale;
var mouseX = 0;
var mouseY = 0;
c.scale(xMult, yMult);
c.lineWidth = 1 / scale;
c.font = '1pt Calibri';

function render() {
    c.fillStyle = '#dcb25c';
    c.fillRect(0, 0, scale, scale);
    c.fillStyle = '#544423';
    c.lineCap = 'square';
    for (var i = 0; i <= 19; ++i) {
        var j = 0.5 + i;
        c.moveTo(j, 0.5);
        c.lineTo(j, 19.5);
        c.stroke();
        c.moveTo(0.5, j);
        c.lineTo(19.5, j);
        c.stroke();
    }
    c.fillStyle = '#ffffff';
    c.fillText('{0}, {1}'.format(mouseX, mouseY), 0.5, 1.5);
}
render();
$canvas.mousemove(function(e) {
    mouseX = e.clientX;
    mouseY = e.clientY;
    render();
});
<canvas id="canvas" width="570" height="570"></canvas>

4

3 に答える 3

10

これは、はるかに優れたコードです。

http://jsfiddle.net/zHpgV/3/

私が変更したことを考慮する必要があることの内訳は次のとおりです。

  • を使用して新しいパスを停止して作成する代わりに、パスに継続的に追加しbeginPathます。これは、ここでの最大のパフォーマンスキラーです。クリアされない何千ものライン セグメントを持つパスになってしまいます。
  • 初期化時に一度だけ作成する必要がある場合に、同じパスを何度も作成し続ける。つまり、内部で呼び出す必要があるのは だけrenderですstrokelineTo/moveTo二度と電話する必要はありません。もちろん、継続的に電話する必要もありません。注 1 を参照してください。
  • 1 つのパスに対して 2 回のストローク
  • for ループ内でのストローク
  • CSS の背景を設定する代わりに背景を再描画する
  • ラインキャップを何度も設定する

注 1:アプリケーションで複数のパスを使用する予定がある場合は、パスは決して変更されないため、おそらくこのようなパスをキャッシュする必要があります。私はそれを行う方法についてのチュートリアルをここに持っています。

もちろん、背景を作成するためだけにこれらすべてを行っている場合は、png として保存し、CSS 背景画像を使用する必要があります。

そのように: http://jsfiddle.net/zHpgV/4/

次に、突然、レンダリング ルーチンがかなり小さくなります。

function render() {
    c.clearRect(0, 0, scale, scale);
    c.fillText('{0}, {1}'.format(mouseX, mouseY), 0.5, 1.5);
}
于 2012-06-22T20:29:41.063 に答える
9

コメントで言ったように、ダブルバッファリングを気にすることなく、非常に高速なアニメーションではるかに複雑なものを描画するため、このコードの速度が遅いことに驚いていました。

それでもう少し調べて、予想通りバグを見つけました。

主な問題は、描画パスの蓄積です。

c.beginPath();1つのパスを描くたびに追加します。

これが同じものの高速レンダリングで、今飛んでいることを証明します。

キャンバスの描画高速で、アニメーションに使用できます。

于 2012-06-22T17:41:14.057 に答える
7

すべてのアニメーション フレームでグリッド全体を描画する必要はありません。別の基礎となるキャンバス (「レイヤー」と呼ぶのが一般的ですが、それらは別のキャンバス要素です) に配置すると、座標のみを再描画できるようになります。

<div id="canv">
 <canvas id="bgLayer" width="500" height="500" style="z-index: 0"></canvas>
 <canvas id="fgLayer"  width="500" height="500" style="z-index: 1"></canvas>
</div>

これは、レイヤードキャンバスで遊んでいる例です。下のキャンバスに描かれた表、上のキャンバスにボールが描かれています。これは遊び場にすぎないため、修正して最適化することがたくさんあります。たとえば、すべてのボールを別の非表示のキャンバスに 1 回だけ描画し、getImageData/putImageDataを使用してパフォーマンスを向上させるなどです。

また、requestAnimationFrameを使用してキャンバスを更新することをお勧めします。あなたの例は、代わりにすべてのマウスの動きを描画します。これは、必要以上に頻繁に行われます(もちろん、マウスが動くとき)。

キャンバスのパフォーマンスの向上に関する良い記事があります。また、このテーマに関する素晴らしいSO 投稿があります。

于 2012-06-22T06:01:22.747 に答える