I wrote the following 1000 bounding squares demo as a test of the capabilities of HTML5 canvas. It runs fine at first but then a noticeable drop in fps after a few seconds. I am not sure why. Any pointers would be appreciated.
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);
There are a few issues with the code but the main reason for this to happen is this code:
This code will require you to use beginPath()
:
function clear(){
context.fillStyle = "#d0e7f9";
context.beginPath();
context.rect(0,0,WIDTH,HEIGHT); /// this will require beginPath();
context.fill();
}
or to avoid it, you can simply modify the code to do this:
function clear(){
context.fillStyle = "#d0e7f9";
context.fillRect(0,0,WIDTH,HEIGHT); /// this does not require beginPath();
}
/// 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
The setInterval
may cause the whole thing to stack calls if the browser is not fast enough processing the sprites within the time budget you give,.
By using rAF the browser will only request a frame when it can even if that means lower frame rates - you will at least not lock up/slow down the browser.
(as you didn't provide a link to the image you're using I substituted it with a temp canvas - you will still need to consider a onload
event handler for the actual image).
A few suggestions:
Use image.onload to be sure your square.png is fully loaded before it's used.
Put the image loading at the bottom of your code after you create your 1000 sprites.
var image=new Image();
image.onload=function(){
draw();
}
image.src="square.png";
Don't iterate using for(i in SpriteList). Do this instead:
for(var i=0;i<SpriteList.length;i++)
Your draw functions are probably stacking--the current draw() isn't being completed before setInterval is requesting another draw().
Replace setInterval with requestAnimationFrame to stop your stacking problems.
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);
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.