How to Drag Clock Hands in a Circle

ActionScript 2.0

This one’s on request.  :)   Here’s a variation on How to Constrain Dragging to a Circle that’s different enough it merits its own entry.  Interestingly, this question crops up often enough in the forums.  Usually, someone is putting together a children’s game in which the child is expected to drag clock hands to the correct time.  As it turns out, this requires even less code than constraining dragging to a circle.  Let’s take a look. 

An answer, short and sweet

The following code assumes two movie clips:  the clock face (instance name mcFace) and a minute hand (mcMinute).  The registration point — this is important! — the registration of the minute hand should be centered on one of its ends.  By this, I mean the minute hand should spin like a real minute hand when you rotate it manually in the authoring environment.  The registration point of the clock face should be its upper left corner.

With those two movie clips in place on the Stage (and respective instance names), type the following ActionScript into a frame of your scripts layer.

mcMinute.onPress = function() {
  this.onMouseMove = function() {
    var angle:Number = Math.atan2(
      mcFace._ymouse - mcFace._height / 2,
      mcFace._xmouse - mcFace._width / 2
    );
    this._rotation = (angle * 180 / Math.PI) + 90;
  };
};
mcMinute.onRelease = function() {
  delete this.onMouseMove;
};
mcMinute.onReleaseOutside = mcMinute.onRelease;

How it works

A function literal is assigned to the MovieClip.onPress event of a movie clip with the instance name mcMinute.  When this clip is pressed, therefore, the following occurs:  immediately, another function literal is assigned to the same clip’s MovieClip.onMouseMove event.  In this second function, a local variable, angle, is declared and set to the return value of the Math.atan2() method.  Math.atan2() provides the angle in radians between two coordinates.  In this case, the coordinates are derived from two math expressions.

In the first case …

mcFace._ymouse - mcFace._height / 2

… the mouse’s vertical location is taken from the point of view of mcFace.  This represents where the mouse is in relation to mcFace, rather than, say, the Stage itself.  Then, half the height of mcFace is subtracted from this value.  Why?  Because this subtraction provides the distance halfway down the clock’s face.  In other words, we’re actually taking the location of the mouse in relation to the clock’s center.

Same goes for the mouse’s horizontal position.

Now that we have this angle in radians, we need to convert it to degrees and use the converted value to set the MovieClip._rotation property of mcMinute.  Here are the necessary formulae:

Radians to Degrees
degree = radian * 180 / pi

Degrees to Radians
radian = degree pi / 180

In Flash, 0 degrees starts at North, which is a bit different from how these classic formulae work.  With those, 0 degrees starts at East, so we add 90 degrees to the radian-to-degree conversion.

And that’s it.  The explanation is longer than the actual code.  At the very end, we use a MovieClip.onRelease event handler to cancel the dragging, and a MovieClip.onReleaseOutside handler to do the same, as it’s possible the mouse may not be directly over the minute hand when it is released.

Leave a Reply