An ActionScript 2.0 Primer for ActionScript 1.0 Folk: Part Two

by Joey Lott (www.person13.com)

As promised in Part One of this article, in this second part we’ll examine the new class syntax in ActionScript 2.0. Before we get started, if you have questions regarding general object-oriented concepts, including classes, then you may want to first check out these two articles:

http://www.oreillynet.com/pub/a/javascript/2003/08/12/actionscriptckbk.html
http://www.oreillynet.com/pub/a/javascript/2003/08/19/actionscriptckbk.html

The two articles discuss object-oriented concepts and creating classes in ActionScript 1.0, so you don’t necessarily need to memorize all the details of the ActionScript 1.0 techniques. But the articles should give you a pretty good introduction to what classes and objects are in a general sense. Once you have that background this article will likely make more sense to you.

ActionScript 2.0 Class Structure

While I could attempt to draw comparisons between ActionScript 1.0 “class” structure and ActionScript 2.0 class structure, it would likely be more confusing that clarifying. The truth is that ActionScript 2.0 class structure is fundamentally different than that of ActionScript 1.0. If you have any background in creating classes in other languages such as Java or C#, or even VB or PHP, then you’ll likely shout a loud hoorah for the new formal class structure in ActionScript. If you’re only prior experience with creating classes was with ActionScript 1.0, then don’t fret too much. You’re sure to find that although the syntax in ActionScript 2.0 is different, it is much more intuitive. After a week writing ActionScript 2.0 classes you’ll wonder how you ever managed with ActionScript 1.0.

To begin with, I’ll highlight a few of the key points of the new class structure and syntax, then we’ll look at some of them more closely.

* ActionScript 2.0 classes must be defined in .as files, and there can only be one class per file.
* ActionScript 2.0 classes are declared using the new class keyword followed by the name of the class and then the body of the class surrounded in curly braces. For example:
class Car {
// Class definition…
}

* ActionScript 2.0 classes can be in packages. ActionScript 2.0 supports the import keyword in order to import entire packages or select classes within packages.
* ActionScript 2.0 class members can be declared as public, private, and static.
* ActionScript 2.0 classes can extend other classes using the extends keyword in the class declaration.
* ActionScript 2.0 classes can implement interfaces.

Whew! If any of that sound scary or new to you, keep on reading. I’m going to explain each of these parts in more detail and with examples you can try on your own (assuming you have a copy of Flash MX 2004 or Flash MX Professional 2004.)

Defining ActionScript Class Files

If you’re not familiar with other languages such as Java or C# then storing classes in their own files may be a new concept. Particularly so if you’ve worked with ActionScript 1.0 in which you could define multiple classes not only within a single .as file, but even within an .fla file.
There are plenty of reasons why it’s advantageous to store all your classes, one per file, in external .as files. The core benefit is, of course, better organization. It’s just simply much easier to store, locate, maintain, and distribute your classes when they’re organized well. If you’re defining classes in all kinds of places, then it becomes a mess rather quickly. Of course, if you were only working with two or three classes, this would not necessarily pose a big problem. But ActionScript 2.0 ushers in a new paradigm for ActionScript. Developers can create and share libraries of classes that provide pre-built functionality. Rather than reinventing the wheel each time people can begin to build upon their own previous work and the work that others have contributed. You can see how Macromedia has already jumpstarted this with their set of standard classes that you can find in the First Run/Classes directory (and subdirectories) of your Flash MX 2004 installation.
So unlike ActionScript 1.0 classes, all ActionScript 2.0 classes absolutely must be saved in external .as files. Further more, these files must be saved such that the file name matches the name of the class. For example, if the class is named Car, then the file must be named Car.as.

Working with Packages

Class files may be stored in packages. If you’re not familiar with packages (also called namespaces in the .NET world) they are simply a way of organizing your classes. There are two aspects to a package. First, the class definition must specify the package in its declaration. We’ll look more closely at that part in the next section. Secondly, the .as file must be saved in a corresponding directory or directories. For example, if the package for a class is com.person13 then the .as file for that class must be saved in a directory structure of com/person13.

There are two primary benefits to working with packages. The most obvious one is that it provides you with a way to organize your class files so that you can locate them quickly. For example, if you look in the set of classes that ship with Flash MX 2004 (in the First Run/Classes directory) you’ll see that many of the classes for the UI components are organized within the mx.controls package, and are therefore saved in the mx/controls directory. The second benefit of packages is that it helps to avoid possible name conflicts. You cannot have two classes with the same name in the same package for the obvious reason that Flash wouldn’t have a way of knowing which one you want to use. So if you didn’t use any packages and saved all your classes in the same directory you would potentially run into this problem. Of course, if you are writing all the classes then you have the ability to easily make sure you give each class a unique name. But when you download and install others’ classes, you don’t have that same control. So when classes are stored in packages it helps to make sure that these types of naming issues don’t occur. For example, the class Car in the com.person13 package and the class Car in the com.ejepo package don’t create any naming conflicts with Flash.

Defining Your Classpath

By default Flash looks first to the First Run/Classes directory within your Flash installation when trying to find class files. If it does not find a specified class in that directory then it next looks to the same directory in which the Flash or ActionScript document is saved.
The classpath is the list of directories to which Flash looks for class files. You can also specify additional directories for the classpath. And, if you want, you can change the order in which Flash looks to these directories. In order to edit the classpath choose Edit>Preferences, and then select the ActionScript tab. Click on the ActionScript 2.0 Settings to bring up the ActionScript Preferences dialog box. Use the + button to add new directories, the – button to remove directories, and the arrow buttons to reorder them.


Figure 1: defining the classpath

As you can see in Figure 1, I’ve added the directory D:\ActionScriptClasses to my classpath. This means that the third place that Flash will look for class files is now D:\ActionScriptClasses. (Incidentally, $(LocalData) resolves to the First Run directory of your Flash installation.) Adding a custom directory to the classpath can be a good idea for a few reasons:
* It can be easier to browse to a directory such as D:\ActionScriptClasses than to the directory in which Flash stores all classes that ship with Flash.
* It is easier to manage your files if you save all your custom classes in a directory other than the directory into which Flash stores classes that ship with Flash.

Understanding Private and Public Members

A class is composed of members – properties and methods. Unless you used some convoluted or undocumented features of ActionScript 1.0, all ActionScript 1.0 members were public. When we say that a member is public, it means that it can be accessed from outside of the class definition. For example, if you create a Car class with a property named make, and that property can be accessed from an instance of the Car class, then the property is public. But there are plenty of times in which you don’t want the properties and methods of a class to be publicly accessible. A class may have properties and variables that are used only internally, and that don’t need to be exposed publicly. In such cases you can declare a member to be private.

Note: If you’ve used other languages such as Java or C# then you should note that a private member in ActionScript 2.0 behaves like a protected member in Java or C#.

In order to declare a member as public or private you can use the public and private keywords, respectively. For example, the following declares a private property:

private var _nInterval:Number;


By convention you can use the underscore character as the first character in a private property’s name to help differentiate between local variables, parameters, and private properties within the class.

We’ll take a look at declaring public and private members in context within an upcoming section. An example of private and public members should help to clarify this topic, and in an upcoming section you’ll create a custom class that uses both public and private members.

Note: If you don’t specify either public or private then the default is public.

Understanding Static Members

Static members are members that are accessed directly from the class, and not from instances. This is not a new concept to ActionScript 2.0. In fact, since Flash 5 you have seen built-in classes with static members. For example, the Math class is comprised entirely of static members. Rather than creating an instance of the Math class and then accessing the properties and methods from a instance, you always access the properties and methods directly from the class itself. For example:

trace(Math.cos(3.14));

Notice that the cos() method is accessed directly from the Math class, thus it is a static method.
In order to create a static member in an ActionScript 2.0 class you use the static keyword in the declaration. And static members can be further modified to be either public or private, just like non-static members. Here’s an example of a public static member declaration.

public static var classname = “Car”;

Declaring a Class

If we look at a class structure in very simplistic terms, there are four basic parts:
* The class declaration consisting of the keyword class and the name of the class.
* Property declarations.
* Constructor declaration.
* Method declarations.

Let’s examine each of these parts a little more closely:

Class declaration

To declare a class you use the keyword class followed by the name of the class. Then you enclose the class definition in curly braces. For example:

class Car {
// Class definition.
}


If you want to place the class in a package then you need to indicate the package as part of the class name in the declaration. We call the name of a class that includes the package the fully-qualified class name. For example, if you wanted to place the Car class in the package com.person13, then the class declaration would look like this:

class com.person13.Car {
// Class definition.
}


And, of course, when you place a class in a package, you must be sure to save the class file to the corresponding directory. In the case of the com.person13.Car class the file Car.as should be saved in a directory structure of com/person13 where the com directory is located within the Flash classpath. (For example, if your classpath includes D:\ActionScriptClasses, then you could save the file as D:\ActionScriptClasses\com\person13\Car.as.)


Property Declarations

You must declare all properties within the curly braces of a class definition. You must also declare all properties outside of any methods. By convention you should declare all the properties at the top of the class definition. For example:

class com.person13.Car {

private var _sMake:String;
private var _sModel:String;
private var _nYear:Number;
private var _nMiles:Number;
private var _nInterval:Number;

// Rest of class definition.

}


Constructor Declaration

After you’ve declared the properties within the class, you should next declare the constructor. Technically, if you don’t declare a constructor explicitly, Flash will create an implicit empty constructor for you. But even if your constructor does not do anything, it is still good form to declare the constructor explicitly.
Remember, the constructor is a special method that shares the same name as the class. The constructor can be used within a new statement to create new instances of the class. The constructor should be declared just like a regular function, and even though it can accept parameters, it should not return any values. Here’s an example of the Car class with a constructor:

class com.person13.Car {

private var _sMake:String;
private var _sModel:String;
private var _nYear:Number;
private var _nMiles:Number;
private var _nInterval:Number;

function Car(sMake:String, sModel:String, nYear:Number, nMiles:Number) {

_sMake = sMake;
_sModel = sModel;
_nYear = nYear;
_nMiles = nMiles;

}

// Rest of class definition.

}

Unlike some other languages, you cannot have overloaded constructors in ActionScript 2.0.

Declaring Methods

Next you can declare the methods of your class. You declare methods just like standard functions, using the function keyword and the same exact syntax. Remember, a method is a function, but it is associated with a class. Because you declare the function within the class, Flash automatically knows to associate it with the class. The only differences between standard functions and methods are that you can declare methods to be public, private, and static if appropriate. Here’s an example of the same Car class with two methods – one public and one private.

class com.person13.Car {

private var _sMake:String;
private var _sModel:String;
private var _nYear:Number;
private var _nMiles:Number;
private var _nInterval:Number;

function Car(sMake:String, sModel:String, nYear:Number, nMiles:Number) {

_sMake = sMake;
_sModel = sModel;
_nYear = nYear;
_nMiles = nMiles;

}

public function drive(nMPH:Number):Void {

if(nMPH == null || nMPH == 0) {

clearInterval(_nInterval);

}
else {

_nInterval = setInterval(this, “increment”, 1000, nMPH);

}

}

private function increment(nMPH:Number):Void {

_nMiles += nMPH;

}

}

Working with Getter/Setter Methods

Getter and setter methods are special methods that are accessible outside the class as properties, but are defined within the class as methods. Among the potential advantages of getter and setter methods is that these methods allow you to create members that work like properties external to the class, but that can have sophisticated logic built into them. In the case of our Car class example, we might want to make sure that the value for the year of the car is never set earlier than 1886 (the year the first automobile was invented) and that the number of miles is never set less than 0. Additional benefits of getter and setter methods are:
* They allow us to work with property names such as _nMiles within the class, but to expose the values publicly with more user-friendly property names such as miles.
* They allow us to create read-only and write-only properties.
* They allow us to create virtual properties – properties that don’t correspond to any one property within the class, but that are generated based on a mixture of internal values.

A getter method should never accept any parameters and should always return a value. The syntax for a getter method is as follows:

function get externalPropertyName():ReturnType {

// Method definition, including return statement.

}

The method can, like other methods, be modified with the public and static keywords as well, but you may not declare a getter method as private.

Here’s an example of a simple getter method that returns the value of _nMiles as the property miles.

public function get miles():Number {

return _nMiles;

}

Setter method syntax is very similar to the syntax for a getter method except that it should always accept a parameter, never return a value, and use the set keyword instead of get. Here’s the basic syntax:

function set externalPropertyName(parameterName:DataType):Void {

// Method defintion.

}

And just like getter methods, you can modify setter methods with the public and static keywords, but not with private. Here’s an example of a setter method that assigns a new value to the private property _nMiles. Notice that it checks to make sure the value is 0 or greater. If not, it uses the default value of 0.

public function set miles(nMiles:Number):Void {

if(nMiles >= 0) {

_nMiles = nMiles;

}

else {

_nMiles = 0;

}

}

Importing Classes

When you place classes in packages, you need to always use the fully-qualified class name when you reference the class. That means that if you have created com.person13.Car, then in order to create an instance of the class your constructor statement might look something like this:

var car:com.person13.Car = new com.person13.Car(“Oldsmobile”, “Alero”, 2000, 43000);

There is, however, a shortcut. You can use the import statement to tell Flash what packages and classes you want it to know about without having to specify the package. Then, Flash will automatically assume the package name without you having to specify it each time. Here is an example that imports the Car class and then constructs an instance.

import com.person13.Car;
var car:Car = new Car(“Oldsmobile”, “Alero”, 2000, 43000);


You’ll notice that it is much more readable. Also, when you have many references to the class name, it can save you a lot of time typing.

You can also import all the classes in a package using the * wildcard. For example, the following will import any class in the com.person13 package.

import com.person13.*;

Creating a Class

You’ve had a chance to now see some of the preliminary stuff with regard to ActionScript 2.0 classes, but I can tell you’re ready to jump in and create a class of your own. We’ll start out by creating a class named Car. Just follow the steps that follow:
1. Open a new ActionScript file. If you use Flash MX Professional 2004 then you can use the ActionScript file editor that is in the IDE. Otherwise, you can use your favorite text editor so long as it can save a plain text file.
2. The first code you should add to the file is the class declaration. In order to do this you use the class keyword followed by the class name and then curly braces to surround the class definition. So start by adding the following code to your file:

class com.person13.Car {

}

3. Next declare the five properties. You’ll make each of these properties private. The first four should be fairly self-evident. The last property you’ll use to store the interval ID for an interval method you’ll set in one of the methods.

class com.person13.Car {

private var _sMake:String;
private var _sModel:String;
private var _nYear:Number;
private var _nMiles:Number;
private var _nInterval:Number;

}

4. Then declare the constructor. In this case, let’s have it accept four parameters and assign those values to the corresponding properties. You’ll notice that in two cases we’re referencing properties that we didn’t declare. That’s because those two properties will be defined with setter methods shortly. We want to set the setter methods in those cases because we want to employ some logic that makes sure the values are valid.

class com.person13.Car {

private var _sMake:String;
private var _sModel:String;
private var _nYear:Number;
private var _nMiles:Number;
private var _nInterval:Number;

function Car(sMake:String, sModel:String, nYear:Number, nMiles:Number) {

_sMake = sMake;
_sModel = sModel;
year = nYear;
miles = nMiles;

}

}


5. Next, declare some methods for the class. In this case we’ll create a single public method named drive(). Then, we’ll also create a private method named increment() that will get called on an interval once the drive()method has been called with a valid miles per hour parameter.

class com.person13.Car {

private var _sMake:String;
private var _sModel:String;
private var _nYear:Number;
private var _nMiles:Number;
private var _nInterval:Number;

function Car(sMake:String, sModel:String, nYear:Number, nMiles:Number) {

_sMake = sMake;
_sModel = sModel;
year = nYear;
miles = nMiles;

}

public function drive(nMPH:Number):Void {

if(nMPH == null || nMPH <= 0) {

// If nMPH is null or less than or equal to 0 then
//
we want to tell the car to stop
// driving…We can do that by clearing the interval.

clearInterval(_nInterval);

}
else {

// Otherwise, if nMPH is a number in the valid
// range, then set an interval so
// that the private method increment() is called
// once a second or so.
_nInterval = setInterval(this, “increment”, 1000, nMPH);

}

}

private function increment(nMPH:Number):Void {

// Each time the method is called, update the _nMiles value
// by incrementing it by nMPH. Of course, since the method
// is called once a second, the actual mileage increment is
// about 360 times what it would be. But, hey, we’ve
// got to speed things up a bit so that we can see some
// progress within a short amount of time. ;)
_nMiles += nMPH;

}

}

6. The remaining step is to define the getter and setter methods as shown in the following code:

class com.person13.Car {

private var _sMake:String;
private var _sModel:String;
private var _nYear:Number;
private var _nMiles:Number;
private var _nInterval:Number;

function Car(sMake:String, sModel:String, nYear:Number, nMiles:Number) {

_sMake = sMake;
_sModel = sModel;
year = nYear;
miles = nMiles;

}

public function get make():String {

return _sMake;

}

public function get model():String {

return _sModel;

}

public function get year():Number {

return _nYear;

}

public function set year(nYear:Number):Void {

if(nYear >= 1886) {

_nYear = nYear;

}
else {

_nYear = 1886;

}

}

public function get miles():Number {

return _nMiles;

}

public function set miles(nMiles:Number):Void {

if(nMiles >= 0) {

_nMiles = nMiles;

}
else {

_nMiles = 0;

}

}

public function drive(nMPH:Number):Void {

if(nMPH == null || nMPH <= 0) {

clearInterval(_nInterval);

}
else {

_nInterval = setInterval(this, “increment”, 1000, nMPH);

}

}

private function increment(nMPH:Number):Void {

_nMiles += nMPH;

}

}

7. If you haven’t yet done so, create a com/person13 directory within your Flash classpath. For example, if your classpath includes D:\ActionScriptClasses, then make sure you have created D:\ActionScriptClasses\com\person13.

8. Save the ActionScript class file as Car.as to the com/person13 directory.

9. Open a new Flash document (.fla).

10. On the first frame of the main timeline add the following ActionScript code:

import com.person13.Car;

/ / First, a function that will display the miles property value
// for a Car object.
function displayMileage(carObj:Car):Void {

trace(carObj.miles);

}

// Create the Car object.
var car:Car = new Car(“Oldsmobile”, “Alero”, 2000, 43000);

// Tell the car to start driving at 65 miles per hour (for those of you
// outside of the U.S., you’ll have to work out the conversions to
// kilometers yourself! ;)
car.drive(65);

// Set an interval so that the mileage of the Car object will
// continually display.
setInterval(displayMileage, 100, car);

11. Test the movie.

You should see the mileage of the car displaying in the Output panel. It should increment by 65 once a second or so.

Conclusion

In this article I touched on the basics of ActionScript 2.0 classes. I didn’t yet go into the details of extending classes or implementing interfaces. We’ll save those topics for a third installment on account of this article is already long enough. Thanks for reading.

 


评论

该日志第一篇评论

发表评论

评论也有版权!