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.
Comments