我正在研究HTML5画布上的概念验证。我能够像Chrome和IE9中的魅力一样工作,但在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>
答案 0 :(得分:5)
我已经将你的例子提炼到了这个:
它在Firefox和Chrome中的运行速度非常快。
所以我们知道问题在于图像。
您需要优化它们的创建和加载方式。现在,每个clear()
创建一个新图像并等待它加载!该图片只能在loadGame()
中创建一次,然后反复重复使用。
与letterImg
中的DrawRain()
完全相同。将其创建移至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
}
};
答案 1 :(得分:1)
补充Simon Sarris的回应。我使用了“双帆布”技术来避免用厚帆布进行屏幕争吵。
它的工作方式总是有两个版本的画布,一个在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();
}
(...)