Experiment 2: Collision Detection

Sections in this Article:

Circle To Circle Collision Detection

Following on from detecting when a circle is entirely within another, an extension to this method is to determine when two circles collide, e.g. when the begin to overlap. Examing the image below:

The explanation is as follows:

  • It can be stated that when the sum of radius, r1 and r2 of cirlces c1 and c2 are less than the distance H between the centre points of cirlces c1 and c2, then the circles are overlapped or collided, or simply put:
  • Circles c1 and c2 are overlapped when: r1 + r2 < H
  • H can again be calculated using Pythagoras theorem H2=a2+b2 with the right angled triangle being defined as sides a and b, where a = x1-x2 and b = y1-y2
  • Which finally gives the following: r1 + r2 < ((x1-x2)2 + (y1+y2)2)0.5

To see a live example of this in action, mouse over our touch (or in this example, drag your finger over) the image below to position the smaller circle. When the smaller circle overlaps or collides within the larger circle, the small circle will change colour to red.

Code - Circle in Circle

The full code for the Circle in Circle demonstration is listed below.

1(function() {
2    // create svg element in div element with name "demo"
3    var host = document.getElementById("demo");
4    
5    var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
6    svg.setAttribute("width","100%");
7    svg.setAttribute("height","400px");
8    svg.setAttribute("style", "background-color: silver;");
9    host.appendChild(svg);
10
11    // create objects to keep track of where the circles are...
12
13    // add circle c1
14    var circle1 = {
15        "id": "circle1",
16        "x": 200,
17        "y": 200,
18        "r": 100,
19        "fill": "green"
20    };
21
22    // create an SVG circle based on the definition of circle1
23    var c1 = createCircle(circle1, svg);   
24
25    // add circle c2
26    var circle2 = {
27        "id": "circle2",
28        "x": 30,
29        "y": 30,
30        "r": 40,
31        "fill": "yellow"
32    };
33
34    // create an SVG circle based on the definition of circle2
35    var c2 = createCircle(circle2, svg);
36
37    // add mouse move handler to svg
38    svg.addEventListener('mousemove',function(e) {
39        var loc = cursorPoint(e);
40        c2.setAttribute("cx", loc.x);
41        c2.setAttribute("cy", loc.y);
42
43        circle2.x = loc.x;
44        circle2.y = loc.y;
45
46        if( isCircleCollided(circle1, circle2)) {
47            c2.setAttribute("fill", "red");
48        } else {
49            c2.setAttribute("fill", circle2.fill);
50        }
51      },false);
52
53    // on touch handler (for mobile devices)
54    svg.addEventListener('touchmove',function(e) {
55        var touchItem = e.touches[0];
56        var loc = {
57            x: touchItem.clientX,
58            y: touchItem.clientY
59        }
60
61        //var loc = cursorPoint(e);
62        c2.setAttribute("cx", loc.x);
63        c2.setAttribute("cy", loc.y);
64
65        circle2.x = loc.x;
66        circle2.y = loc.y;
67
68        if( isCircleCollided(circle1, circle2)) {
69            c2.setAttribute("fill", "red");
70        } else {
71            c2.setAttribute("fill", circle2.fill);
72        }
73      },false);
74
75    // need to translate the position to the SVG coordinate space
76    var svgPoint = svg.createSVGPoint();
77    function cursorPoint(evt){
78        svgPoint.x = evt.clientX;
79        svgPoint.y = evt.clientY;
80        return svgPoint.matrixTransform(svg.getScreenCTM().inverse());
81    }
82
83    // here's where the maths is applied...
84    function isCircleCollided(parent, child) {
85        // triangle sides
86        var a = child.x - parent.x;
87        var b = child.y - parent.y;
88
89        // apply Pythagoras...
90        var h_sqr = Math.pow(a,2) + Math.pow(b,2);
91
92        // now the detection part (suqaring the radius' as more efficent than square roots!)
93        // see https://scicomp.stackexchange.com/questions/2168/what-is-the-computational-cost-of-sqrtx-in-standard-libraries
94        return h_sqr < Math.pow((parent.r + child.r), 2);
95    }
96
97    function createCircle(circle, svg) {
98        var element = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
99        element.setAttribute("id", circle.id);
100        element.setAttribute("cx", circle.x);
101        element.setAttribute("cy", circle.y);
102        element.setAttribute("r", circle.r);
103        element.setAttribute("fill",circle.fill);
104        element.setAttribute("fill-opacity","80%");
105        svg.appendChild(element);
106        return element;
107    }
108})();
109
110
111

Walk Through

If the code above isn't self-explanatory, here's some additional notes to guide through what's going on. Most of the code presented is more around getting the demo working and not the actual detection mechanism, which is only really a few lines of code!

  • Line 1 Definition of a self-invoking function to get everything up and running when the JavaScript begins execution.
  • Line 3 Locate the demo element in the main document - this is where the svg for the demo will be rendered. execution.
  • Lines 5-9 Create an SVG element and add it to the Web Component.
  • Lines 13-20 Create an object literal for the main, larger circle.
  • Line 23 Call to a helper function to create the circle that was defined on lines 13-20 and add it to the SVG.
  • Lines 25-32 Create an object literal to represent the smaller circle that will be positioned on user input.
  • Line 35 Call to a helper function to create the circle that was defined on lines 25-32 and add it to the SVG.
  • Lines 38-51 Add an event listener to the SVG to track the mouse move position over the SVG. The positon of circle c2 will be adjusted to the mouse position and when positioned, a call to a helper method to detect if the circles C1 and C2 are collides. If they are, the smaller circle is filled red, if not, the smaller circle is returned to its original colour.
  • Lines 54-73 An almost repeat of lines 38-51 [this could benefit from some refactoring] to position the smaller circle based on touch input; used to make the demonstration work on devices without a mouse, e.g. mobile phones!
  • Lines 76-81 Helper method to translate the coordinate space in the browser, to the coordinate system of the SVG. This basically means converting the cursor position to the corresponding position on the SVG.
  • Lines 84-95 This is simply a function that implements the collision detection algorithm.

Continue on reading to Conclusions...