How I tackled Collision Detection

I thought this would initially be fairly easy but actually took a couple of go’s and, if the forums are anything to go by, seem’s to be the biggest killer for most developers when making a game!

In the end I opted for the approach I saw using the XNA Platform Starter Kit – This approach only works when colliding to rectangles (Which was fine for Manic Spaceman) and involves calculating the Intersection Depth Vector between the two shapes.

All of the objects in my game inherit from the base GameObject class which has a public property CollisionBody which is of type “Rectangle”, as defined in my Geometry include. So I added the IntersectDepthVector function to my Rectangle class;

Rectangle.prototype.IntersectDepthVector = function (r) {
  // Calculate centers.
  centerA = new Vector2d(this.Left + this.HalfWidth, this.Top + this.HalfHeight);
  centerB = new Vector2d(r.Left + r.HalfWidth, r.Top + r.HalfHeight);

  // Calculate current and minimum-non-intersecting distances between centers.
  distanceX = centerA.x - centerB.x;
  distanceY = centerA.y - centerB.y;
  minDistanceX = this.HalfWidth + r.HalfWidth;
  minDistanceY = this.HalfHeight + r.HalfHeight;

  // If we are not intersecting at all, return (0, 0).
  if (Math.abs(distanceX) >= minDistanceX || Math.abs(distanceY) >= minDistanceY)
    return new Vector2d(0,0);

  // Calculate and return intersection depths.
  depthX = distanceX > 0 ? minDistanceX - distanceX : -minDistanceX - distanceX;
  depthY = distanceY > 0 ? minDistanceY - distanceY : -minDistanceY - distanceY;
  return new Vector2d(depthX, depthY);
}

The method will return you a Vector2d (v in the below example), with an x & y value set with the values you need to correct the intersection- This tells you a number of things;

  • If there was a collision; If (v.x != 0 || v.y != 0)
  • Which axis the collision occured on; If (v.x > v.y) then y axis, else on the x
  • Following on from the last point, which specific side the intersection occured on; Once you know which axis it was on, it’s just a matter of checking if the number is positive or negative to know which of the 2 sides of the axis were hit
  • How to correct the intersection; Simply add v to the position vector of your object to correct the intersection

The last point is important because this method doesn’t pre-empt collisions- you only get a report of a collision once it’s happened, which is no good if the collision is between your player and the floor! So you need to know how to correct that collision.

Now for a demo;

$("#canvas").mousemove(function(e){	
	movableBox = new Rectangle(new Vector2d(e.pageX - 30,e.pageY - 30),20,20);
	v = movableBox.IntersectDepthVector(fixedBox)

	absx = Math.abs(v.x);
	absy = Math.abs(v.y);
		
        // if a collision has happened		
	if (! (v.x ==0 && v.y ==0) ) {
		if (absx > absy) // the shallower impact is the correct one- this is on the y axis
		{
			axis = 'y';
			if (v.y < 0)
				loc = 'top';
			else
				loc = 'bottom';
		}
		else // the x axis!
		{
			axis = 'x';
			if (v.x < 0)
				loc = 'left';
			else
				loc = 'right';
		}

		//apply the intersection vector to the boxes position so we are no longer intersecting
		newpos = new Vector2d(movableBox.Position.x + v.x, movableBox.Position.y);
		movableBox = new Rectangle(newpos,20,20);

		// pick a red colour and draw the box
		context2D.strokeStyle = '#F00';
	}
	else
		context2D.strokeStyle = '#000';

        // update the status texts
	$('#status').html('x: ' + v.x + ' y: ' + v.y + '<br />axis: ' + axis + '<br />impact: ' + loc);

        // clear out the canvas ready to draw
	context2D.clearRect(0,0,800,600);
	
	// draw the boxes
	context2D.strokeRect(movableBox.Position.x,movableBox.Position.y,movableBox.Width,movableBox.Height);
	context2D.strokeRect(fixedBox.Position.x,fixedBox.Position.y,fixedBox.Width,fixedBox.Height);
});
  1. No comments yet.
(will not be published)