我编写了以下1000个边界方块演示,作为HTML5 canvas功能的测试。它首先运行良好,但几秒后fps明显下降。我不知道为什么。任何指针都会受到赞赏。
var c = document.getElementById("canvas");
var context = c.getContext("2d");
var WIDTH = 600;
var HEIGHT = 800;
c.width = WIDTH;
c.height = HEIGHT;
image = loadImage("square.png");
function loadImage(imageName){
var i = new Image();
i.src = imageName;
return i;
}
function clear(){
context.fillStyle = "#d0e7f9";
context.rect(0,0,WIDTH,HEIGHT);
context.fill();
}
clear();
var SpriteList = [];
var Sprite = (function() { //javascript class(?)... shredders
function Sprite(){ //constructor
this.x = Math.random()*WIDTH;
this.y = Math.random()*HEIGHT;
this.vx = Math.random()*10;
this.vy = Math.random()*10;
SpriteList.push(this);
}
Sprite.prototype.update = function(){
this.x += this.vx;
this.y += this.vy;
if (this.x<0 || this.x>WIDTH){
this.vx *= -1;
}
if (this.y<0 || this.y>HEIGHT){
this.vy *= -1;
}
};
return Sprite;
})();
for (var i = 0;i<1000;i++){
new Sprite();
}
function draw(){
clear();
for (i in SpriteList)
{
var s = SpriteList[i];
s.update();
context.drawImage(image, s.x, s.y);
}
}
setInterval(draw,1000/60);
答案 0 :(得分:2)
代码存在一些问题,但主要原因是此代码:
此代码要求您使用beginPath()
:
function clear(){
context.fillStyle = "#d0e7f9";
context.beginPath();
context.rect(0,0,WIDTH,HEIGHT); /// this will require beginPath();
context.fill();
}
或者为了避免它,您只需修改代码即可:
function clear(){
context.fillStyle = "#d0e7f9";
context.fillRect(0,0,WIDTH,HEIGHT); /// this does not require beginPath();
}
<强> Live fiddle here 强>
/// use a var here
var image = loadImage("square.png");
/// your image loader is missing - image may not show up
function loadImage(imageName){
var i = new Image();
i.onload = nextStep; /// something like this
i.src = imageName;
return i;
}
var SpriteList = [];
/// create this as an object
function Sprite(){ //constructor
this.x = Math.random()*WIDTH;
this.y = Math.random()*HEIGHT;
this.vx = Math.random()*10;
this.vy = Math.random()*10;
return this;
}
Sprite.prototype.update = function(){
this.x += this.vx;
this.y += this.vy;
if (this.x<0 || this.x>WIDTH){
this.vx *= -1;
}
if (this.y<0 || this.y>HEIGHT){
this.vy *= -1;
}
};
/// separate pushing of the instances
for (var i = 0;i<1000;i++){
SpriteList.push(new Sprite());
}
var oldTime = 0;
function draw(timeElapsed){ /// in milliseconds
clear();
var diffTime = timeElapsed - oldTime;
/// use vars here too
for (var i = 0, s; s = SpriteList[i]; i++ )
{
s.update();
context.drawImage(image, s.x, s.y);
}
oldTime = timeElapsed;
/// use rAF here
requestAnimationFrame(draw);
}
draw(0); /// start
如果浏览器在你给出的时间预算内处理精灵的速度不够快,setInterval
可能会导致整个事件堆叠调用。
通过使用rAF,浏览器只会请求一个帧,即使这意味着更低的帧速率 - 您至少不会锁定/减慢浏览器。
(因为你没有提供你正在使用的图像的链接我用temp画布替换它 - 你仍然需要考虑实际图像的onload
事件处理程序。)
答案 1 :(得分:1)
一些建议:
使用image.onload以确保square.png在使用之前已完全加载。
在创建1000个精灵后,将图像加载到代码的底部。
var image=new Image();
image.onload=function(){
draw();
}
image.src="square.png";
不要使用for(i在SpriteList中)进行迭代。这样做:
for(var i=0;i<SpriteList.length;i++)
你的绘图函数可能是堆叠的 - 当setInterval请求另一个draw()之前,当前draw()没有完成。
将setInterval替换为requestAnimationFrame以停止堆叠问题。
function draw(){
// request another animation frame
requestAnimationFrame(draw);
// draw the current frame
clear();
for(var i=0;i<SpriteList.length;i++)
{
var s = SpriteList[i];
s.update();
context.drawImage(image, s.x, s.y);
}
}