Collision Detection on Canvas

I was toying around with a bouncing ball on an HTML canvas the other day when I wanted to find an easy way to detect collisions. One thing that is easy is validating against the bounds of the canvas. This is done with a simple check on the bounds of the canvas as follows:

//this is a Ball object
if (this.position.y > bound.y2) {
this.velocity.x2 = -this.velocity.x2 * drag;
this.position.y = bound.y2;
} else if (this.position.y < bound.y1) {
this.velocity.x2 = -this.velocity.x2 * drag;
this.position.y = bound.y1;
}
if (this.position.x < bound.x1) {
this.velocity.x1 = -this.velocity.x1 * drag;
this.position.x = bound.x1;
} else {
if (this.position.x > bound.x2) {
this.velocity.x1 = -this.velocity.x1 * drag;
this.position.x = bound.x2;
}
}

You’ll see that if we get the Ball beyond the bounds of either axis we reverse the velocity vector (and for my example) I augment that vector with some drag. Then I start the Ball off (headed the other direction now) from the start of the boundary. This is straight forward and not too difficult to come up with. The same can be done for other shapes on the canvas which we do not wish for the ball to pass through. These again can be simple if we know the layout and the position of the target walls (think floating boxes). Where this gets to a point where the shapes are not at right angles or the boundaries have become more arbitrary, I no longer want to calculate each possible collision point. I also do not wish to wrap the object into a larger boundary box to utilize for detection. So a more elegant solution can be found. If we, just before moving the ball, simulate the move and have another means for detection we can then change the trajectory of the object and send it sailing away. Here’s what we need. we need a ball sized snapshot of the canvas where we plan to put the ball on the next move. We then iterate through those pixels on the image and find ones that arent the color of our background (in my case non-white). To do this without also seeing the ball as a collided upon object, I’ll clear the canvas of the ball first. Here is the code:

//clear canvas, add shape
context.clearRect(0, 0, canvasWidth, canvasHeight);

context.fillStyle = "rgb(150,150,150)"; //not white
context.beginPath();
context.moveTo(200, 100);
context.lineTo(300, 125);
context.lineTo(250, 175);
context.lineTo(200, 200);
context.lineTo(200, 100);
context.fill();
context.closePath();

//now we check our next move for collision
var imgData = context.getImageData(this.position.x + this.velocity.x1, this.position.y + this.velocity.x2, r, r);
var pix = imgData.data;
for (var i = 0; n = pix.length, i < n; i += 4) {
//check if we're not on a white pixel
if (pix[i] != 0) {
this.collided = true;
//bounce away
if (Math.abs(this.velocity.x1) > Math.abs(this.velocity.x2)){
this.velocity.x1 = -this.velocity.x1 * drag;
} else {
this.velocity.x2 = -this.velocity.x2 * drag;
}
break;
} else {
this.collided = false;
}

}

Thats it! Now we can throw our ball at a target. The demo I have is located at this jsFiddle.