5

I want to check if circles are colliding with each other.

I know I can do this by getting a distance between the two centers of the circles and subtracting the radius of each circle from that distance and seeing if 'distance' is > 1.

How can I do this efficiently though with say, 1000 circles? Maybe I can somehow get the nearest 20 circles or something like that and check these? I don't know how I would begin to go about that efficiently though either..

Any ideas?

Here is an example:

http://experiments.lionel.me/blocs/

Max Hudson
  • 9,961
  • 14
  • 57
  • 107

4 Answers4

7

Before you start calculating exact differences in distances, you can at least compare the x/y positions of the centers v.s. the radii. That information is implicitly available in the circle and requires just some simple comparisons and addition/subtraction.

That'll let you compare the simple distances in x/y between all the circle pairs, and throw away any that are obviously not collision candidates, e.g.

abs(x2 - x1) > (r2 + r1)
abs(y2 - y1) > (r2 + r1)

... if the distance in X or Y between the circle centers is greater than the sum of the radii, then they cannot be colliding.

Once you've whittled down the possible colliders, THEN you do the formal exact cartesian distance, which is where the 'heavy' multiplication/division stuff comes in.

Marc B
  • 356,200
  • 43
  • 426
  • 500
2

Consider storing the coordinates of the circles' centers in a quad tree, then you would only need to check whether the circle intersects with other circles in that quadrant or adjacent quadrants.

The one caveat is that you need to sure the quad tree's leaf nodes have a minimal diameter of the radius of your largest circle, otherwise you will have to check more than just adjacent nodes for intersection.

http://en.wikipedia.org/wiki/Quadtree

If your circles are well scattered, then a simple optimization you can do is to store your circles sorted on the x or y axis, then you only need to check with circles who's x or y coordinate is within the radius of the circle.

Charles Ma
  • 47,141
  • 22
  • 87
  • 101
0

The efficiency is going to be concerned with the speed of the algorithms you are using, for instance the speed of the square root algorithm that you calculate the distance with, and your data structures will determine the efficiency of memory, in addition to algorithms. Another way to speed up the calculations would be to reduce the precision of the distance calculations.

The best method to detect if the circles are colliding is, as you said, to store the circles' center coordinates and radius in variables and compute whether or not the distance between the centers is equivalent to 0 when the radii are subtracted.

Alex W
  • 37,233
  • 13
  • 109
  • 109
0

I highly recommend Keith Peter's AdvancED ActionScript 3.0 Animation book, where you can find the concrete implementation of Quadtree algorithm in Actionscript.

Here are the basic steps:

  • First create a two dimensional grid and scatter all the balls randomly across the field.

    private function createGrids():void {
        _grids = new Array();
        for (var i:int = 0; i< stage.stageWidth / GRID_SIZE; i++) {
            _grids[i] = new Array();
            for (var j:int = 0; j< stage.stageHeight / GRID_SIZE; j++) {
                _grids[i][j] = new Array();
            }
        }
    }
    
  • Assign balls to grid cells

    private function assignBallsToGrid():void {
        for (var i:int = 0; i< numBalls; i++) {
            var ball:Ball = Ball(_balls[i]);
            var xpos:int = Math.floor(ball.x / GRID_SIZE);
            var ypos:int = Math.floor(ball.y / GRID_SIZE);
            _grids[xpos][ypos].push(ball);
        }
    }
    
  • Check if two balls are colliding in a single cell, then check the balls in adjacent cells. As Charles Ma mentioned the only consideration here the grid cells dimension must be greater or equal to the largest ball diameter.

    private function checkOneCell(x1:Number, y1:Number):void {
        var _cell:Array = _grids[x1][y1] as Array;
        for (var i:int = 0; i< _cell.length-1; i++) {
            var ballA:Ball = _cell[i] as Ball;
            for (var j:int = i+1; j< _cell.length; j++) {
                var ballB:Ball = _cell[j] as Ball;
                checkCollision(ballA, ballB);
            }
        }
    }
    
    private function checkTwoCell(x1:Number, y1:Number, x2:Number, y2:Number):void {
        if (x2 < 0) { return } 
        if (x2 >= _grids.length) { return }
        if (y2 >= _grids[x2].length) { return }
    
        var _cell0:Array = _grids[x1][y1] as Array;
        var _cell1:Array = _grids[x2][y2] as Array;
    
        for (var i:int = 0; i< _cell0.length; i++) {
            var ballA:Ball = _cell0[i] as Ball;
            for (var j:int = 0; j< _cell1.length; j++) {
                var ballB:Ball = _cell1[j] as Ball;
                checkCollision(ballA, ballB);
            }
        }
    }
    
    private function checkCollision(ballA:Ball, ballB:Ball):void {
        var dx:Number = ballB.x - ballA.x;
        var dy:Number = ballB.y - ballA.y;
        var dist:Number = Math.sqrt(dx*dx + dy*dy);
        if (dist < ballB.radius + ballA.radius) {
                         // do something
        }
    }
    
  • Here is how it looks like the main method:

    private function checkBallsCollision():void {
        for (var i:int = 0; i< _grids.length; i++) {
            for (var j:int = 0; j< _grids[i].length; j++) {
                checkOneCell(i, j);
    
                checkTwoCell(i, j, i+1, j);
                checkTwoCell(i, j, i, j+1);
                checkTwoCell(i, j, i-1, j);
                checkTwoCell(i, j, i+1, j+1);
            }
        }
    }
    

NOTE:

The code is written in Actionscript but can be implemented quite easily in Javascript.

Endre Simo
  • 11,330
  • 2
  • 40
  • 49