2016-03-20 9 views
0

私はリアルタイムでお互いを引き付ける小さなボールであるはずのスクリプトを作った。非常に遅いという問題です。アニメーションフレームを使用していたので、すべてのフレームを更新する必要があると思いますが、そうではありません。なぜこのスクリプトはJavascriptで遅れを遅らせますか?

$(function() { 
 

 
    var mouseDown 
 
    var c = document.getElementById('myCanvas'); 
 
    var ctx = c.getContext("2d"); 
 
    var objects = [] 
 

 
    c.addEventListener("mousedown", onMouseDown); 
 
    c.addEventListener("mouseup", onMouseUp); 
 

 
    function createSquare(x, y, size, direction, xVel, yVel) { 
 
    this.x = x; 
 
    this.y = y; 
 
    this.size = size; 
 
    this.drawStylus = drawStylus; 
 
    }; 
 

 
    function drawStylus() { 
 
    ctx.beginPath(); 
 
    ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI); 
 
    ctx.fill(); 
 
    }; 
 

 
    function getDistance(x1, y1, x2, y2) { 
 
    return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); 
 
    } 
 

 
    function draw() { 
 
    ctx.clearRect(0, 0, 5000, 5000); 
 
    for (i = 0; i < objects.length; i++) { 
 

 
     var x = objects[i][0] 
 
     var y = objects[i][1] 
 
     var size = objects[i][2] 
 
     var dir = Math.random() * Math.PI * 2 
 
     var force = 0 
 
     var xVel = 0 
 
     var yVel = 0 
 
     for (n = 0; n < objects.length; n++) { 
 
     if (n != i) { 
 
      force = 100 * objects[n][2]/getDistance(x, y, objects[n][0], objects[n][1]) 
 
      angle = Math.atan2(y - objects[n][1], x - objects[n][0]) 
 
      xVel += force * -Math.cos(angle) 
 
      yVel += force * -Math.sin(angle) 
 
      window.requestAnimationFrame(draw) 
 
     }; 
 
     }; 
 

 
     ctx.beginPath(); 
 
     ctx.arc(x + xVel, y + yVel, size, 0, 2 * Math.PI); 
 
     ctx.fill(); 
 
    }; 
 
    }; 
 

 
    function onMouseDown() { 
 
    mouseDown = true 
 
    x = event.clientX 
 
    y = event.clientY 
 
    size = 100 
 

 
    animation = function() { 
 
     size = size + 20 
 

 
     var cursorSquare = new createSquare(x, y, size); 
 
     cursorSquare.drawStylus(); 
 
     anim = window.requestAnimationFrame(animation) 
 
    }; 
 
    window.requestAnimationFrame(animation) 
 
    }; 
 

 
    function onMouseUp() { 
 
    if (mouseDown) { 
 
     window.cancelAnimationFrame(anim) 
 
     var newSquare = new createSquare(x, y, size); 
 
     objects.push([x, y, size]) 
 
     mouseDown = false 
 
    }; 
 
    }; 
 

 
    function loop() { 
 
    draw(); 
 
    window.requestAnimationFrame(loop); 
 
    }; 
 

 
    function init() { 
 
    loop(); 
 
    }; 
 

 
    init() 
 

 
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script> 
 
<canvas id='myCanvas' width="5000" height="5000" style="border:1px solid #000000;"></canvas>

+0

あなたは5000 * 5000の領域ごとに枠をクリアし、それが可能になるだろう本当に本当に遅い –

+0

私はちょうど700 * 700で試してみましたが、それでも同じ問題があります:( –

+0

あなたは大量のグローバル変数を作成しています。私はまずそれをきれいにするだろう。 –

答えて

0

役立つかもしれない物事のカップル:ここでは、コードです。

ループを開始する前に、objects.lengthをforループから取り出し、varに割り当てます。現在、ループの各インタラクションのオブジェクトの長さを数えます。

さらに、objects.forEachを使用して配列を反復処理します。

最後に、2つのforループの最後にdraw()が呼び出されるのはなぜですか?これはイベントループを非常に速く埋めることになり、スローダウンの主な理由が疑われます。

+0

JSは配列上の '.length'にアクセスするときオブジェクトを数えず、' .forEach() 'は' for'ループよりも遅くなる可能性がより高くなります。 –

+0

ありがとう、それはクラッシュで問題を修正しましたが、パーティクルはまだリアルタイムで移動しません...何か間違っていますか? –

+0

@OwM巨大な粒子があり、大きな空間を占めています。特に円であれば、時間がかかります。 –

1

オブジェクトごとにrequestAnimationFrameを呼び出していますが、これはrequestAnimationFrame(RAF)を使用する間違った方法です。

オブジェクトごとに1回ではなく、フレームごとに1回呼び出す必要があります。

function mainLoop(time){ // main loop RAF will add the time in milliseconds to the arguments. 
    ctx.clearRect(0,0,canvas.width,canvas.height); // clear 
    draw(); // call the draw loop 
    requestAnimationFrame(loop); // request next frame 
} 
requestAnimationFrame(loop); // request next frame 

ctx.arcのような描画関数を使用するのは非常に遅いです。代わりにctx.drawImageイメージをレンダリングすると、パフォーマンスが大幅に向上します。キャンバスを作成し、そのキャンバスに円弧を描画し、そのキャンバスをctx.drawImage(canvasImage,...で描画すると、はるかに高速な更新を得ることができます。

他の答えは(、行う一方で、用)

forEachまたは彼らは、標準のループを使用するよりもはるかに遅いですとしてコールバックを伴う配列関数のいずれかを使用していない、forEachを使用することができ忠告しました更新

ブラウザの世界では物事が急速に変化するため、この場合はforEachの使用をテストしました。この場合、ニュースは良くありません。比較するとforEachはまだ各反復に重大な追加のオーバーヘッドを追加しforwhile、およびdo while

注意すべき重要なことに(と私は最後の段落をstrikedなぜ)あなたが持っている場合、オーバーヘッドは、反復ごとにあるということです反復回数が少なく反復回数が多いため、オーバーヘッドは重要ではなく、心配する必要はありません。個人用コーディングスタイルは、そのような場合に使用するスタイルを選択する必要があります。

反復回数が多く、繰り返し回数が少ない場合、forEachを使用するとループのパフォーマンスに大きく影響します。

インラインコード(関数を呼び出さない)が標準の反復よりも10%遅くなるように標準的な繰り返しを表示するChrome、Edge、Firefoxの場合(forEachのような)関数呼び出し、そしてforEachの2倍以上の繰り返しごとのオーバーヘッドを伴う。 (各テストでは15-20対1のコードバランスを使用しました。つまり、反復処理のコードは反復処理に必要な最小コードの15-20倍です。したがってループ内にfor,forEachループと10〜15行のコードが1行で表示されます)

数千から数万の配列を扱っている場合は、違いが気になることはありません。何千も何百万もの100sを処理すると、あなたは避けるべきですforEach

注:入力された配列でforEachをテストしませんでしたが、この場合は該当しません。

  • クロームバージョン50.0.2661.37ベータメートル
  • Firefoxの46.0b2
  • でテスト

    エッジ25.10586

+0

これは私には間違いありません。しかし、1つのメモ。 'forEach'は、型付き配列では例外なくほぼ高速(〜10倍)です。しかし、 'forEach'は通常の配列ではるかに高速です。速度は、あなたがやっていることに非常に依存します。私は個人的に、最新のブラウザが毎回「forEach」を高速化することを発見しました。最初にテストしてください。 – Andrew

+0

@Andrew私はこれらのことを定期的にテストしますが、私は 'forEach'(と同様のもの)を何ヶ月もテストしていないことを認めなければなりません。 'forEach'が最終的に自分自身を使う価値があるとすれば、私の答えは変わります。 – Blindman67

+0

あなたはまだそれらを遅く見つけるかもしれません。再び、それはあなたがやっていることとあなたがそれをやっている方法に依存します。私のコールバックは、通常非常に簡単です(通常は不変です)。パフォーマンステスト(約6週間前)を実行しなければならなかった最後のときに、私は、forEachが通常の配列を反復することがほぼ20倍高速であることを発見しました。再テストされ、17倍も速くなりました。私はあなたのコードとあなたのJSエンジンが実行できる最適化に依存していると本当に思っています。しかし、perfが重要であるか、またはperf(問題のような)問題がある場合、切り替えが多大に役立つかもしれないと私は思います。 – Andrew

関連する問題