Advanced Component Creation: The Particles Component

You are now going to focus your energy on creating an advanced component that pulls out all the bells and whistles. Before you can really put your hands to work in creating the component, you must go through a few waves of brainstorming. This is especially important in advanced components, because changes in mid-development will result in a sloppily built component.

The new component we are going to construct will be much more advanced, as it will contain most everything a professional component should include. The component we will create is called the Particles component, and it will simply create a bunch of particles and move them randomly around the screen, as shown in Figure 10.7.

click to expand
Figure 10.7: Randomly scattering particles on the screen

To create a continuous stream of particles, a new particle will be placed on the screen after a certain number of frames have passed, and a particle will be removed when it travels off the stage. This component will be a lot more functional than the last, because we will provide custom methods attached to the component movie clip that will allow the user of the component to start and stop the streams of particles. You can edit those methods using ActionScript, for example on a button, which will then control the stream of the particles. I'll further develop the concept of interacting with components through ActionScript as we progress through the chapter.

As we saw previously, the brainstorming step really helped us out. We planned out the parameters we wanted the user to be able to change, and we coded a few short procedures that were used in the code for the component. Since this component is more sophisticated, it has more parameters to edit:

Frame Delay The first parameter the user can edit determines the number of frames that must pass before a new particle is added to the stage; the smaller the value, the faster the particles are added.

Particle Graphics Linkage Next, an array is used so that the user can provide their own graphics for the particles. The user will create movie clips to hold their graphics for the particles, give each movie clip a distinct linkage name, and then enter those names into the component. The component will in turn use those graphics for the particle animations by choosing a linkage name at random from the array and attaching an instance of the particle to the stage.

Particle Creation The third parameter is a list that determines the behavior of the particles when a new one is created. If you choose Convergent, then the particles will initially start in a specified area; if you choose Divergent, then the particles will start in a random place on the screen.

Convergence Radius, Convergence X, and Convergence Y These are all related, yet they are not all set in an Object data type. The reason for this will become clear in Chapter 11 when we build a custom UI for the component. These parameters define the area the particles should initially start when the Convergent setting is used. Together they define a disk with its center and radius determined by the parameters. When a new particle is created, it will start at a random point contained in that disk.

Maximum Acceleration This parameter specifies the maximum rate of change at which any particle can speed up or slow down. In a sense, it controls the overall speed of the particle system.

Stage Width, Stage Height These next two parameters are no strangers to you; they record the width and height of the stage you are using for your movie. These values are important because they are used to determine when a particle has traveled outside of the stage so that it can be removed.

Creation Handler, Deletion Handler Finally, the last two parameters are event handlers. This special type of function may be something new to you. Event handlers are simply functions that are called when a certain event occurs in the Flash movie; arguments may or may not be passed in the function call. They allow you to add extra customization and functionality to the component by using code of your own. In the context of this component, the Handler functions are called when a particle is created and removed, respectively. A movie clip reference to the particle that is being created or deleted is passed to the function.

If any of these parameters seem mysterious or confusing, do not fret; after we've created the component, we'll see a few small demos that show how to take advantage of each of the parameters.

Building the Component's Modules

Now, considering all the parameters we are adding to the component and the original idea of the component, let's develop a few tangible parts of the component that can be pieced together later on for the final production.

One of the first things you might be clueless about is how to move the particles randomly about the screen. To solve this problem, we will pull from a few elementary concepts from physics. Velocity is the rate of change at which an object moves—in our case, two separate movements: one along the x-axis and one along the y-axis. The unit of measurement we will be using for velocity is pixels per frame; so, for example, a particle can move at 5 pixels per frame, which means that 5 pixels will be added to the object's position every frame. In addition to velocity, an object can have acceleration, which is the rate of change of the object's velocity. This quantity is also split into two components, one along the x-axis and one along the y-axis. The unit of measurement for acceleration will not help in understanding acceleration because it is quite awkward at first, but in our movie it is pixels per frame squared. The "squared" part is due to the fact that acceleration is the rate of change of a rate of change. All you need to know is that if an object has an acceleration of 2 pixels per frame squared, then the object's velocity is increased by 2 every frame.

Using this information, we can formulate a way of creating a random, fluid movement. The idea is to start with an object that has 0 velocity in the x- and y-directions. Then, every frame a random acceleration will be calculated for the object, which will result in the velocity of the object changing by random values. Finally, when the velocity is added to the object's position, the result is a nice, fluid movement. This concept can be demonstrated with a simple example. Create a new Flash movie, add a movie clip to the stage with a simple graphic inside, and give the movie clip the name "thing." Then, add the actions of Listing 10.3 to the first frame on the main stage.

Listing 10.3: Giving an Object Random, Fluid Movement

start example
           // set the onEnterFrame handler of the object to handle its movement           thing.onEnterFrame = function ()           {              // calculate a random acceleration between 1 and -1              var acceleration_x = Math.random () * 2.0 - 1.0;              var acceleration_y = Math.random () * 2.0 - 1.0;              // increment the object's velocity by its acceleration              this.velocity_x += acceleration_x;              this.velocity_y += acceleration_y;              // increment the object's position by its velocity              this._x += this.velocity_x;              this._y += this.velocity_y;           } 
end example

On the CD 

With these actions in place, you can test the movie and see your movie clip wander about the screen aimlessly. An example of this effect in motion can be found in the RandomFluid- Movement.fla file in the Chapter 10 file on the CD.

With one of the more complicated tasks taken care of, we can turn to some simpler areas that need to be discussed. The Frame Delay parameter asks for the number of frames that the component should let pass by before a new particle is added to the system. Obviously, we must have a way to track the number of frames that pass after the movie starts, so we should create a frame counter variable that will be incremented every frame; we'll call this variable frame_counter. Next, to detect when a particular number of frames have passed, which will be a variable called frame_delay, we will use the modulus operator, which is the percent sign (%) in ActionScript. When the line a % b, for two integers a and b, is executed, the modulus operation returns the remainder left when dividing a by b. For our component, frame_delay number of frames will have passed when frame_delay divides evenly into frame_counter—that is, the modulus of the two values is zero. By means of this information, we can now write the code in Listing 10.4, which will trace the message "10 frames have passed" in the output window for every 10 frames that pass.

Listing 10.4: Detecting When a Certain Number of Frames Have Passed

start example
           // number of frames that must pass           frame_delay = 10;           // number of frames that have passed since the movie started           frame_counter = 0;           // onEnterFrame event for the _root that will trace the message           _root.onEnterFrame = function ()           {              // keep track of the current frame count              this.frame_counter++;              // check if enough frames have passed to trace the message              if ((this.frame_counter % this.frame_delay) == 0)              {                 // trace the message that 10 frames have passed                 trace ("10 frames have passed");              }           } 
end example

Once we have determined when to create a new particle, we then have to figure out a way to randomly place the particle on the stage. For the simple case when the divergent behavior is chosen, we can merely choose a random number between 0 and the stage's width for the particle's x-position, and a number between 0 and the stage's height for its y-position. However, for the convergent case, we must find a way to calculate a random position in a circle with arbitrary radius and center. Although only elementary trigonometry is used to do this calculation, a full explanation is beyond the scope of this book. So, here is a sample of how to calculate such a point:

         // radius of the disk         r = 50.0;         // center of the disk         cx = 100.0;         cy = 100.0;         // choose a random angle and radius to plot in the disk         var radius = Math.random () * r;         var angle = Math.random () * 2.0 * Math.PI;         // calculate the random point in the disk         var random_x = radius * Math.cos (angle);         var random_y = radius * Math.sin (angle); 

Outside of the actual structure and architecture of the component's code, the only small programming tasks that stand in our way are getting a random element of an array and how to remove a specific element from an array. The former task will be used to pick a random linkage name from the array provided by the user, while the latter will be used when a particle is removed from the stage (this will become clear when we write the actual code for the component). Both of these objectives are very simple and can be done with basic ActionScripting:

         // just an arbitrary array to operate on         var _array = new Array (0, 1, 2, 3, 4, 5);         // trace a random element from the array         trace (_array[Math.floor (Math.random () * _array.length)]);         // remove the third element from the array         _array.splice (3, 1); 

With our newly found information, we can start discussing the architecture of a typical, professional component.

The Architecture of a Professional Component

As I said, the processes and concepts in this part of the chapter are by far the most complicated in the entire book. However, they are included here because the ideas they represent form the very basis of the component movement.

The component we will be developing gets its functionality from what is called a class. A class is best thought of as a blueprint of an object from which instances can be created. Any attributes associated with the class can be represented with variables and are called properties of the class; any functions associated with the class can be attached as functions and are called methods of the class. Using this abstract definition of a class, we can formulate a simple example: a Ball class. The Ball class has properties such as color and size, and it might have methods that change the color of the ball or change its size.

To define a class, we use a regular function. The keyword this is used to set properties in the class. For example, we could declare a Ball class like this:

         Ball = function (color, width)         {            this.color = color;            this.width = width;         } 

Methods are attached to the class through the use of the prototype object. Essentially, any property or function that you want to be a part of the blueprint of the class, you set in the class's prototype. For example, a change_color method can be implemented in the Ball class like this:

         Ball.prototype.change_color = function (new_color)         {            this.new_color = color;         } 

With this very simple class defined, we can create instances of the class through the use of the new keyword:

         my_ball = new Ball ("red", 100); 

You might notice some similarities between creating an instance of the Ball class and creating an instance of ActionScript objects such as Array. In fact, they are the exact same; the Array object is merely a class that handles the functionality of an array. Of course, such functionality cannot be written in ActionScript and is probably handled through C++, but that still does not take away from the fact that the array's functionality has been encapsulated as a class.

The one drawback to the class we have just written is its lack of graphical representation. If we wanted to link the simple Ball class with a graphic, we would probably have to write a method for the class to render a circle to the screen. This is where components prevail. Components provide the very fundamental link between graphics and code, and once the two are connected, the component movie clip will act as an instance of the ActionScript class that handles the functionality of the component.

To start, create a new Flash movie named ParticlesComponent.fla and add a movie clip to the library; this will be the graphical representation of the component. Like before, we'll turn this plain movie clip into a component by adding some parameters to it. We have already planned the parameters we are going to use (at the start of the "Advanced Component Creation: The Particles Component" section); Table 10.2 and Figure 10.8 present the specifics on how the parameters are added to the component's definition.

Table 10.2: Parameters for the Particles Component

PARAMETER NAME

VARIABLE NAME

DEFAULT VALUE

DATA TYPE


Frame Delay

frame_delay

5

Number

Particle Graphics

Graphics_linkage

[particle0,

particle1,

particle2]

Array

 
 

Particle Creation

particle_creation_type

Convergent

List

Convergence Radius

convergence_radius

25

Number

Convergence X

convergence_x

275

Number

Convergence Y

convergence_y

200

Number

Maximum Acceleration

max_acceleration

2

Number

Stage Width

stage_width

550

Number

Stage Height

stage_height

400

Number

Creation Handler

creation_handler

creation_handler

String

Deletion Handler

deletion_handler

deletion_handler

String

click to expand
Figure 10.8: Component definition for the Particles component

At this point, take an extra step and open the component movie clip's Linkage Properties dialog box to give it a linkage name, as shown in Figure 10.9. The name given will be used to establish the connection of the code with the component movie clip.


Figure 10.9: Give the component a linkage name.

Now we are in a position to associate an ActionScript class with the movie clip of the component. Remember that for now we are only interested in the architecture of the component and not any specific implementation of the code we are mentioning. The code for the component will be covered in due time, but for now let's look at the best possible way to create a component.

The first part of setting up the relationship at hand is to write the ActionScript class that handles all of the functionality of the component. However, we are not yet worried about the implementation of the class since that code can be hundreds of lines. For now, we create a simple filler class with no properties or methods so that the code and component relationship can be set up:

         ParticlesClass = function ()         {         } 

Next we associate this class with the component in two steps: (1) we register the class with the movie clip of the component, and (2) we impose the structure of the movie clip on all particles.

         // register the class with the component         Object.registerClass ("ParticlesComponent", ParticlesClass);         // inherit the class from the MovieClip class         ParticlesClass.prototype = new MovieClip (); 

The call to the registerClass function takes two arguments: the first is a string for the linkage name of the component, and the second is the function of the constructor of the component's class. The registerClass function essentially strips everything from the movie clip, including its movie clip properties such as _x and _y, and then gives the movie clip all of the class's properties and methods. So, in a sense, the movie clip has become an instance of the component's class; this is what we wanted. However, a side effect of the call to registerClass is that the movie clip that represents the component has had all of its functionality removed; there are no longer the removeMovieClip, swapDepths, or any method attached to the movie clip. To offset this consequence, we must inherit the ActionScript class we wrote from the MovieClip class; this means that all the properties and methods of the MovieClip class will be added to the properties and methods of the component's class. To do this, we set the prototype object of ParticlesClass equal to an instance of the MovieClip class.

Now, let us assume that the full ParticlesClass has been written and implemented. Every time we drag an instance of the component to the stage, it is like we are creating an instance of the class. However, behind the scenes we are also redeclaring the entire class for every instance of the component on the stage. This is an obvious drain on the computer's memory. Macromedia provides two commands that you can place at the top and bottom of a block of code, and any code in between the two commands is only executed once at the very start of the movie. These commands are #initclip and #endinitclip; using them, our code becomes Listing 10.5.

Listing 10.5: Setting Up the Relationship between the Component's Code and the Component's Movie Clip

start example
           #initclip           ParticlesClass = function ()           {           }           // register the class with the component           Object.registerClass ("ParticlesComponent", ParticlesClass);           // inherit the class from the MovieClip class           ParticlesClass.prototype = new MovieClip ();           #endinitclip 
end example

Quite a bit of information has been presented to you so far, so here are a few things to keep in mind that may have slipped by with all the bits of data flying everywhere. Because the component movie clip is inherited from the component class, you can attach event handlers to the ActionScript class and those handlers will become the movie clip's handlers. For example, if we added an onEnterFrame method to ParticlesClass, then the actions in the method would be called every frame the component is on the stage. Same goes for onMouse-Down, onMouseUp, and every other handler that the MovieClip class allows. In addition to this, every method you attach to the component class can be called from the component movie clip. Assume you have an instance of the component on the stage, and you have given it the instance name "component." Also assume that the component's class has a method named some_method. Then, you can call the method of the class as if it were attached directly to the movie clip:

         component.some_method (); 

With this code in place, we are now ready to fill in the missing pieces of the class's implementation.

Assembling the Component's Code

The final step to creating this component is to implement all of the component's functionality that we planned in the brainstorming process. To understand how the actions in the ParticlesClass class can control the component, we simply draw from previously developed ideas. The two-step inheritance discussed earlier brings the class and the component into an intimate relationship; in fact, they are made into a single thing. So, when you set a property in the class via the this keyword, you are also setting a variable directly in the component movie clip. Therefore, the keyword this refers directly to the Timeline of the component; any time you want to set the position of the component movie clip, use this._x and this._y, or if you want to attach a movie clip to the component's Timeline, use this.attachMovie.

All of this insightful data greatly simplifies the programming side of the component. The first set of actions executed when a component is being initialized on the stage is the ParticlesClass constructor (see Listing 10.6). In this function, we simply need to initialize all the variables we are going to use later on: a variable to keep track of the frame count, a variable used to keep depths of attached movies separate, and an array that holds a reference to the movie clip of every particle currently on the stage. In addition to these properties, we need to align the component's stage with that of the main stage so we can determine when a particle has fallen out of sight.

Listing 10.6: Constructor for ParticlesClass

start example
           // class that will handle the functionality of the Particles component           ParticlesClass = function ()           {              // frame counter used by the component to determine              // when to create a new particle              this.frame_counter = 0;              // depth variable used to keep the depths of attached movie              // clips separate              this.depth = 0;              // array of particles that are currently on the stage              this.current_particles = new Array ();              // align the component's stage to the main stage              this._x = 0.0;              this._y = 0.0;              // assign the onEnterFrame event handler for the component              this.onEnterFrame = this.Particles_onEnterFrame;           } 
end example

The last line where the onEnterFrame handler for the class is set may be a little confusing. In general, you should never directly attach an onEnterFrame method to a component class because it offers very little flexibility; the same applies to all event handlers. Instead, you create methods that take care of what you want for the event handler, and then simply set up a pointer to the differently named method. So, in the above case, we are pointing the onEnterFrame handler to the Particles_onEnterFrame handler. If we want to change the onEnterFrame handler to another function, we simply point it to another method in the class.

Basic Methods

Next, we will discuss every method that the component will use. First up is the Particles_ onEnterFrame method, shown in Listing 10.7. In order to stay as organized and modular as possible, the Particles_onEnterFrame method only calls two other methods: one for checking when a new particle should be created and one for animating all the particles on the stage.

Listing 10.7: Possible Event Handler for the Particles Component

start example
         // method assigned as an onEnterFrame handler that handles         // the animations of particles         ParticlesClass.prototype.Particles_onEnterFrame = function ()         {            // check if a new particle should be created            this.check_for_new_particle ();            // animate all the particles on the screen            this.animate_particles ();         } 
end example

The first thing the check_for_new_particle method (Listing 10.8) does is check if enough frames have passed for a new particle to be introduced to the system. If enough frames have passed, then we call a method that is in charge of initializing a new particle. Lastly, the method increments the frame counter.

Listing 10.8: Checking Whether a New Particle Should Be Created

start example
           ParticlesClass.prototype.check_for_new_particle = function ()           {              // check if enough frames have passed to create a new particle              if ((this.frame_counter % this.frame_delay) == 0)              {                 // create a new particle                 this.create_particle ();              }              // increment the frame counter              this.frame_counter++;           } 
end example

Continuing with the flow of work, we go on to the create_particle method (Listing 10.9).

Listing 10.9: Adding Another Particle to the System

start example
           ParticlesClass.prototype.create_particle = function ()           {              // get a random particle linkage to attach              var linkage = this.graphics_linkage[                 Math.floor (Math.random () * this.graphics_linkage.length)];              // attach a new particle to the stage              var _mc = this.attachMovie                        (linkage, "particle" + this.depth, this.depth);              // check how the particle should be positioned initially              if (this.particle_creation_type == "Convergent")              {                 // calculate a random angle and radius for the particle to be                 // displaced from the center of convergence                 var angle = Math.random () * 2.0 * Math.PI;                 var radius = Math.random () * this.convergence_radius;                 // position the particle randomly in the disk                 _mc._x = this.convergence_x + radius * Math.cos (angle);                 _mc._y = this.convergence_y + radius * Math.sin (angle);              }              else              {                 // position the particle randomly on the stage                 _mc._x = Math.random () * this.stage_width;                 _mc._y = Math.random () * this.stage_height;              }              // push the movie clip reference to the array that keeps track of              // the particles on the stage              this.current_particles.push (_mc);              // call the creation handler              this._parent[this.creation_handler] (_mc);              // increment the depth variable to keep the depths separate              this.depth++;           } 
end example

The create_particle method takes care of quite a few things at once, so I'll break it down to one bite at a time. The first thing it does is get a random linkage name from the array defined by the user and attaches an instance of the movie clip to the component's stage.

Take note that the depth property of the class is used to give each attached movie a distinct name and depth. Also, a slight shorthand is being used; the attachMovie method of the MovieClip class returns a reference to the newly created movie clip. So, by assigning that reference to _mc, we have a more compact way of referencing the attached particle.

Next, we must set the particles' initial position. This depends on two things: whether the particles' behavior was set to convergent or divergent by the user. If convergent is chosen, then we calculate a random point in the disk defined by the component's parameters. Luckily, we have already figured out how to do such a thing. But, if divergent is chosen, then we are left with the remedial task of calculating a random point on the screen.

The last lines of the method carry out a few miscellaneous tasks. First, the reference to the movie clip is pushed to the end of the current_particles array. We use this array in the animate_particles method to efficiently loop through all the particles on the stage and animate them across the stage. Next, the creation handler is called. Take note that the handler provided by the user should live on the stage that is parent to the component. Hence the funny-looking syntax used to call the function. Lastly, the depth property is incremented to make sure all movie clips have distinct names and depths.

Now we move to the most complicated method in the entire class. The animate_particles method (Listing 10.10) loops through all particles on the stage and applies the random, fluid motion, which we discussed previously, to each particle.

Listing 10.10: Animating All Particles on the Stage

start example
           ParticlesClass.prototype.animate_particles = function ()           {              // loop through the particles on the stage              for (var j = 0; j < this.current_particles.length; j++)              {                 // get a reference to the movie clip of the particle                 var _mc = this.current_particles[j];              // calculate a random acceleration for the particle                 var acceleration_x = Math.random () * 2.0 *                    this.max_acceleration - this.max_acceleration;                 var acceleration_y = Math.random () * 2.0 *                    this.max_acceleration - this.max_acceleration;                 // increment the particle's velocity by its acceleration                 _mc.velocity_x += acceleration_x;                 _mc.velocity_y += acceleration_y;                 // increment the particle's position by its velocity                 _mc._x += _mc.velocity_x;                 _mc._y += _mc.velocity_y;                 // check if the particle has gone off the stage                 if ((_mc._x > this.stage_width) || (_mc._x < 0.0) ||                    (_mc._y > this.stage_height) || (_mc._y < 0.0))                 {                    // call the deletion handler                    this._parent[this.deletion_handler] (_mc);                    // remove the particle from the array that keeps track                    // of particles on the stage                    this.current_particles.splice (j, 1);                    // remove the particle from the stage                    _mc.removeMovieClip ();                 }              }       } 
end example

To start out with, we perform a for loop that iterates through each element in the current_particles array. Then, just to make our code short and readable, we create a temporary variable that holds the reference to a particular movie clip in the current_particles array.

Next, we calculate a random acceleration for the object, apply it to the object's velocity, and finally apply the object's velocity to its position. This is all very similar to the code developed in the brainstorming.

But we cannot stop here; there is an extra step. To keep the user's computer from bogging down with hundreds of particles, we have to remove any particles that fall off the sides of the screen. To detect these particles, we can write out one large conditional statement that checks the particle's position against the width and height of the stage the user defined. If we detect that a particle has fallen off the stage, we need to call the deletion handler, remove the particle's movie clip from the current_particles array, and then remove the particle movie clip from the stage. As you can see, we apply the technique used earlier to remove an element from an array.

Control Methods

With all of the code so far, we have created a fully functional component. However, the component does not have all of the features we want it to have. To create a well-designed component, you must give the user control both when they are customizing the component and when the component is already in action in the movie SWF. You provide the latter type of interaction by attaching methods to the component so the user can change some of the component's parameters on-the-fly through the use of ActionScript.

For example, what would the user do if they wanted to be able to stop and start the stream of particles? For this capability, we add on a few "setter" methods—that is, methods whose sole purpose is to give the user the ability to customize the component through ActionScript. For example, the two methods stop_stream and start_stream (Listing 10.11) enable the user to stop and start streams of particles by simple function calls. Take note that the onEnter- Frame handler is set to animate_particles when the stop_stream method is called. This is because when the stream of particles is stopped, we still want the particles that remain on the stage to animate away.

Listing 10.11: Methods to Stop and Start the Stream of Particles

start example
           // stops the stream of particles           ParticlesClass.prototype.stop_stream = function ()           {              this.onEnterFrame = this.animate_particles;           }           // starts the stream of particles           ParticlesClass.prototype.start_stream = function ()           {              this.onEnterFrame = this.Particles_onEnterFrame;           } 
end example

The next three methods (Listing 10.12) are used to change the frame delay of the particles, their convergence radius, and their convergence center.

Listing 10.12: Methods to Change Certain Parameters of the Component

start example
           // changes the frame delay of the component           ParticlesClass.prototype.change_frame_delay = function (delay)           {              this.frame_delay = delay;           }           // changes the convergence point of the particle stream           ParticlesClass.prototype.change_convergence_point = function (x, y)           {              this.convergence_x = x;              this.convergence_y = y;           }           // changes the convergence radius for the particle stream           ParticlesClass.prototype.change_convergence_radius = function (radius)           {              this.convergence_radius = radius;           } 
end example

These additional methods empower the user of the component with the facility to create a far more interesting use of the particles effect. To drive this point home, we will create a sample application using some of these additional methods. The application will have two buttons at the bottom for starting and stopping the stream of particles and another button with a text field for setting the frame delay of the component. Also, we'll write a deletion event handler for the component to play a small animation at the point where the particle falls off the edge of the screen. And finally, an onEnterFrame handler will be written for the _root to have the particles constantly stream from wherever the mouse is on the stage.

On the CD 

In the file ParticlesComponent_Sample.fla in the Chapter 10 folder on the CD, you can see such an application already created. On the main stage, you will see that all the controls give the user control of some the component's parameters, as shown in Figure 10.10.

click to expand
Figure 10.10: Open the sample file to view the controls for the component.

Drag an instance of the component to the stage and set its initial parameters. Next, click the instance of the component and open its Component Properties panel to set its instance name; we will use the name "particles." Remember that the instance name is very important; it enables us to take control of the component through ActionScript. For the graphics of the particles, I have created three movie clips, each with a small, colored dot in the middle, as shown in Figure 10.11. Give each movie clip a linkage name. For simplicity, I have used "particle0," "particle1," and "particle2."

click to expand
Figure 10.11: Create graphics for the particles used in the component.

Next, we'll write the ActionScript for the buttons on the stage. The actions to stop and start the stream of particles are simple. Open the Actions window for each button by right-clicking the instance and selecting Actions from the pop-up menu. The buttons will either call the start_stream or stop_stream method of the component, which can be done with the following code:

         on (press)         {            particles.start_stream ();         }         on (press)         {            particles.stop_stream ();         } 

The text field that holds the frame delay of the component has the instance name "delay." So, the actions for the Set Delay button are:

         on (press)         {            particles.change_frame_delay (delay.text);         } 

The onEnterFrame handler of the _root makes use of the change_convergence_point method to force the particles to stream from the user's mouse.

         _root.onEnterFrame = function ()         {            this.particles.change_convergence_point (this._xmouse, this._ymouse);         } 

Finally, we need to write the deletion handler that will play an animation at the point the particle is removed from the stage, shown in Listing 10.13. I've added a small animation with the linkage name "deletion_animation" that is simply a small square that fades out. Also, for memory purposes, I've added an action to the last frame that removes the movie clip from the stage when the animation is done playing. So, with the movie clip already made, all we need to do is attach it to the stage and position it over the particle movie clip. Take note that I've used the depth property in the same way as in the component to give attached animations distinct names and depths.

Listing 10.13: Function Called When a Particle Is Removed from the Stage

start example
           deletion_handler = function (particle_mc)           {              // increment the depth variable to keep the depths and names              // of attached movies distinct              this.depth++;              // attach a deletion animation to the screen              var _mc = this.attachMovie              ("deletion_animation", "animation" + this.depth, this.depth);              // position the animation to be on top of where the particle used to be              _mc._x = particle_mc._x;              _mc._y = particle_mc._y;           } 
end example

On the CD 

You are now done with a drastic customization to the original Particles component! Figure 10.12 shows a capture of the particles streaming from the mouse. Look in the file ParticlesComponent_Sample.fla file to see the changes we have made.

click to expand
Figure 10.12: With a small customization to the component, you can make the particles continuously stream from wherever the mouse is positioned.




The Hidden Power of Flash Components
The Hidden Power of Flash Components
ISBN: 0782142109
EAN: 2147483647
Year: 2002
Pages: 111

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net