Linking a MovieClip Symbol to a Class

Source File: 

The idea of having some kind of built-in behavior for our MovieClip symbol was really cool. The major disadvantage was having the code buried inside the symbol, inside the fla file. We can do away with that disadvantage, and still get the built-in behavior just by linking the MovieClip symbol in the library to an external class. Let's do that now!

Timeline coders just don't have any Class

Open the fla file (if you don't already have it open), and double click the Circle symbol to edit it. On the Circle symbol's timeline, highlight the actions layer and click the little trashcan icon to delete the layer. This is just a faster way of deleting the code, since we really don't need the layer anymore either.

Next, go back to the main timeline by clicking the Scene1 button, as we are done editing the Circle symbol. In fact, let's go ahead and save this fla file under a different name. Choose File, Save As... and save the file as "code_in_custom_class.fla" as now we are going to be putting the code for the Circle symbol into its own custom class!

Creating a new class file

Next, from the File menu choose New... (or just press CTRL-N) to create a new file. Choose "Actionscript File" from the New File dialog box. You will be given a new blank document on a new tab. Immediately save this blank file and name it "Circle.as." Save it to the same folder as the fla file. Next, click on the other tab to return to the fla file.

Linking the library symbol to the class

Right click the Circle symbol in the library and choose "Properties" from the right click menu. This will open up the Symbol Properties dialog box. In this dialog box, make sure that the "Advanced" button is clicked so that you are viewing the larger version of this dialog box. In the section where it says Linkage, click the checkbox for "Export for Actionscript." Flash will automatically select the next checkbox, "Export in first frame." Go ahead and leave that checked. Flash also automatically fills in the class field with the word Circle. This is exactly the name we want, and already we see the benefit of having given our library symbol a name that's also an appropriate class name.

Notice that to the right of the Class field there is a little button that looks like a checkmark. This button is there for the purpose of checking your symbol's class linkage. Click it now and Flash will pop up this dialog box letting you know the class was found (note: in this illustration I've blanked out my file path, but yours will be different anway):

Even though our "class" file is just a blank document at this point, the fact that the file has the .as extension and is named the same as the name given in the Class field (it's case sensitive, too!) is enough for Flash to accept it and create the linkage. However, if your class had not been found, Flash would have popped up this other dialog box instead:

What is the classpath?

I want you particularly notice that this latter dialog box says that the class was not found in the classpath. The "place" where Flash looks for class files is something called the classpath. I'd like to elaborate on that now, and also give you some visuals to help you picture it.

Let's start by examining our current classpath, because obviously we do have one if Flash found our file in it. But first, I'd like to point out that there is also a default classpath where Flash looks for its built-in classes (for example flash.display.MovieClip), but we can't really take control of that, nor do we need to. Just realize that it's there, but let's ignore it for now and just consider what we will call the "user-defined" classpath that we do have contol over.

We can find out our current classpath from our fla file's publish settings. So, first make sure that the fla file is in the editing window, and from the File menu, choose "Publish Settings" and you will get the Publish Settings dialog box. In this dialog box, click the Flash tab. Then, click the button that says "Settings," the one that's next to the "Actionscript 3.0" button:

This button will open up the following dialog box:

Notice the little folder icon with a single dot next to it. In case you are a new resident in the land of universal geekdom, this little dot symbol is a shorthand notation that means "this folder" or "the same folder." In other words, our current classpath consists of only the same folder that the fla file resides in. The dot is also a relative path, which means that if you were to move this fla file to another directory, the dot reference will mean that other directory instead. This dot will always point to the fla file's home folder, which also means that Flash will always look in the same folder as the fla for Class files.

One brief aside: There is also another shorthand notation that consists of a double dot ( .. ), and it always means "my parent folder" or "one folder up from this one" (and, naturally, it's a relative reference, too). I mention this because later we will make use of this double dot notation. Anyway, the dot and the double dot are very well known conventions for writing relative URL's, in the world of web publishing and not just Flash.

Writing the Circle class file

Now let's go back to our empty class file and start writing it. It's going to be the same simple code, just structured a little bit differently:

package {
	import flash.events.MouseEvent;
	import flash.display.MovieClip;
	
	public class Circle extends MovieClip {
		public function Circle() {
			buttonMode = true;
			addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
			addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
		}
		private function mouseDownHandler(event:MouseEvent):void {
			startDrag();
		}
		private function mouseUpHandler(event:MouseEvent):void {
			stopDrag();
		}
	}
}

Let's go over it line by line. The package statement is required. You can use the package statement by itself (with nothing following the word package) if the class is going to be saved to a classpath folder. Since we saved the file to the same folder as the fla, and that folder is in the classpath, we can thus get away with using the word "package" by itself here.

The import statements are required here. In the case of timeline code, they were optional, because like I said before Flash does all that importing for you. We have to import the MovieClip class because our class is extending the MovieClip class. We have to import the MouseEvent class because our code makes use of mouse events. You will get hip pretty quick to which classes you have to import (the ones you actually use in your code!), and the compiler will let you know if you forget one. Flash CS5 adds the import statements for you, as long as your file has been saved, which, along with code hinting, are two very good reasons for saving a Class file right away, even when it's blank.

Extending the MovieClip class is like saying our class is a MovieClip, so that it can inherit everything that has already been written into the original MovieClip class. Our class is just a new, extended version of that. We get all of the properties and methods of the original MovieClip class (like x, y, alpha, rotation, gotoAndStop(), etc, etc), along with whatever new properties and methods we'd like to add. Again, consult the adobe livedocs under MovieClip to see just exactly what methods, properties, and events we get!

The Constructor: "I get called when you say new"

The function with the same name as the class (which is also the same name as the file) is called the constructor. Whenever the external, controlling code makes a new instance of this class (using the keyword new), this constructor function gets called, so it makes a fantastic place to put code that you want to have run right away. Dragging copies of a MovieClip out of the library onto the stage is a manual way of creating new instances. The effect is the same, the constructor runs once in stage instances, too. The use of a constructor function is optional, but if you use one, it must have the public keyword in front of it. It can't return any value, so don't put a return type after the parentheses. If you don't supply a constructor, Flash makes one for you. It's a good practice, though, to always supply your own, even if it's an empty one. You might need it later, and it won't hurt anything in the meantime.

The constructor can also potentially take arguments to a parameter list inside the parentheses. However, when you manually place instances from the library to the stage, there is no way to send it any arguments, and if they are required arguments, you will get error messages. But right now, we aren't worried about arguments anyway, as we aren't using any.

The private modifier on the mouse event handler functions is not required, but doesn't hurt anything either. In timeline code, these modifiers (along with the others: public, protected, and internal) are not allowed. But in a class, they give us a large degree of control over just what functions can be called from outside the class. In this case, using private means that these functions can only be called from within this class. That's all we need for these anyway. Functions, when they are used in a class, are also called methods. Variables, when used in a class, are also called properties.

The three "levels" in a class

Your classes will always be structured like this. I think of them as having three basic levels. The first, outermost level is the package block. The only thing it usually contains is import statements. I think of the package statement as just a way of telling the compiler where my class is in relation to some classpath folder. The word package by itself means that the class is directly in a classpath folder. Then, the import statements are like saying, "Oh yeah, but my class is going to be using these other classes, too, and they're not in this current package, so let's bring them into this package's space and make them available here, too." These import statements appear just under the initial package line's opening curly brace. But curiously, they can also be placed after the class block's closing brace but before the package block's closing brace, the idea being that they are legal as long as they are enclosed inside the package block's brackets, but outside of the class block's brackets. I don't necessarily recommend this, but it's interesting (and instructive) that it works.

The second level is the class block. Inside this block is where you declare all of your variables and functions. Usually your variables are listed right after the initial class statement line. However, variables and functions inside the class block can appear in any order. Probably the best practice is to have the variables list right at the top, but again, it's interesting to note that you can have them mixed in with the function definitions if you want.

The third level is not really a level at all, but for some reason I think of it as one: the constructor. I think I consider it another level because it's the only place where you can put code that runs right away.

Class code vs. timeline code

Anyway, I made a couple of diagrams to illustrate a comparison between timeline code and code in a class:

  1. The line that sets buttonMode to true happens right away.
  2. The lines that add event listeners for mouse events to the circle happen right away.
  3. The code inside the listener functions (mouseDownHandler and mouseUpHandler) waits to run until those events actually happen.

The above might seem painfully obvious, but I point it out because I want to show that these things have their counterparts when you write class files. Here is our class's code in a similar diagram:

More comparisons and contrasts

Code written into a timeline executes whenever the flash playhead reads the frame. This could potentially happen any number of times, and any code that's not inside a function will run each time. In contrast, the only code in a class that runs right away is inside the constructor function. Other than that, and the idea of access modifiers (like public and private) not being allowed in timeline code, the two are fairly similar.

There is one other difference that takes a little getting used to. You can run your fla file without saving it. So I love to use fla files with timeline code to conduct experiments. In contrast, you must always save your class files before running them, because Flash is reading them from the folder when it compiles (when you test your movie, in other words). So I had a hard time with this when I first started writing classes. Since you are saving the file each time, there is a tendency to think "This was working already, but what if I mess it up? How can I get the old version back?" However, I have long since gotten used to it, and am now just as comfortable with it either way. If you mess up your file and you've saved it, you can still press CTRL-Z repeatedly to undo everything you've done, as long as you keep your file in your editor program. Undo will take you past your last save, and it can potentially go all the way back to the state of your file when you opened it, as long as you don't close it. So it winds up being no sweat after all.

I know this page has turned into a long one. But I like to not only explain how things work, but also my own take on "why" they work that way. As for the swf file, it works exactly like it did when the code was placed in the MovieClip's timeline. You can drag out as many copies of the circle as you want from the library, and each one will (once again) exhibit the drag-and-drop behavior, and no further coding is necessary, nor are instance names. The class file is linked to the MovieClip symbol and telling it what to do. For all practical purposes, the class file is the MovieClip symbol, and vice versa. In fact, you could even (potentially) have code in the class tell the MovieClip symbol to gotoAndStop() on one of its frames, because the class is the MovieClip.

I'll have more to say about the classpath later, too. But for now, I'll close this page with another diagram of our publishing and classpath scenario so far: