Search code examples
javascriptcollision-detection

My collision detection algo seems to trigger even before the objects touched


I wrote a very simple collision detection demo: http://jsfiddle.net/colintoh/UzPg2/5/

As you can see, the objects sometimes doesn't connect at all but yet the collision is being triggered. The radius for the balls are 10px so the algo triggered the collision whenever the distance between two balls center is less than 20px. I reduced it to 18px for a better visual but the empty collision still happens randomly. Am I doing something wrong?


Solution

  • It looks like you are not using the right formula for distance between two points. See http://www.purplemath.com/modules/distform.htm for a full explanation.

    You are doing this:

    this.ballCollide = function(balli) {
        if (Math.abs((this.x) - (balli.x)) < (2*radius - buffer)) {
            if (Math.abs((this.y) - (balli.y)) < (2*radius - buffer)) {
                 // Do collision
            }
        }
    };
    

    That's a square bounding box, not a circular one. To get a circular bounding box, you can do something like this, based on the formula in the referenced web page:

    this.ballCollide = function(balli) {
        var deltax = this.x - balli.x;
        var deltay = this.y - balli.y;
        if (Math.sqrt(deltax * deltax + deltay * deltay) < 2 * radius - buffer) {
            // Do collision
        }
    };
    

    See http://jsfiddle.net/UzPg2/14/ for a working example.

    Note that a perfect circular bounding box is a much slower algorithm than a square bounding box approximation.

    Following Jarrod Roberson's point (a perfect circle is always inside a perfect square), you'd do that by basically combining your original code with the code I posted, like this (and you could combine them both into one conditional switch if you wanted to):

    var deltax = this.x - balli.x;
    var deltay = this.y - balli.y;
    var dist = 2 * radius - buffer;
    if (Math.abs(deltax) < dist && Math.abs(deltay) < dist) {
        if (Math.sqrt(deltax * deltax + deltay * deltay) < dist) {
           // Do collision
        }
    }
    

    See http://jsfiddle.net/UzPg2/21/ for a working example (I've left the buffer as your variable is called at 2, but I personally think it looks better with a value of 1).

    There are also many other ways you can optimize this for speed if you need to, but Jarrod's suggestion gives you the biggest immediate speed boost.