To allow a movieclip to be dragged while the mouse is pressed (only), you assign a function which executes the startDrag method to the movieclip's onPress event, and a function which executes the stopDrag method to the movieclip's onRelease and onReleaseOutside events. The reason for assigning stopDrag to both the onRelease and onReleaseOutside events is that if the mouse is moved too quickly while dragging, it will not be over the movieclip when it's released, and if no stopDrag has been assigned to onReleaseOutside, the object will continue to be dragged even when the mouse is not pressed.
If no constraints on the drag are required, a simple startDrag with no parameters may be issued. If the draggable movement of the object is to be constained within a rectangle, or along a horizontal or vertical line, parameters must be supplied to the startDrag to specify these things. Here's the general syntax to make a movieclip with an upper left registration point draggable within a rectangle:

In the code above, the first parameter (lockCenter) is set to false to keep the mouse from jumping to the middle of the object on press, then the parameters for left, top, right and bottom constraints (in pixels relative to the registration point of the timeline the movieclip is in) are specified. Here's an example, where the bluegreen square is a draggable movieclip, constrained within the rectangle shown:
This is the code in frame 1 of that movie:
square_mc.onPress = function() {
this.startDrag(false, 40, 50, 260, 150);
}
square_mc.onRelease = square_mc.onReleaseOutside = function() {
this.stopDrag();
}
square_mc.onRollOver = function() {
this.gotoAndPlay("tooltip");
}
where the parts relevant to dragging are the onPress and onRelease parts. (The
onRollOver part activates a sequence within square_mc to show a tooltip that
displays for a couple seconds and then fades). Notice that because the movieclip
being dragged has an upper left registration point, its width (20) must be subtracted
from the right (280) and bottom (170) positions of the rectangle to make sure
the square stays completely inside it (ie, with its right edge touching the
right edge of the constraining rectangle, or its bottom edge touching the bottom
edge of the rectangle).
To make a movieclip draggable along a horizontal line, just pass the same parameters for T and B to startDrag. These can be the same numeric value, or, if you want the drag to happen in the same position the movieclip is already in (the usual case), pass this._y for T and B. For a vertical drag, pass the same values for L and R (either this._x or a number value). That is:
// horizontal drag
square_mc.onPress = function() {
this.startDrag(false, 40, this._y, 260, this._y);
}
// vertical drag
square_mc.onPress = function() {
this.startDrag(false, this._x, 50, this._x, 150);
}
Ok, now we have a draggable movieclip, but how to tell when it hits something else? For that, we'll use hitTest, a method of the MovieClip class that can detect a collision either between the bounding edges of two movieclips, or between a specified point on the stage and the actual shape content of a movieclip. The syntax for both is shown here. The code at the top is for checking a collision between the bounding edges of "instancename" and the bounding edges of "otherinstance". The code at the bottom checks for a collision between the content (the actual shape of) "instancename" and a point on the stage defined by x and y (x pixels from the left edge of the stage and y pixels down).

The movie at the top of the page has an example of both. If a collision occurs between the squiggle and the smiley, frame "ow" of the smiley is displayed. Notice though, that a collision is detected when any part of the bounding box of squiggle_mc touches any part of the bounding box of smiley_mc, not when the actual shapes touch each other (and the bounding box of smiley_mc includes the area around its mouseover voice balloons too, even though they are not in the first frame). In the second example though, a more precise detection is done, between the actual content of the squiggle and a point (actually, two points) on the stage. In this case, frame "myeye" of smiley_mc is displayed and it happens only when the squiggle is directly touching either point. Check the code below to see the difference between the parameters in each case:
// start the squiggle dragging when the mouse is pressed over it
squiggle_mc.onPress = function() {
this.startDrag();
}
// stop the squiggle dragging when the mouse is released
squiggle_mc.onRelease = squiggle_mc.onReleaseOutside = function() {
this.stopDrag();
}
// do this every frame for a continuous check
smiley_mc.onEnterFrame = function() {
// check for a collision between either point (middle of each eye)
// and a shape (squiggle) ( || means "or" )
// if one occured, show "ow, my eye" frame in smiley_mc
if (squiggle_mc.hitTest(195, 78, true) || squiggle_mc.hitTest(222, 78, true)) {
this.gotoAndStop("myeye");
// if no collision between squiggle and an eye,
// check for a collision between the bounding edges of two movieclips
// if one occurred, show "ow" frame in smiley_mc
} else if (squiggle_mc.hitTest(this)) {
this.gotoAndStop("ow");
// if no collision occurred at all, send back to frame 1
} else {
this.gotoAndStop(1);
}
}
Notice that both collision checks are done within an onEnterFrame function, because they must be checked for continuously. The onEnterFrame does not necessarily have to be defined for smiley_mc -- it could be defined instead for the main timeline or squiggle_mc; I just chose it because it seemed the most logical here. You can download the source flas for both examples from the class directory (in asbasics.zip).
Instead of using numbers to show the position of the center of each eye, it would be better to let the program calculate that position, so that the same code could be used even after moving the smiley mc to a new place on stage, or moving the eyes within the face.
To do that, we need to calculate and save the position of each eye relative to the main movie. In order to calculate the position of something in a movie, it needs to be a movieclip (in order to be addressable). So we'll first convert one of the eye shapes to a movieclip with a top center registration point. Remember, the registration point is the point that is used as a point of reference for any actionscript, so it will determine what are the _x and _y values for a movieclip. If the registration point is set to top center of the eye movieclip, then smiley_mc.eye_mc._x and smiley_mc.eye_mc._y will return the values of that point, relative to the registration point of smiley_mc itself. Here's a picture:

And here are the changes to the code to calculate each position and use it to detect collisions:
var p1x:Number = smiley_mc._x + smiley_mc.eye1._x;
var p1y:Number = smiley_mc._y + smiley_mc.eye1._y;
var p2x:Number = smiley_mc._x + smiley_mc.eye2._x;
var p2y:Number = smiley_mc._y + smiley_mc.eye2._y;
// do this every frame for a continuous check
smiley_mc.onEnterFrame = function() {
// check for a collision between a point and a shape
if (squiggle_mc.hitTest(p1x, p1y, true) || squiggle_mc.hitTest(p2x, p2y, true)) {
this.gotoAndStop("myeye");
// etc
}
You can also use the localToGlobal method to calculate the collision point of each eye relative to the main stage. Check the Help files for more about localToGlobal and globalToLocal.
Another use of hitTest is to find out when the mouse has 'hit' (passes over) an object on stage. For this example, we'll use a modified version of smiley_mc which just has a background face and two eye movieclips in it. Each eye movieclip has a two-keyframe structure in which one keyframe contains the open eye (frame label="open") and the other contains a squinting eye (frame label="squint"). The movieclip also has a layer to define the active area of the movieclip so that the mouse doesn't have to be exactly over part of the squint for this to work. Here is what the innards of the eye movieclip look like:

and here is the code to make the movie shown above work:
// do this every frame for a continuous check
smiley_mc.eye1.onEnterFrame =
smiley_mc.eye2.onEnterFrame = function() {
// check for a collision between mouse and any part of an eye
if (this.hitTest(_xmouse, _ymouse, true)) {
this.gotoAndStop("squint");
} else {
this.gotoAndStop("open");
}
}
To see an example of dragging and collision detection in action (with a free fla), check the Dart Shooter example.
last update: 9 Mar 2006
Discussed on this page:
collision detection, make movieclip draggable, onEnterFrame for continuous checking, drag in a line, rectangle drag constraints, collision between point and movieclip, collision between between bounding box of 2 movieclips, collision between mouse and movieclip bounding box
Files:
dragconstrain.fla
draghit.fla
draghit_calcpoints.fla
draghit_mousehit.fla
In asbasics.zip, password required
Subscription:
A password may be obtained by subscription ($20 for one month)
An access password will be emailed to the address you specify within 24 hours of receipt of payment, and will remain active for 30 days thereafter. A list of all files currently available at the site may be viewed here.
Other Resources
For more game inspiration, take a look at Orisinal and notice how many games there involve the use of hitTest.
Grant Skinner has posted an example and downloadable fla of detecting collisions between one complex shape and another in Flash 8 which uses built-in Flash 8 processing to speed up the detection. (added 10/11/2005)