2012-02-09 16 views
0

私は小さなオブジェクト指向のjavasscriptデモを作成しています。この時点で何も想像もせず、衝突の検出も何もしません。私のBall.jsクラスが良いと仮定することは安全だと考えてください。HTML5コンテキスト/キャンバス - コンテキスト上の描画を呼び出すタイミング

私の質問はこれに相当します:どこでball.draw(コンテキスト)を呼び出す必要がありますか?私が設定した方法で画面に描画されるボールを得る唯一の方法は、generateBalls()にコールを置くことによるものと思われます。しかし、それは各ボールが一度描かれたことを意味します。

誰かが私のやり方の誤りをここで指摘できるなら、私は本当にそれを気楽にしています。これは宿題ではなく、javascriptとcanvasでより良い処理をしようとしています。

<!DOCTYPE HTML> 
<html> 
<head> 
<meta charset="utf-8"> 
<title>Untitled Document</title> 
<script src="ball.js"></script> 
<script src="utils.js"></script> 
... 
    <canvas id="canvas" width="600" height="480"></canvas> 
    <script type="text/javascript"> 
     window.addEventListener('load', eventWindowLoaded, false); 

     function eventWindowLoaded() { 
      canvasApp();  
     } 

     function canvasSupport() { 
      return true;  
     } 

     function canvasApp() { 
      if(!canvasSupport()) { 
       return; 
      } 
     } 
     console.log("app entered"); 
     var numBalls = 45; 
     //var numBalls = demo.numberofballs.value; 
     var maxSize = 8; 
     var minSize = 5; 
     var maxSpeed = maxSize + 5; 
     var balls = new Array(); 
     var tempBall; 
     var tempX; 
     var tempY; 
     var tempSpeed; 
     var tempAngle; 
     var tempRadius; 
     var tempRadians; 
     var tempXunits; 
     var tempYunits; 

     canvas = document.getElementById("canvas"); 
     context = canvas.getContext("2d"); 

     generateBalls(); 

     setInterval(drawScreen, 33); 

     function generateBalls() { 
      console.log("Make some balls"); 
      for(var index = 0; index < numBalls; index++) { 
       var tempRadius = Math.floor(Math.random()*maxSize)+minSize; 
       var ball = new Ball(tempRadius, "#000000"); 
       ball.x = tempRadius * 2 + (Math.floor(Math.random()*canvas.width) - tempRadius * 2); 
       ball.y = tempRadius * 2 + (Math.floor(Math.random()*canvas.height) - tempRadius * 2); 
       ball.speed = maxSpeed - tempRadius; 
       ball.angle = Math.floor(Math.random()*360); 
       ball.dx = Math.cos(tempRadians) * tempSpeed; 
       ball.dy = Math.sin(tempRadians) * tempSpeed; 
       // here outputted balls but a stupid place to put it LOL 
       balls.push(ball); 



      } 

     } 

     function drawScreen() { 
      console.log("draw screen"); 



      // loop through all balls and adjust their position 
      // a BallManager could do this more cleanly 
      for(var index = 0; index < balls.length; index++) { 

       context.fillStyle="#EE00EE"; 
       context.fillRect(0,0,canvas.width, canvas.height); 

       // Box 
       context.strokeStyle = "#ff0043"; 
       context.strokeRect(1,1,canvas.width-2, canvas.height-2); 

       // place balls 
       context.fillStyle = "#ff8783"; 
       console.log("ball mover loop in drawscreen"); 
       // no var ball now 

       ball = balls[index]; 
       ball.x += ball.dx; 
       ball.y += ball.dy; 
       ball.draw(context); 
       //checkBoundaries(balls[index]); 
       if(ball.x > canvas.width || ball.x < 0) { 
       ball.angle = 180 - ball.angle; 
       updateBall(ball); 
        } else if(ball.y > canvas.height || ball.y < 0) { 
         ball.angle = 360 - ball.angle; 
         updateBall(ball); 
         //ball.draw(context); 
       } 

      } 

     } 

     //function checkBoundaries(ball) { 
      //console.log("Check Bounds: " + " " + "ball.x: " + ball.x + " " + //"ball.y: " + ball.y); 

     //} 

     function updateBall(ball) { 
      ball.radians = ball.angle * Math.PI/180; 
      ball.dx = Math.cos(ball.radians) * ball.speed; 
      ball.dy = Math.sin(ball.radians) * ball.speed; 
      //ball.draw(context); 
     } 

    </script> 
</body> 
</html> 

+0

私は、可能なアプローチの1つは、背景をクリアし、現在の位置にすべてのボールを描画する画面更新のための関数を導入することができると思います。この関数は、setIntervalを介して呼び出す必要があります。 – Stan

答えて

2

あなたの例では、より多くの、1つのエラーを含む マルク、あなたのアドバイスをいただき、ありがとうございます。次は少し修正したコードです。それは働いていますが、それを拡張して修正する必要があります。

スタンは、1箇所のボールのそれぞれを描画する機能を作成する推奨:ちょうどここに到着したキャンバスに、新たな人のために、更新のビットを追加するためのスレッドをnecroing

<!DOCTYPE HTML> 
<html> 
    <head> 
    <meta charset="utf-8"> 
    <title>Untitled Document</title> 
    <script type="text/javascript"> 
    // next lines is a Ball() implementation code 
    Ball = function(radius,color) { 
     this.radius=radius; 
     this.color=color; 
    }; 
    Ball.prototype.x=0; 
    Ball.prototype.y=0; 
    Ball.prototype.speed=0; 
    Ball.prototype.angle=0; 
    Ball.prototype.dx=0; 
    Ball.prototype.dy=0; 
    Ball.prototype.radius=10; 
    Ball.prototype.color="#000"; 
    Ball.prototype.draw=function() { 

     context.beginPath(); 
     context.arc(this.x,this.y,this.radius,0,Math.PI*2,true); 
     context.lineWidth = 5; 
     context.strokeStyle = this.color; // line color 
     context.stroke(); 
     context.closePath(); 
    }; 

    window.addEventListener('load', eventWindowLoaded, false); 

    function eventWindowLoaded() { 
     canvasApp();  

     //console.log("app entered"); 
     window.canvas = document.getElementById("canvas"); 
     window.context = canvas.getContext("2d"); 

     generateBalls(); 
     // if you want to use setInterval() instead replace next line 
     setTimeout(drawScreen, 33); 
    } 

    function canvasSupport() { 
     return true;  
    } 

    function canvasApp() { 
     if(!canvasSupport()) { 
      return; 
     } 
    } 

    var numBalls = 45; 
    //var numBalls = demo.numberofballs.value; 
    var maxSize = 8; 
    var minSize = 5; 
    var maxSpeed = maxSize + 5; 
    var balls = new Array(); 
    var tempBall; 
    var tempX; 
    var tempY; 
    var tempSpeed; 
    var tempAngle; 
    var tempRadius; 
    var tempRadians; 
    var tempXunits; 
    var tempYunits; 

    function generateBalls() { 
     //console.log("Make some balls"); 
     for(var index = 0; index < numBalls; index++) { 
      var tempRadius = Math.floor(Math.random()*maxSize)+minSize; 
      var tempRadians = Math.random()*Math.PI; 
      var tempSpeed = 10; 
      var ball = new Ball(tempRadius, "#000000"); 
      ball.x = tempRadius * 2 + (Math.floor(Math.random()*canvas.width) - tempRadius * 2); 
      ball.y = tempRadius * 2 + (Math.floor(Math.random()*canvas.height) - tempRadius * 2); 
      ball.speed = maxSpeed - tempRadius; 
      ball.angle = Math.floor(Math.random()*360); 
      ball.dx = Math.cos(tempRadians) * tempSpeed; 
      ball.dy = Math.sin(tempRadians) * tempSpeed; 
      // here outputted balls but a stupid place to put it LOL 
      balls.push(ball); 
     } 
    } 

    function drawScreen() { 
     console.log("draw screen"); 


     context.fillStyle="#EE00EE"; 
     context.fillRect(0,0,canvas.width, canvas.height); 

     // Box 
     context.strokeStyle = "#ff0043"; 
     context.strokeRect(1,1,canvas.width-2, canvas.height-2); 

     // loop through all balls and adjust their position 
     // a BallManager could do this more cleanly 
     for(var index = 0; index < balls.length; index++) { 
      // place balls 
      context.fillStyle = "#008700"; 
      //console.log("ball mover loop in drawscreen"); 
      // no var ball now 

      ball = balls[index]; 
      ball.x += ball.dx; 
      ball.y += ball.dy; 
      ball.draw(context); 
      //checkBoundaries(balls[index]); 
      if(ball.x > canvas.width || ball.x < 0) { 
       ball.angle = 180 - ball.angle; 
       updateBall(ball); 
      } else if(ball.y > canvas.height || ball.y < 0) { 
       ball.angle = 360 - ball.angle; 
       updateBall(ball); 
       //ball.draw(context); 
      } 

     } 
     // if you want to use setInterval() instead remove next line 
     setTimeout(drawScreen, 33); 
    } 

    //function checkBoundaries(ball) { 
     //console.log("Check Bounds: " + " " + "ball.x: " + ball.x + " " + //"ball.y: " + ball.y); 

    //} 

    function updateBall(ball) { 
     ball.radians = ball.angle * Math.PI/180; 
     ball.dx = Math.cos(ball.radians) * ball.speed; 
     ball.dy = Math.sin(ball.radians) * ball.speed; 
     //ball.draw(context); 
    } 

    </script> 
    </head> 
    <body> 
    <canvas id="canvas" width="600" height="480" style="background:red;"></canvas> 
    </body> 
</html> 

http://jsfiddle.net/QVgZx/2/

+0

私はボールがここでどのように機能するかを見ていますが、これは私が鉱山を設定する方法です。 –

+1

@Marc H:あなたのコードには:1)は、以外のタグの中に '

0

コード内;これはいくつかの理由で良いことです。アニメーションをスムーズにし、コードをデバッグ/メンテナンスするのがはるかに簡単です。

しかし、私はStanに同意しませんでしたが、これを引き起こすためにsetIntervalを使用することについては、スタンがそれを書いたときによく行われていたことです。

ただし、requestAnimationFrameを使用します。

これは、あなたのペイントをブラウザの他の部分と同期させます。

これにより、ブラウザが何かを描画するたびに、ページ全体を再解析して、何かが動いた場合に備えて、すべてがどこに行くのかを判断する必要があります。

setIntervalを使用すると、いつ起動するのか保証されず、ブラウザの画面の更新と一致するまでに時間がかかることはありません。

これは、ページを再構成して、少し再描画し、再構成しなおして、もう一度描画することを意味します。これは非常に悪く、非常に遅いです。

しかし、requestAnimationFrameを使用すると、ブラウザーは、画面を再描画しようとするたびに関数を呼び出すことができます。つまり、1回の再描画と1回のリフレッシュを意味します。

はるかに速く、はるかにクリーナーです。

少し違って動作しますが、実際は非常に簡単です。

requestAnimationFrame(redraw); 

これは、ブラウザウィンドウを再描画したい次回は、あなたの関数が呼び出されるように、あなたの関数は、requestAnimationFrameので「再描画」に登録します。

これは、あなたの関数を1回だけ呼び出すということです。このように、setIntervalではなくsetTimeoutに似ています。

この方法では、アニメーションを停止するためにtimer変数を渡す必要はありません。停止したので停止します。

はしかし、あなたのアニメーションを実行し続けることを保証するために、ちょうどあなたの再描画機能の下部にある、非常に同じコールを置く:

function redraw() 
{ 
    var blah, blahblah; 
    ... 

    requestAnimationFrame(redraw); 
} 

あなたはまた、それがあるまで、あなたのアニメーションを実行するために、条件付きでこれを設定することができます完成し、その後、停止します。

function redraw() 
{ 
    ... 

    if (!finished) requestAnimationFrame(redraw); 
} 

Mozillaの参照HERE、ポール・アイリッシュHERE、そしてクリスCoyer HERE

関連する問題