When you sit down to create a component, you must put quite a bit of thought and brainstorming into the process. Think of all the different aspects of the component you want the user to have control of, and of course having an inkling of an idea of how you will program the functionality of the component won't hurt.
Above all, make the component as easy to use as possible. The point of taking the time to create components is to make working with a particular element a breeze with as little extra effort as possible. Do as much as possible to keep the user from having to do anything themselves. For example, don't have your component call on the user to provide a certain graphic if you can create this graphic through the use of Flash's drawing methods. Take the extra effort to keep the user from having to providing anything. All of the additional efforts you put into the component during the development process will truly pay off when you use the component for the first time.
The motivation for components may or may not be something new to you. If you're a developer, you have probably at one time or another needed to modularize certain aspects of a project, meaning you divided large tasks into smaller tasks, quite possibly the most important concept in large-scale projects. Likewise, your component should be abstracted to be independent from outside elements—in a sense, a self-supported subprogram that operates separately from your movie.
To drive the modularity concept home, we will create a very simple component that does not necessarily take advantage of everything a component has to offer, but it does show the basic structure of a component. This component is very simple so that you can ease into the process. It merely draws a bunch of random squares on the screen, but it will contain quite a few parameters to customize how the squares are drawn; however, that is part of the brainstorming process.
Never hard-code any values. If you find yourself using a number or string that is not obvious—for example, using the number 1.67 in some mathematics calculation—then you should set a variable (or, as it applies to components, define a parameter) to hold your numerical value. This is why we use Math.PI and Math.E for the values of widely used constants instead of hard-coding 3.14 and 2.81 everywhere. This principle of general programming is also important to practice while creating components, except instead of creating a new variable for the value, you use a parameter in the component.
We are going to give the user control of seven different parameters to customize this component:
Obviously, one parameter will control the number of squares drawn on the stage.
Another parameter will let the user assign each square a random color or a predefined color. For the latter case, we will include two parameters to control the fill and border color of the squares.
There will also be a parameter to set the thickness of the borders of each rendered square.
To determine the dimensions of each square, a parameter will specify the maximum and minimum dimensions of each square, and the rendered squares will have a random width between the two values.
Finally, to spread the squares across the stage randomly, we need the dimensions of the stage, which is what the last parameter will track.
Now that we know the parameters we are going to use, we should think about how to accomplish the task of drawing the squares on the stage. There are quite a few small code snippets that will help us in this large task.
Remember, we are just brainstorming the code for now. We'll enter it into ActionScript later in the chapter.
First, how can we calculate a random number between any two numbers? This will mainly be used to calculate a random dimension for the squares between the two predefined dimensions given by the user. If the minimum and maximum numbers are a and b, we can get a random number c between them with the following code:
c = Math.random () * (b - a) + a;
Also, we need to calculate a random color to apply to the squares when the user chooses to color each rendered square differently. As you probably know, a hexadecimal number of the form RRGGBB—where RR, GG, and BB are two-digit hexadecimals—represents a color with red, green, and blue parts. For example, FF0000 is a full red, 00FF00 is a full green, and 0000FF is a full blue. Obviously, 000000 is black and FFFFFF is white. There are decimal numbers that correspond to hexadecimal numbers, but they do not correspond to colors in such an obvious way. For instance, the decimal representation of FF0000 is 16711680.
Fortunately, Flash's ActionScript can handle hexadecimal numbers so that we don't have to worry about making conversions. To specify that a number is being used as a hexadecimal, you must append the prefix 0x to the number. So, the hexadecimal number FF00FF becomes 0xFF00FF in ActionScript. With this knowledge, we can write the following code to calculate a random color in the entire spectrum:
random_color = Math.floor (Math.random () * 0xFFFFFF);
Finally, a useful piece of code to have at hand is one for drawing an arbitrarily sized square with arbitrary colors for its border and fill. Let's assume we have two variables already declared, min_dim and max_dim, which hold the range of the square's possible dimensions. To start off, we'll calculate a random dimension for the square and two random colors for the square's border and fill:
dim = Math.random () * (max_dim - min_dim) + min_dim; border_color = Math.floor (Math.random () * 0xFFFFFF); fill_color = Math.floor (Math.random () * 0xFFFFFF);
With these preliminary values calculated, we can now draw the square using Flash MX's new drawing methods. The drawing methods are functions attached to every movie clip that allow you to draw certain geometric primitives, such as lines and filled objects that are defined by a set of points. A square is made up of four vertices and has equal-length sides. We start the drawing process by setting the line style of the movie clip we are drawing in; for simplicity, we'll draw to the _root. We will also start with a 1-pixel border for the square, but later in the component, we will use the value specified by the user. The lineStyle method takes three arguments: the first for the line's thickness, the second for the color of the line, and the last for the alpha, or transparency, of the line.
_root.lineStyle (1.0, border_color, 100.0);
Next, we start the filling procedure with the beginFill method. It takes two arguments: the first for the fill's color and the second for the fill's alpha. All vertices set with the lineTo method after beginFill has been called will create a fill of the polygon defined by the lineTo points. When you are done creating the fill, you must call endFill to properly stop drawing; failing to call this method will result in total disaster for your ActionScripted drawings.
_root.beginFill (this.fill_color, 100.0);
Finally, we specify the vertices of the square, thus drawing a filled square on the stage. Note that for this small demonstration, we are going to draw the square with its top-left vertex at (0,0), its top-right vertex at (dim,0), its bottom-right vertex at (dim,dim), and its bottom-left vertex at (0,dim). When we go into the actual code for the component, all the vertices will be shifted by certain values since the squares should be positioned randomly across the screen.
_root.moveTo (0.0, 0.0); // upper-left corner _root.lineTo (dim, 0.0); // upper-right corner _root.lineTo (dim, dim); // bottom-right corner _root.lineTo (0.0, dim); // bottom-left corner _root.endFill (); // stop the fill drawing
All of this code combined draws a square on the stage. Listing 10.1 shows the code in full for your reference.
Listing 10.1: Drawing a Square on the Stage
dim = Math.random () * (max_dim - min_dim) + min_dim; border_color = Math.floor (Math.random () * 0xFFFFFF); fill_color = Math.floor (Math.random () * 0xFFFFFF); _root.lineStyle (1.0, border_color, 100.0); _root.beginFill (this.fill_color, 100.0); _root.moveTo (0.0, 0.0); // upper-left corner _root.lineTo (dim, 0.0); // upper-right corner _root.lineTo (dim, dim); // bottom-right corner _root.lineTo (0.0, dim); // bottom-left corner _root.endFill ( ); // stop the fill drawing