私のコードには、一連のピクセル座標を含むオブジェクトがあります。出力が常にキャッシュされるとは限らない 60fps ゲームで使用されるため、このオブジェクトのパフォーマンスは重要です。
実験とベンチマークの後、型なし配列を使用する場合、3D 配列が実装の最速の方法であることが判明しました。
var PixelCollection = function() {
this.pixels = [];
};
PixelCollection.prototype = {
add: function(x, y) {
var pixels = this.pixels;
if (pixels[y]) {
pixels[y].push(x);
} else {
pixels[y] = [x];
}
},
each: function(callback) {
var pixels = this.pixels;
for (var y = 0, m = pixels.length; y < m; y++) {
var row = pixels[y];
if (row) {
for (var i = 0, mm = row.length; i < mm; i++) {
callback(row[i], y);
}
}
}
}
};
状況によっては、オブジェクトの速度が十分でないためUint8Array
、2D 配列を使用して実装を試みました。
var WIDTH = 255;
var HEIGHT = 160;
PixelCollection = function() {
this.pixels = new Uint8Array(WIDTH * HEIGHT);
};
PixelCollection.prototype = {
add: function(x, y) {
this.pixels[WIDTH * y + x] = 1;
},
each: function(callback) {
var pixels = this.pixels;
for (var i = 0, m = pixels.length; i < m; i++) {
if (pixels[i]) {
callback(i % WIDTH, Math.floor(i / WIDTH));
}
}
}
}
これは遅くなります。- への書き込みと s からの読み取りが高速であるため、高速になると思いましたがUint8array
、すべての PixelCollection オブジェクトに対して巨大なオブジェクトを作成しているため、すべてのピクセルを反復処理するのに時間がかかるため、ピクセルの取得が大幅に遅くなります。(注:型なし配列を使用して上記の実装も試しました。かなり遅いです)
通常、PixelCollection にはすべてのピクセルが設定されているわけではありません。ただし、境界ボックスはキャンバス全体にまたがる可能性があるため、この大きなバッファーを使用して配列を作成する必要があります。
しかし、それを回避する方法があるかもしれません。1 つの大きな共有バッファーを作成し、PixelCollection ごとにバイト オフセットを使用できます。そのため、PixelCollectionP1
が 100 バイトを占める場合、PixelCollectionP2
はバイト オフセット 100 から開始されます。これによりメモリがより効率的に使用されますが、PixelCollection が使用するすべてのバイトの範囲を追跡する必要があります (これは C が「ポインター」と呼ぶものですか?) .
厄介な部分:P1
のバウンディング ボックスが拡大すると、 のP2
スペースを確保するために移動する必要がありP1
ます。また、共有バッファーに安全なバッファー サイズを設定する必要があるため、必要なメモリ量を安全に推測する必要があります。
これを実装することは可能ですが、多くの時間と試行錯誤が必要です。
ですから、これを始める前に、それは良い方法だと思いますか? これを行うためのより良い方法または簡単な方法はありますか? 私が学ぶことができる実装例を知っていますか?
編集:最適化を試してみたい場合に備えて、jsperf を追加しました。
最適化の優れたアイデアがある場合は、この jsperf に追加してください。