0

html5キャンバスに描画する必要のあるブロックのマップを含む2次元の連想配列があります。

現在、完了するまでに約28ミリ秒かかりますが、これは長すぎます(1秒間に60回コードを実行しています)。どういうわけか、マトリックスをより効率的に実行する必要があります。これは私のコードです:

for(var x=0; x<Object.keys(matrix).length; x++){ // Run through cols
    col = Object.keys(matrix)[x];
    for(var y=0; y<matrix[col].length; y++){ // Run though rows
        row = Object.keys(matrix[col])[y];
        if(matrix[col][row] != '0'){
            drawRect(col,row,blockSize,blockSize);
            }
        }
    }

非効率的で、何かを修正できることを願っています。2D配列の合計を最も効率的にループするにはどうすればよいですか?

4

5 に答える 5

1

2次元配列全体をループするには、doubleforループを使用する必要があります。パフォーマンスの問題があるコードを高速化しようとする場合と同様に、最初のステップは、何が最も時間がかかっているかを把握し、問題のその要素で最適化に取り組むことです。

おそらく、drawRectはループ内のどの問題よりも時間がかかると思われますが、残りのコードを高速化したい場合は、次のことを実行できます。

  1. キャッシュObject.keys(matrix)するので、常に再計算されることはありません
  2. 各ループの停止値をキャッシュして、各forループで毎回再計算されないようにします
  3. 列キーをキャッシュして、内部ループを介して毎回再計算されないようにします
  4. マトリックス列をキャッシュする

そのコードは次のようになります。

var keys = Object.keys(matrix);
for(var x = 0, lenX = keys.length; x < lenX; x++) { // Run through cols
    col = keys[x];
    var colKeys = Object.keys(matrix[col]);
    var matrixCol = matrix[col];
    for(var y = 0, lenY = matrix[col].length; y < lenY; y++) { // Run though rows
        row = colKeys[y];
        matrixCol[row] != '0'){
            drawRect(col,row,blockSize,blockSize);
        }
    }
}
于 2012-12-11T02:37:46.587 に答える
1

最初に、最も時間がかかるものを確認する必要があります。私の賭けは、drawRect関数が最も遅いということです。長方形を描く代わりに、コンソールに印刷して(または画面に書き込んで)、どれくらいの時間がかかるかを確認してください。次に、1つの操作を実行するために必要なdrawRectの量を計算できます。それがあなたの問題かもしれないと思います。drawRectは描画に時間がかかりすぎます。

于 2012-12-11T02:38:10.480 に答える
0

これを試して、ループ内の評価を減らすことができます

var m = Object.keys(matrix), mc, x = 0, xlen = m.length, col, mcol, y, ylen, row;
for(;x < xlen; x++) {
  col = m[x];
  mc = matrix[col];
  for(y = 0, ylen = mc.length; y < ylen; y++) {
    row = mc[y];
    if(mc[row] != '0') {
      drawRect(col, row, blockSize, blockSize);
    }
  }
}

ここで重要なのは、オブジェクトキーの評価の必要性を減らすことです。関数が何をしているのかわからないので、それを超えて減らす方法はまだわかりません。

于 2012-12-11T02:45:40.557 に答える
0

これを試して。

for(var x=0, xlimit=Object.keys(matrix).length; x<xlimit; x++){ // Run through cols
    col = Object.keys(matrix)[x];
    for(var y=0, ylimit=matrix[col].length; y<ylimit; y++){ // Run though rows
        row = Object.keys(matrix[col])[y];
        if(matrix[col][row] != '0'){
            drawRect(col,row,blockSize,blockSize);
        }
    }
}
于 2012-12-11T02:36:46.377 に答える
0

多くの変数をキャッシュすることを提案したいくつかの回答のおかげで、私は描画を30msから20msに変更しました。

しかし、今日はObject.keys()を削除することで、なんとか1msに到達しました。キーが含まれる範囲がわかったので、xとlenXを変更して範囲を事前に選択しました。yとlenYも同じです。ロード時間は、マトリックスのサイズにほとんど比例しません。(私は100倍大きいマトリックスをテストしましたが、2ミリ秒しかかかりません)。

minX = Math.floor(cameraPos.x/blockSize)*blockSize;
minY = Math.floor(cameraPos.y/blockSize)*blockSize;
maxX = minX+WIDTH+blockSize;
maxY = minY+HEIGHT+blockSize;
for(var col = minX; col < maxX; col+=blockSize) { // Run through cols
    for(var row = minY; row < maxY; row+=blockSize) { // Run though rows
        if(typeof matrix[col] !== "undefined" && typeof matrix[col][row] !== "undefined"){
            drawRect(xFix(col),yFix(row),blockSize,blockSize,blockColors[matrix[col][row]]);
        }
    }
}

関数は非常に高速ですが、最終的にはスケーリングを開始します。すべてのスケーリングを削除し、理論的にはゲームマップを途方もなく大きくすることができるようにするために、カメラが特定の距離をスクロールするたびにマップをキャッシュし始めました(現在は画面の幅が2倍になっていますが、それ以上になる可能性があります) )。キャッシュする領域はこれと同様の機能でフィルタリングされるため、ほぼ瞬時に実行されます。

var cached = [];
function cacheMap() {
    if(cached['pos'] === undefined || cameraPos.x < cached['pos']['x']-WIDTH || cameraPos.x > cached['pos']['x']+WIDTH || cameraPos.y < cached['pos']['y']-HEIGHT || cameraPos.y > cached['pos']['y']+HEIGHT) {
        cached['map'] = filterMatrix(map,cameraPos.x-WIDTH-blockSize*5,cameraPos.y-HEIGHT-blockSize*5,WIDTH*3+blockSize*10,HEIGHT*3+blockSize*10);
        cached['pos'] = {'x':cameraPos.x,'y':cameraPos.y};
        console.log('cached map');
        }
    }
于 2012-12-13T06:55:42.787 に答える