Quick Tip: Collision Detection Between Circles
basix

Quick Tip: Collision Detection Between Circles

Tutorial Details
  • Difficulty: Basix
  • Platform: Flash (Flash Player 10.1)
  • Language: AS3
  • Software used: FlashDevelop
  • Estimated Completion Time: 15 minutes
This entry is part 1 of 8 in the Collision Detection and Reaction Session
Next »

Collision detection is a branch of algorithms that checks whether two shapes overlap. If you build physics or action games with ActionScript, you will certainly not escape acquaintance with this topic. This is the first of the series regarding collision detection. In this Quick Tip, we shall look at ActionScript’s built-in collision detection method, hitTestObject(), and write our own to detect overlap between two circles.


Final Result Preview

This is the final SWF we will create in this Quick Tip. Click the blue circle and drag it towards the green one. Once they overlap, the green circle will change its color; if you remove the blue circle again, the other will return to being green.


Step 1: Bounding Box Checks

Those who are aquainted with ActionScript 2.0 will definitely recognise the method, hitTest(). This command checks for overlap between two shapes, or between a shape and a single point. In ActionScript 3.0 it is split into two separate methods: hitTestObject() and hitTestPoint().

We shall look at hitTestObject() first. This commnad generally suits collision detection for box-like shapes (squares, rectangles). A bounding box is drawn around shapes and when these bounding boxes overlap each other, hitTestObject() returns true.

Check out the example below. Drag the blue box towards the green one. As they overlap, the green box’s shade darkens.

I attach here the corresponding ActionScript that generates the above presentation. Box is a custom written class to easily generate square shapes. I’ve included the classes in the source folder; do refer to them. The important script for collision detection is highlighted below.

package 
{
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	/**
	 * Simple hitTest with boxes
	 * @author Shiu
	 */
	[SWF(width = 400, height = 300)]
	public class Simple extends Sprite
	{
		private var box1:Box, box2:Box;
		
		public function Simple() {
			box1 = new Box(0x0000FF); addChild(box1); 
			box1.x = 250; box1.y = 250;
			box1.addEventListener(MouseEvent.MOUSE_DOWN, start);
			box1.addEventListener(MouseEvent.MOUSE_UP, end);
			
			box2 = new Box(0x00FF00); addChild(box2);
			box2.x = 100; box2.y = 50;
		}
		private function start(e:MouseEvent):void {
			e.target.startDrag();
			e.target.addEventListener(MouseEvent.MOUSE_MOVE, check);
		}
		private function end(e:MouseEvent):void {
			e.target.stopDrag();
			e.target.removeEventListener(MouseEvent.MOUSE_MOVE, check);
		}
		private function check(e:MouseEvent):void {
			if (e.target.hitTestObject(box2)) box2.color = 0x00AA00;
			else				box2.color = 0x00FF00;
		}
	}
}

Step 2: Shortcomings of Bounding Boxes

However, collision between circles cannot be effectively checked using this command. Check out the presentation below. Drag the blue circle towards the green one. Before the shapes collide, their bounding boxes already overlap and hitTestObject() is true. We need a more accurate solution.

This problem is prevalent not only for collision detection between circles but non-square shapes generally. Observe the diagram below. For organic shapes that are difficult to resolve by polygons, we shall make use of pixel-precise collision detection.


Various inaccurate collision detected through hitTestObject.

Step 3: Distance Between Centers

The solution to this problem is quite simple: we shall measure the distance between the centers of these circles. If the centers get close enough to each other, we shall flag collision as true. But how close is close enough?


Distance between circles.

Observe the diagram above. r1 refers to the radius of circle1 and r2 refers to the radius of circle2. The distance between circles is calculated on every frame. If (and only if) it is equal to or less than the sum of both radii (r1+ r2), then the two circles must be touching or overlapping each other.


Step 4: Circle-Circle Collision Detection

Here are the important ActionScript for the implementation of the concept above:

minDist = circle1.radius + circle2.radius;
private function check(e:MouseEvent):void {
	var distance:Number = Math2.Pythagoras(circle1.x, circle1.y, circle2.x, circle2.y);
	if (distance <= minDist) circle2.color = 0x00FFAA;
	else circle2.color = 0x00FF00;
}

Step 5: Sample Solution

Here is a sample of the solution. Drag the blue circle towards to the green one. As they overlap, you will see green’s color change. It returns to normal when both circles are not colliding.

I have included the ActionScript implementation below.

package 
{
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	/**
	* Simple collision between 2 circles
	* @author Shiu 
	*/
	[SWF(width = 400, height = 300)]
	public class Simple3 extends Sprite
	{
		private var circle1:Circle, circle2:Circle;
		private var minDist:Number;
		
		public function Simple3() {
			circle1 = new Circle(0x0055AA, 30); addChild(circle1);
			circle1.x = 250; circle1.y = 250;
			circle1.addEventListener(MouseEvent.MOUSE_DOWN, start);
			circle1.addEventListener(MouseEvent.MOUSE_UP, end);
			
			circle2 = new Circle(0x00FF00, 30); addChild(circle2);
			circle2.x = 100; circle2.y = 50;
			
			minDist = circle1.radius + circle2.radius;
		}
	
		private function start(e:MouseEvent):void {
			e.target.startDrag();
			e.target.addEventListener(MouseEvent.MOUSE_MOVE, check);
		}
	
		private function end(e:MouseEvent):void {
			e.target.stopDrag();
			e.target.removeEventListener(MouseEvent.MOUSE_MOVE, check);
		}
	
		private function check(e:MouseEvent):void {
		var distance:Number = Math2.Pythagoras(circle1.x, circle1.y, circle2.x, circle2.y);
			if (distance <= minDist) circle2.color = 0x00FFAA;
			else circle2.color = 0x00FF00;
		}
	}

}

Conclusion

As you can see, the general principle of collision detection is to use mathematical formulae to check for overlappings between different shapes. Vector mathematics plays an important role too. Next to come is collision between a circle and a line. Thanks for reading and see you soon.

  • http://www.snorkl.tv Carl Schooff

    Thanks Kah,

    This is one of those tips that seems really obvious AFTER you learn about it. I know this will come in handy some day. Thanks for taking the extra time to create the graphics and interactive examples. They really made the concepts crystal clear.

    Carl

  • james

    Where is Math2.Pythagoras coming from?

    • james

      Guess I should have downloaded the exercise files first :). Great tutorial, and I am really looking forward to the rest of this series.

      • kah shiu
        Author

        Its a custom written class extending the functionalities of Math (Actiosncript built-in)

  • Frank Mawn

    Great tutorial ! It will sure come handy.

    In terms of performance, I would also guess its faster to use maths instead of the built in function?

    • kah shiu
      Author

      Well, I suppose it is as it’s rather simple number crunching. Havent validated it through stress test though.

    • Enrique P.

      Yes, and also more important, you should not use Math.sqrt, a common trick (not only in programming but also in maths) when you need some operation over a “distance” is to use the squared distance (hence, without sqrt). Therefore use the distance without Math.sqrt and compare it with minDist_sq = minDist*minDist;

      • kah shiu
        Author

        Enrique, I agree with you. Your statement reminds me of an article I read some time ago on bitwise optimisation at http://lab.polygonal.de/?p=81. Establishes an understanding for those who really want to blitz through number crunching.

  • AJ

    This tut is awesome!!!!! thank you for sharing this information .

  • talkonly2me

    What about if i have to collide an oval with the rectangle where rectangle is stationary and oval can be moved with keyboard i have done it with hittestobject but got border problem so wanna implement with hittestpoint please help me as circle to circle you used raidus, what about oval to rectangle ??