AS Reference  :  Notes Index  :  Resources  :  About/Contact  :  Downloads

Detecting Collisions Between Any Point of Two Movieclips


Finding out when a moving object has hit another object is a crucial part of any action-based game. Since I don't play (or write) a whole lot of action-based games, I haven't spent much time worrying about collision detection. But the other day I was working on a way to make dynamic text move along a dynamically-defined curve (which I'll post a sample of when I get it cleaned up), and I remembered that Gary Fixler had posted something about using a line of "sentries" along the border of a movieclip to provide precise collision detection, which is related in a way. I went looking at his site and found the sample you see above. I love it! I like the way the things bounce and flip around, and the way if you throw one upwards hard, it disappears and then eventually comes thudding back down and bounces around some more, and it's just icing on the cake (ok, I guess it's actually the whole point of the thing) that the alpha of both clips change as soon as any part of one hits the other. Gary has a good way of thinking about how a thing works physically (like how off-center is an object when it hits an edge = how much the thing should rotate when it bounces) and making equations that produce the same effect in Flash, without being overly mathematically complicated. He graciously agreed to send over the fla and allow me to post it here, so I've had a good time digging around in it, commenting, rearranging and trying to make sense of it.

Collision detection basics

Anyone who's tried to find out when two objects collide in Flash knows that there are two things you can detect: when the bounding box of one movieclip touches the bounding box of another, or when the contents of a movieclip (not its bounding box) touches a defined point on the stage, or on another clip that's on the stage. The former is done with this kind of code, for two movieclips onstage, mcShape1 and mcShape2:

Find when one movieclip's bounding box hits another's

mcShape1.onPress = mcShape2.onPress = function() {
    this.startDrag();
}
mcShape1.onRelease = mcShape2.onRelease = function() {
    this.stopDrag();
}

function basicHitTest() {
    if (mcShape1.hitTest(mcShape2)) {
        trace("hit " + i++);
    }
}
this.onEnterFrame = basicHitTest;

That works nicely if mcShape1 and mcShape2 are both of a fairly rectangular shape (and thus fill their respective bounding boxes). If they are not so rectangularly shaped, and you want to check when any part of the content of one (say, mcShape1) touches a particular point on the other (say, a dot placed 5 pixels to the right and 7 down from the registration point on mcShape2), you can do so like this:

Find when one movieclip's content hits a point on stage

mcShape1.onPress = mcShape2.onPress = function() {
    this.startDrag();
}
mcShape1.onRelease = mcShape2.onRelease = function() {
    this.stopDrag();
}

function shapeHitTest() {
    if (mcShape1.hitTest(mcShape2._x+5, mcShape2._y+7, true)) {
        trace("shape hit " + i++);
    }
}
this.onEnterFrame = shapeHitTest;

But if you want to know when any part of the content (not bounding box) of mcShape1 hits any part of the content (not bounding box) of mcShape2, you'll need to do something like Gary did in his sample: use multiple blank clips to define the border.

Precise detection

If you look at movieclip symbols blue and green in the library of the above fla, you'll see that each contains a movieclip named perim. Perim contains a series of blank movieclips, arranged shoulder to shoulder (the more clips, the more precision, but also the more processing power required to detect a collision, of course) around the border of the clip's shape. Then, instead of checking if clip a has collided with clip b, we check whether clip a has collided with any of the sentries (treated as single points) in clip b:

Find when one movieclip's content hits another clip anywhere along its shape border

// for each sentry in this clip ("clip b")
for (i in this.perim) {
    // get the sentry's point on the stage
    this.perim.localToGlobal(p={x:this.perim[i]._x,y:this.perim[i]._y});
    // see if it's touching o ("clip a")
    if(o.hitTest(p.x, p.y, true)){
        o._alpha=50;
    }
}

The localToGlobal method allows us to find the location of the sentry relative to the stage (rather than to perim, which it is inside of). That statement says: take the current x and y values of the sentry (eg, this.perim[i]._x) and make an object p out of those values. Assign p.x the sentry's x value within perim, and assign p.y its y value. Then use localToGlobal to convert that to a new p object, whose x value is the point on the stage where the sentry is, and whose y value is the sentry's y value on the stage.

Imitating physical laws of motion

If you've looked at the fla, you'll see that other things are happening inside the collision detection movieclip method (col) besides detecting a collision and setting the alpha to 50. Within the loop, the location of each sentry on the stage (p.x, p.y) is calculated for collision detection purposes, and also used

Physical effects such as acceleration and deceleration are applied by simply adding an increasing or decreasing x or y amount to the object over time (each frame). Eg, acceleration (gravity) is applied by adding a constant y amount (constant gcGravity) to the object on each frame when it's moving downward. Similarly, deceleration is achieved by adding a decreasing amount (multiplying the amount to be added by a factor less than 1, or dividing it by a factor > 1) on each frame to slow the object down (eg, friction, damping). For a better look at how each effect was achieved, we suggest starting with the fla (all code is in frame 1 of the main timeline, and has inline comments to explain what is being done in each segment) and then changing numbers and/or commenting out lines to see what effect is produced. The fla may be downloaded here.

Intro
Flash: What & How
Example Sites
Create
Draw, Edit Shapes
Gradients
More Drawing Tips
Import
A Sample
Animate
Frames, Keyframes
Motion Tweens
More Motion Tweens
Shape Tweens
Masks
Control
Stop/Replay
Movieclips Intro
Movieclip Reference
Site Structure 1
Slideshow Movieclip
Contact Form
Scroll Resume
Preloader
Site Structure 2
Publish
Display Options
Player Detection
Optimize
AS 2.0 Basics
Intro to Syntax
Playhead Commands
Playhead Cmds 2
Coded Tween
onEnterFrame
Intro to Classes
Declare/Assign
Comments, Trace
Simple Data Types
Arrays & Objects
Code Blocks
Operators
Beyond Buttons
Code Structure
Toggle Controls
Group of Buttons
Drag and Hit
Distort Magnifier
Scroll Text
Bee Game
Dart Shooter
Sound Control
Easing Slider
Easing Slider 2
Components Intro
Timers & Delays
Dynamic Content
Intro
Drawing API
Create Text
Attach Movieclips
Easing Slider 3
Easing Slider 4
Load jpg/swf
Sliding Viewer
Preload swf
XML
Easing Slider 5
Server Comm
LoadVars (w/ PHP)
AS - PHP Lookup
Text File
Database 1:LoadVars
Database 2:Remoting
Read from directory
AS 2.0 Classes
Intro
Math
Key
Date
Color
EventDispatcher
New Samples
Pie Chart
Event-model Emailer
Tween Sequence
Fuse Sequence
SVG in Flash
Bitmap Topo
SWF as Data Holder
Two-level Menu
Yahoo! Flash Maps
Class-based Game
ASTB Samples
Disclaimer
3D Outlines
Bounce Collide
Address Book
Save Drawings
Home  :  Notes Index  :  Resources  :  About/Contact  :  Downloads