2011-04-15 122 views
4

我正在研究HTML5畫布上的概念驗證。我能夠在Chrome和IE9中像魅力一樣工作,但在Firefox 4中,我重新繪製畫布時會不斷閃爍。我已經嘗試了在這個網站上提到的一些技術,例如雙緩衝,但我仍然收到大量的閃爍。任何有關這方面的見解將不勝感激!HTML5畫布在FireFox中閃爍4

<!DOCTYPE HTML> 
<html> 
<head> 
<style type="text/css"> 
body 
{ 
    margin:0px; 
    padding:0px; 
    text-align:center; 
} 
canvas 
{ 
    outline:0; 
    border:1px solid #000; 
    margin-top: 10px; 
    margin-left: auto; 
    margin-right: auto; 
} 
</style> 
<script type="text/javascript"> 
var canvasWidth = 640; 
var thisXPos = 0; 
var canvasHeight = 820; 
var thisYPos = 0; 
var canvas = null; 
var context = null; 
var gLoop = null; 
var rain = []; 
var rainImg = "images/raindrop.gif"; 
var bgImg = null; 
var i; 

for (i = 0; i < howManyLetters; i++) 
{ 
    rain.push([Math.floor(Math.random() * canvasWidth), Math.floor(Math.random() * canvasHeight),rainImg]); 
} 

var DrawRain = function() 
{ 
    for (i = 0; i < 10; i++) 
    { 
     thisXPos = rain[i][0]; 
     thisYPos = rain[i][1]; 
     imgSrc = rain[i][2]; 
     letterImg = new Image(); 
     letterImg.setAtX = thisXPos; 
     letterImg.setAtY = thisYPos; 
     letterImg.onload = function() 
     { 
      context.drawImage(this, this.setAtX, this.setAtY); 
     } 
     letterImg.src = imgSrc; 
    } 
}; 

var MoveRain = function(e) 
{ 
    for (i = 0; i < 10; i++) 
    { 
     if ((rain[i][1] - 5) > canvasHeight) 
     { 
      randomnumber = Math.floor(Math.random()*26); 

      rain[i][0] = Math.random() * canvasWidth; 
      rain[i][1] = 0; 
      rain[i][2] = rainImg; 
     } 
     else 
     { 
      rain[i][1] += e; 
     } 
    } 
}; 

var clear = function() 
{ 
    context.beginPath(); 
    context.rect(0, 0, canvasWidth, canvasHeight); 
    context.closePath(); 

    bgImg = new Image(); 
    bgImg.src = "images/bg.png"; 
    bgImg.onload = function() 
    { 
     context.drawImage(bgImg,0,0); 
    } 
} 

var GameLoop = function() 
{ 
    context.save(); 
    clear(); 
    MoveRain(1); 
    DrawRain(); 
    context.restore(); 

    gLoop = setTimeout(GameLoop, 10); 
} 

function loadGame() 
{ 
    canvas = document.getElementById("gameCanvas"); 
    context = canvas.getContext("2d"); 
    canvas.width = canvasWidth; 
    canvas.height = canvasHeight; 

    GameLoop(); 
} 

</script> 
</head> 
<body onload="loadGame();"> 
    <canvas id="gameCanvas"></canvas> 
</body> 
</html> 

回答

5

我已經蒸你的榜樣到這一點:

http://jsfiddle.net/sPm3b/6/

和它的作品非常快,Firefox和Chrome。

所以我們知道問題在於圖像。

您需要優化它們的創建和加載方式。現在,每個clear()創建一個新的圖像,並等待它加載!該圖像只能在您的loadGame()中創建一次,然後反覆重複使用。

letterImgDrawRain()相同。將其創建到loadGame()

這可能會解決問題。

編輯:

這樣的:

在頂部加入:

var letterImg = new Image(); 
var bgImg = new Image(); 

然後

function loadGame() 
{ 
    canvas = document.getElementById("gameCanvas"); 
    context = canvas.getContext("2d"); 
    canvas.width = canvasWidth; 
    canvas.height = canvasHeight; 

    bgImg.src = "images/bg.png"; 
    letterImg.src = "images/raindrop.gif"; 

    // optional: wait for them to load here 

    GameLoop(); 
} 

然後drawRain,例如,應該是這樣的:

var DrawRain = function() 
{ 
    for (i = 0; i < 10; i++) 
    { 
     thisXPos = rain[i][0]; 
     thisYPos = rain[i][1]; 
     context.drawImage(letterImg, thisXPosX, thisYPos); // letterImg was already constructed, no need to make it again 
    } 
}; 
+0

我消除了原圖像雖然和部分「重新繪製」它先前的位置低於1個像素,從而顯示下降。也許我誤解了你的例子的工作原理。如果我在loadGame()中創建圖像對象,我怎樣才能在畫布中重新繪製它們的位置? – Dexter 2011-04-15 14:28:55

+0

我編輯了一下,讓它更清晰一些。如果您願意,您可以清除畫布並重新繪製已經加載的圖像,這是沒有問題的。 – 2011-04-15 15:26:33

+0

謝謝!工作完美! – Dexter 2011-04-15 17:10:53

1

補充Simon Sarris的迴應。我已經使用了「雙層帆布」技術來避免屏幕與厚重的畫布發生糾纏。

它的工作方式總是有2個版本的畫布,一個在DOM中,一個在外面,並且始終使用繪製不在DOM中的那個。我用它與重繪隊列。

這裏的工作代碼

(...) 
clear: function() { 
    //rotating on 2 canvas, one for draw (outside DOM) one for show 
    var self = this; 
    if (null == self.canvasbackup) { 
     var tmpcanvas = self.canvas.clone(true); 
     self.canvasbackup = self.canvas; 
     self.canvas=tmpcanvas; 
    } else { 
     var tmpcanvas = self.canvasbackup; 
     self.canvasbackup = self.canvas; 
     self.canvas=tmpcanvas; 
    } 
    self.ctx = self.canvas[0].getContext('2d'); 
    self.ctx.clearRect(0, 0, self.options.width, self.options.height); 
    jQuery.each(self.elements,function(idx,elt){ 
     // custom function: my elements need to know which canvas they depends on 
     elt.reconnectCanvas(self.canvas,self.ctx); 
    }); 
}, 
inDOM: function() { 
    var self = this; 
    if(null==self.canvasbackup) { 
     //1st time need to get all things in DOM 
     self.canvas.appendTo(self.div); 
     self.div.appendTo(self.container); 
    } else { 
     // remove current shown canvas 
     self.connectHuman(); 
     self.canvasbackup.remove(); 
     // loosing some events here... 
     self.canvas.appendTo(self.div); 
     // div is already in DOM, we are in redraw 
    } 
}, 
redraw: function() { 
    var self = this; 
    self.clear(); 
    jQuery.each(self.elements,function(idx,elt){ 
     elt.draw(); 
     elt.enddraw(); 
    }); 
    self.inDOM(); 
} 
(...)