I'm trying to squeeze every last bit of performance out of my canvas game; recently I found out that clearing the canvas is very performance heavy, so I'm trying to find a way to replace clearing the entire canvas every frame. However I'm finding a few problems with the new method I'm trying, which is to clear each object's bounding box individually, then update them.
The problem is that elements get 'left behind' as they leave the canvas and some part of the image remains. I tried simplifying the code to make sure the problem wasn't in the rest of the code and no joy.
Returning to wiping the entire canvas each frame is undesirable too, especially as this new method is a lot faster. Here's the code (for some reason it doesn't work as a fiddle).
var enemyCtx = document.getElementById('enemy').getContext('2d');
var game =
{
w: 800,
h: 500
};
var enemies = [];
window.addEventListener('load', function()
{
for (var i = 0; i < 200; i++)
{
enemies[enemies.length] = new Enemy();
}
update();
}, false);
var buffer = document.createElement('canvas');
buffer.width = 42;
buffer.height = 42;
var bufferCtx = buffer.getContext('2d');
drawEnemy(bufferCtx, 5, 5, 32, 32, 'red');
function update()
{
for (var i = 0; i < enemies.length; i++)
{
enemyCtx.clearRect( enemies[i].x,
enemies[i].y,
enemies[i].x + enemies[i].width,
enemies[i].y + enemies[i].height);
}
for (var i = 0; i < enemies.length; i++)
{
enemies[i].x-=5;
enemyCtx.drawImage(buffer, enemies[i].x-5, enemies[i].y-5);
}
requestAnimationFrame(update);
}
function drawEnemy(ctx, x, y, width, height, colour)
{
ctx.lineWidth = 1;
ctx.strokeStyle = colour;
ctx.strokeRect(x + 0.5, y + 0.5, width, height);
}
function Enemy()
{
this.x = Math.random()*game.w;
this.y = Math.random()*game.h;
this.width = 32;
this.height = 32;
}
(function()
{
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x)
{
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame) window.requestAnimationFrame = function(callback, element)
{
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function()
{
callback(currTime + timeToCall);
}, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame) window.cancelAnimationFrame = function(id)
{
clearTimeout(id);
};
}());
& html:
<canvas id="enemy" width="800" height="500"></canvas>
Any insight you guys could give me would be very useful; thanks!
Had a bit more thought about this and I came up with a solution; perhaps it may be of some benefit to you guys.
Basically the image is 'left behind' on the canvas because the clearRect() method needs to work with actual canvas co-ordinates. Because the image is leaving the canvas its co-ordinates are going to be negative values.
function update()
{
for (var i = 0; i < enemies.length; i++)
{
lx = (enemies[i].x > 0) ? enemies[i].x : 0;
ly = (enemies[i].y > 0) ? enemies[i].y : 0;
enemyCtx.clearRect( lx,
ly,
lx + enemies[i].width + 1,
ly + enemies[i].height + 1);
}
// ...
}
The additional 1 to the width is to stop the canvas drawing the last pixel column of the image as it is being erased. Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With