2013-05-28 40 views
6

我正在研究模擬引力的JavaScript遊戲。它使用HTML5 canvas元素爲行星繪製2D橢圓。我在谷歌瀏覽器中測試我的遊戲。這裏有一個鏈接到遊戲:http://gravitygame.hostingsiteforfree.com/index.php?page=playHTML爲什麼canvas2d上下文不再填充橢圓?

截至5月24日,它的工作就好了。但是,Chrome從26.0.1410.64升級到27.0.1453.94後,填充的橢圓有時不會繪製。每次我加載我的遊戲時都不會發生這種情況,我從來沒有在本地運行時讓它崩潰。

這裏的遊戲工作的截圖:enter image description here

這裏是一個說明它不填充的橢圓截圖:enter image description here

我不能告訴發生了什麼。我將包括繪製所有行星的循環部分。爲了便於閱讀,我對其進行了修改。

var i = bodies.length; 
    while(i--){ 
    var I = bodies[i]; 
    var planetRad = (I.width/2)*_scale; 
    if(_showTrails){ 
     //draw the planet's trail 
    } 
    if(//the planet is completely off the screen){ 
     //draw a red planet on the edge of the screen 
     ctx.beginPath(); 
     ctx.arc(nX, nY, 2.5, 0, TWOPI); 
     ctx.fillStyle = offScreenColor; 
     ctx.fill(); 
     ctx.strokeStyle = offScreenOutline; 
     ctx.stroke(); 
    } 
    else{ 
     //draw planet 
     ctx.beginPath(); 
     ctx.arc(nX, nY, (I.width/2)*_scale, 0, TWOPI); 
     ctx.closePath(); 
     ctx.fillStyle = I.bodyColor; 
     ctx.fill();  
    } 
    if(_showMotionVector){ 
     //draw a line from the center of a planet showing the direction and speed it's travelling 
     ctx.strokeStyle = motionColor; 
     ctx.beginPath(); 
     ctx.moveTo(I.getScX(), I.getScY()); 
     ctx.lineTo(I.motion.x * _scale * 12 + I.getScX(), I.motion.y * _scale * 12 + I.getScY()); 
     ctx.stroke(); 
    } 
} 

爲什麼它會突然中斷?

+0

我遇到了類似的問題與IE瀏覽器,所以這裏試試。如果你添加ctx.closePath();在示例代碼中的第一個弧之後? – markE

+0

這沒有奏效。每過一段時間,我仍然可以讓它加載它,行星不會出現。 – Justin

+0

無法在Chrome或Canary(+其他瀏覽器)中重現(在FF平移不適用於我btw)。你如何觸發動畫循環? – K3N

回答

5

我看了一下你的在線代碼,發現你在動畫循環中使用了setInterval

這是最有可能的原因是如果代碼是不能完成調用運行堆棧調用的風險Calcs(計算)等 - 的情況下,這意味着你可以有路徑這麼復位對方。

嘗試先用setTimeout更換setInterval。當然,您將需要從代碼中又重新觸發了 - 更重要的是,把一切都放在一個函數具有的setTimeout在該函數結束,即:

function animate() { 
    //... calcs and redraws which you have in setInterval 
    setTimeout(animate, 0); 
} 
animate(); 

我用0超時這裏這個測試。在任何情況下,setTimeout/setInterval都不會同步到屏幕刷新率。

如果那有效,那麼你知道原因。下一步是用​​替換它,但讓我知道它是怎麼回事。

在試圖說明這個問題,我們可以看一下這個圖示中:

Working interval

每個塊代表的功能的環內,以及一個環是一種顏色。請記住,在setInterval呼叫固定間隔而setTimeout調用相對當它叫。在這個例子中,功能在時間預算內執行,所以一切都很順利。

在下一個示意圖:

Stacking interval

的支出預算,以便setInterval再次調用外部和第一完成之前下一個呼叫排隊至第二環。當隊列在兩次調用之間進行處理時,最終有可能在「同一時間」有兩個函數在上下文中工作(或者與您預期的順序不同)。

Javascript當然是單線程的,所以它們不會同時執行,但是其中一個被保持等待 - 如果在最後一個塊有時間被調用之前調用下一個隊列的第一個塊,那麼第一個塊將修改上下文,甚至可能在調用上一次調用的最後一次調用之前更改路徑。隨着時間的推移,滯後將增加並且潛在地(除非一些額外的可用處理資源不時地解決隊列 - 在繁忙的系統上這不太可能發生)隨着更多堆疊發生而變得越來越差。

也就是說,在這種情況下,您可以在arc填充前將行添加到上下文中beginPath()

(希望做出任何意義......)

使用setTimeout會阻止這種在動畫循環的所有調用返回的時候,纔不會被執行。更好的選擇是使用requestAnimationFrame,因爲這將調用與屏幕刷新率同步,並且在可能的情況下。它更低級,因此也更高效。

另一條路徑(無雙關語)是使用Web-workers來進行計算。這將是多線程的,並且可以提高整體性能,因爲Web工作人員不會影響UI線程。

+0

我對setTimeout()的初始測試似乎有效。不過,在我確信之前,我必須在幾臺電腦上試用它。我會讓你知道結果。 – Justin

+1

迄今爲止看起來不錯。除了從setInterval切換到setTimeout之外,我必須在第一條評論中提到您所提到的更改。 – Justin