Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Graphics on canvas not being cleared properly?

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!

like image 355
Ben Avatar asked Nov 13 '22 14:11

Ben


1 Answers

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.

like image 166
Ben Avatar answered Nov 15 '22 07:11

Ben