DekGenius.com
[ Team LiB ] Previous Section Next Section

Recipe 4.5 Drawing a Circle

4.5.1 Problem

You want to draw a circle at runtime.

4.5.2 Solution

Create a custom MovieClip.drawCircle( ) method using the Drawing API and invoke it on a movie clip.

4.5.3 Discussion

You can create a circle in ActionScript with eight curves. Fewer curves results in a distorted circle and too many curves hinders performance. Let's create a custom method of the MovieClip class for drawing circles. This method, drawCircle( ), allows for three parameters:

radius

The radius of the circle

x

The x coordinate of the circle's center point. If undefined, the circle is centered at x = 0.

y

The y coordinate of the circle's center point. If undefined, the circle is centered at y = 0.

Define the custom drawCircle( ) method on MovieClip.prototype to make it available to all movie clip instances:

MovieClip.prototype.drawCircle = function (radius, x, y) {
  // The angle of each of the eight segments is 45 degrees (360 divided by 8), which
  // equals p/4 radians.
  var angleDelta = Math.PI / 4;

  // Find the distance from the circle's center to the control points for the curves.
  var ctrlDist = radius/Math.cos(angleDelta/2);

  // Initialize the angle to 0 and define local variables that are used for the 
  // control and ending points. 
  var angle = 0;
  var rx, ry, ax, ay;

  // Move to the starting point, one radius to the right of the circle's center.
  this.moveTo(x + radius, y);

  // Repeat eight times to create eight segments.
  for (var i = 0; i < 8; i++) {

    // Increment the angle by angleDelta (p/4) to create the whole circle (2p).
    angle += angleDelta;

    // The control points are derived using sine and cosine.
    rx = x + Math.cos(angle-(angleDelta/2))*(ctrlDist);
    ry = y + Math.sin(angle-(angleDelta/2))*(ctrlDist);

    // The anchor points (end points of the curve) can be found similarly to the 
    // control points.
    ax = x + Math.cos(angle)*radius;
    ay = y + Math.sin(angle)*radius;

    // Draw the segment.
    this.curveTo(rx, ry, ax, ay);
  }
}

How the drawCircle( ) method functions is better understood with a little explanation.

The distance of the control point for each segment from the circle's center is found using a trigonometric formula that states that the cosine of an angle is equal to the adjacent side over the hypotenuse. In the case of the circle, the angle that bisects a segment (thus also intersecting its control point) is p/8 (angleDelta/2). The distance to the control point from the center of the circle forms the hypotenuse of the right triangle, as you can see in Figure 4-3.

var ctrlDist = radius/Math.cos(angleDelta/2);
Figure 4-3. Calculating a point approximating a circular path
figs/ascb_0403.gif

Basic trigonometric formulas can be used to find the x and y coordinates along the circle's circumference given the angle and the hypotenuse. For the control point, the hypotenuse value is ctrlDist, and the angle is angle - angleDelta/2, since this angle bisects the segment. The anchor point is found using the value of angle, which is calculated to be the angle that intersects the anchor point, and the circle's radius (since the anchor point should always be on the circle's circumference). Thus, it follows:

rx = x + Math.cos(angle-(angleDelta/2))*(ctrlDist);
ry = y + Math.sin(angle-(angleDelta/2))*(ctrlDist);
ax = x + Math.cos(angle)*radius;
ay = y + Math.sin(angle)*radius;

Once you have defined the drawCircle( ) method and included it in your Flash document, you can quickly draw a circle with just a few lines of code. Remember that you still need to define a line style before Flash will draw anything.

// Create a movie clip instance in which you will draw the circle.
this.createEmptyMovieClip("circle_mc", 1);

// Define a 1-pixel, black, solid line style.
circle_mc.lineStyle(1, 0x000000, 100);

// Draw a circle of radius 100, centered at (50,75).
circle_mc.drawCircle(100, 50, 75);
// Draw a circle of radius 65, centered at (0,0).
circle_mc.drawCircle(65);

You can fill a circle by invoking beginFill( ) or beginGradientFill( ) before drawCircle( ) and invoking endFill( ) after drawCircle( ):

this.createEmptyMovieClip("circle_mc", 1);
circle_mc.lineStyle(1, 0x000000, 100);   // Use a 1-pixel, black, solid border.
circle_mc.beginFill(0x0000FF);           // Use a solid blue fill.
circle_mc.drawCircle(100);
circle_mc.endFill(  );
    [ Team LiB ] Previous Section Next Section