18
new object types are called classes and are implemented in external text files. the text file must be named
to match the class it implements: MyNewClass would be defined in a file named MyNewClass.as .
class files can be written in any text editor, but conveniences like syntax hilighting, auto-indenting, code insight, syntax checking, and code folding make some editors more comfortable than others.
the flash authoring environment can be used to author class files:CTRL-n > "ActionScript File" (creates a new file)TAB / SHFT-TAB (indents / outdents a line)F1 (opens help panel; if a word was hilighted in the editor, help will attempt to open to it)CTRL-f (brings up find / replace dialog)CTRL-SHFT-f (performs auto-format)CTRL-g (brings up goto line# dialog)CTRL-u (brings up preferences window, actionscript editor tab has syntax coloring settings)CTRL-t (checks syntax)CTRL-w (closes the current file)all classes in ActionScript 3 must be declared within a package, as a way of organizing and preventing naming conflicts.
the package keyword will be at the start of the file,
optionally with a package name if the class is being nested within a folder structure, and then with a matched pair of curly braces to enclose the class code.
for simple applications with few custom classes, it's often convenient to just keep the classes in the same folder as the .fla and leave the package name blank:
package { }
within the package we can define a new class with the public and class keywords,
meaning we're defining a template for making instances of a new datatype and making it available to use by any code that imports the file.
public class Shape { }we can add properties and methods by just declaring them inside the code brackets of the class as we would declare them on a timeline script in flash:
package { public class Noun { private var hello:String public function Noun(adj:String, noun:String) { hello = "Hello, I am a " +adj +" " +noun; trace(hello); } } }one special method bears the same name as the class, and is called the constructor method. this function is executed when the class is instantiated (
new Noun()), and gives us a chance to initialize
variables and do any other work required to make the class ready for use.
import, and then the keyword new to instantiate the class:
import Noun;
var p:Noun = new Noun("big", "pumpkin");
this should already feel familiar after working with the Point and Graphics classes.
what if today i want to implement a class that shows various videos, and tomorrow one that implements
a participant in a game? i might want to call each of them Player, but i can't have two files
with the same name in the same directory. even if the names didn't conflict, it would be unorganized to store
them in the same directory when they apply to different projects.
a better approach is to use packages—nested folders that create a unique path to a file, and incorporation
of that unique path into the file name. so util/video/Player.as would contain the class
util.video.Player and games/poker/Player.as would contain the class
games.poker.Player .
import statement creates a shortcut to the fully qualified path name, so we can use just the name
of the class:
import util.video.Player; var P:Player = new Player();instead of the fully qualified class name:
var P:util.video.Player = new util.video.Player();however, if we had a need to use two classes of the same name in the same file, we would have to use their fully qualified names, since the
import statement would no longer be useful.
in order for flash to be able to import and compile classes we've written, it has to be able to locate them. we must ensure the path to the root of our class package is in the list of classpaths that flash stores.
there are actually two places flash stores classpaths:
[CTRL-U or Edit / Preferences] / ActionScript tab / Actionscript 3.0
Settings button)[CTRL-SHFT-F12 or File / Publish Settings] / Flash tab / Settings button
(next to the actionScript version drop-down))
note that relative paths can be used, such as . (period) for current directory, or ../lib
for one directory up and in the lib folder.
classes can also extend other classes by inheriting everything from the class they extend, and then adding new properties and methods or overwriting existing ones. this is typically described as an is-a relationship: a car is a vehicle, or a rectangle is a shape.
the class that gets extended is called the base class or super class, while the class doing the inheriting is called a sub class.
to extend another class, we use the keywordextends in the declaration of the class, and the
keyword super to call the constructor function of the base class:
class ExtendedGraphics extends Graphics { function ExtendedGraphics() { super(); } }many built-in flash classes can be extended too, like Sprite, Array, Date, or MovieClip.
Document class field of the movie properties panel.
flash.display. this diagram illustrates their lineage.
public keyword, we can declare properties and methods fully accessible from outside
the class. these are the Application Programming Interface, or API; the dials, knobs, and buttons that
the user is given to manipulate.
public function draw() {}
private keyword, we can declare some properties and methods inaccessible
from outside the class, to prevent values important to the function of the class from being modified
by any other code. if no access modifier is specified, flash defaults to public access.
private var type:String;
another technique for protecting internal properties involves hiding them behind public functions. to allow the user
to access a private property, we can provide a getProperty method, that returns the value of
the private property. to allow users to modify a private property, we can provide a setProperty
method that accepts a new value for the property as a parameter, and updates internal state accordingly.
public. we don't
even neccessarily need an actual property; the user won't care as long as they get a value back when they call the
accessor method, and can set the value with the mutator method.
actionscript goes a step further in an attempt to simplify the use of accessors and mutators. by supporting
special get and set keywords, you can implement accessor and mutator functions that
create a virtual public property:
class SingleLetter { private var _letter:String; private static var alphabet:String; public function SingleLetter(c:String) { // initialize set of valid letters alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; // call letter mutator function to get error checking this.letter = c; } public function set letter(c:String):Void { // only accept valid letters if (alphabet.indexOf(c) > -1) { _letter = c; } else { trace("SingleLetter only accepts letter values."); } } public function get letter():String { // only return uppercase letters return _letter.toUpperCase(); } }now users of the class can access the
letter property directly, but the implementation of the class
has the opportunity to execute additional code any time the letter value is requested or asked to be changed.
var L:SingleLetter = new SingleLetter("q"); trace(L.letter);
classes can inherit from only one class (datatype) at a time. yet sometimes it's important to guarantee that a class will support certain methods, regardless of its datatype.
with the keyword interface, we can declare an abstract class that defines only method
names, not their implementation. other classes can use the keyword implements in their class
declaration to claim compliance with one or more interfaces and provide their own datatype-specific implementation.
Point class and a Shape class. both of these
are generic, separate concepts and make sense to be base classes. a Point is not a type of Shape, nor is a
Shape a type of Point. so neither will inherit from the other. yet it would be convenient to be able to
transform instances of each, so maybe we'd like to ensure that all instances of Point and Shape support the
methods translate(), rotate(), and scale(). we can do this with an interface:
interface Transformable { function translate(deltax:Number, deltaY:Number):Void; function rotate(angle:Number, center:Point):Void; function scale(deltax:Number, deltaY:Number, center:Point):Void; }and then both Shape and Point can implement the Transformable interface, guaranteeing that they will provide implementations for the transform methods specified in the interface.
class Point implements Transformable {}
class Shape implements Transformable {}
properties and methods can be implemented on one of two levels: at the class level, meaning one copy of the property or method is shared between all instances of the class, or at the instance level, meaning every new instance of the class has its own copy of the data.
by default, all properties and methods are instance level properties and methods. often, this is the desired
behavior. if i create a Point class, i want every instance to able to have different x and
y values.
static in the declaration of the property or method to keep a single copy
of it at the class level that will be shared by all instances of the class.
private static TWO_PI:Number = 2 * Math.PI; public static multiply(a:Number, b:Number) { return a * b; }