- Everything is an Object
- Method and Properties
- Built in Classes: Looking at the MovieClip Class
- Creating and Manipulating Objects
- Creating Objects using the New Operator
- Accessing Properties and Calling Methods
- Copying Objects
- Casting Objects to a Type
- The Object object
- Inheritance
- Using External .as Files
- Creating a Custom Class
- Adding Properties to Your Class
- Adding Methods to Your Class
- The Constructor Method
- Controlling Access to Properties and Methods
- Getter / Setter Methods
- Read-only Methods
- Static Properties and Methods
- Using Inheritance
- Packages
- Defining Packages
- Importing Packages
- The Display List
- Using and Manipulating Display Objects
- Display Object Depth
- Creating and Removing Display Objects From the Stage
Week 3 Examples – CS3!
ActionScript and OOP: Everything is an Object
Absolutely everything that you use in ActionScript is an Object, and each of those Objects is defined by a Class. Classes are stored in external .as files. When you installed the Flash IDE on your computer, you also installed the entire library of built-in classes that are the foundation of the ActionScript language. Objects represent a specific instance of a Class. Another way to look at it is that a Class is a blueprint for an Object.
Classes in ActionScript are composed of three elements: Methods, Properties, and Events.
- Properties are what Objects are
- Methods are what Objects do
- Events track when something happens that ActionScript can respond to
We’re not going to get into Events just yet.
Methods and properties have a relationship to programming concepts that we have already explored. You can think of Properties as Variables that belong exclusively to a class, and Methods as Functions that do the same.
Let’s look at the MovieClip class in the Help system to see how it is organized.
You’ll notice that the first thing that is listed about the MovieClip class is its Package.
Packages
A package is a way of organizing classes. A package is a collection of associated .as files, each of which contains a class. For example, the package that contains the MovieClip class is the flash.display package. This package contains all the core classes which describe objects that are displayed visually on the stage (including the stage itself!).
Inheritance
One of the most powerful aspects of OOP is the concept of inheritance. Classes can inherit properties and methods from other classes. This sets up parent/child relationships in a hierarchy of classes that allow a class to share, or inherit, properties and method from the parent classes, in much the same way that you inherit biological traits from your parents. A better analogy is actually your relation as a organism to the human race. You share with all humans the trait (or properties) of having two arms, two legs, hair on your head, etc. You can do the things that humans do (methods!) like walk upright on two legs, and talk in human verbal language. Beyond that, you are a member of the larger class of mammals, and share traits and behaviors with that class, like being warm-blooded, and breathing oxygen. In fact, the whole taxonomy of biological classification that you learned in high school (you know, Kingdom, Phylum, Class, Order ….) could be looked at as a series of Objects or Classes in a OOP system.
The MovieClip class inherits properties and methods from the Sprite, DisplayObjectContainer, InteractiveObject, DisplayObject, EventDispatcher, and Object Classes.
Subclasses
The MovieClip is a subclass of all the classes it inherits from, and it has a subclass of its own, LivePreviewParent. Subclasses inherit the properties and methods of their parents, but also have characteristic that are unique to themselves. A well-defined OOP system has very generic classes at the top of the hierarchy, and gets more specific as you go down the hierarchy.
Properties
The next thing about the MovieClip class that we see, after the description of it, are its Properties. These are the Properties that are specific to the MovieClip class, currentFrame, currentLabels, currentScene, etc. You’ll perhaps notice that these properties are related to the timeline. This is because MovieClip is a display object with a timeline, and this is the primary difference between it and its parent, the Sprite!
Methods
Next are the methods, and you will notice that they are also pretty much timeline-related: goToAndPlay, goToAndStop, nextFrame, etc.
Creating and Manipulating Objects
We already explored how to create a new Array last week using the new operator. This works for any type of ActionScript Object. For instance we can make a new String object and populate it like this:
var greeting:String = new String("Hi there!");
This technique of creating a new object can be used with built-in classes as well as those classes you will write yourself.
Accessing Properties and Calling Methods
Again, we touched on this last week when we worked with arrays, but it extends to all objects. We access properties and call methods using the dot (.) operator. Before the dot you specify the name of the variable in which the object is stored, and after the dot the name of the property or method you wish to access.
For a string, you can access the length property like this:
greeting.length
Or call the String method charAt() like this:
greeting.charAt(4);
A string is actually an array of characters, and the charAt method allows you to access a character at a specifc place in the array.
Copying Objects
In the reading, you learned that primitive objects (Numbers, Booleans, Strings) are “passed by value” where complex objects like arrays are “passed by reference”. Passing by reference means that instead of actually setting a variables value to the value of another variable as it stands at that moment, you are instead just pointing it to the place in memory where that value is stored. This means that if that value changes for one object that is pointing to that reference, it will change for all objects that are pointing to that reference. This is one of the more difficult concepts in programming to grasp, but for the moment, just understand that this means that you can’t make a pure copy of an complex Object the same way you can a simple datatype.
In the case of an Array object, we can make a copy of the array using Array’s built in slice() method.
var array1:Array = new Array("one","two","three");
var array2:Array = array1.slice();
Now array2 will be unaffected by any changes you make to array1 later in the code.
The Object object
Almost all objects in ActionScript are the children of, and inherit properties and methods of, the Object object. An Object is the simplest type of object you can make.
You can create a new Object, like all objects, with the new operator:
var myObject:Object = new Object();
These generic objects are “dynamic” objects, which means that you can assign properties to them on the fly without generating errors:
myObject.name = "Simple Object";
myObject.ID = 12345;
Like an Array, you can create a new Object instance by using an object literal, and define properties within it:
var myObject:Object = {name:"SimpleObject", ID:12345 };
Using the Object object allows you to create very generic, dynamic objects on the fly, but I would caution against overusing this ability in your code. It is better to use the built-in classes and to create your own custom classes.
And how about that? How do we make classes of our own?
Using External .as Files
Placing ActionScript on the timeline of your .fla files works, but it is not the most efficient way to write your code. It means that you or other developers must hunt through the timeline to find and edit code, and that it must be compiled everytime a change is made. Also, the code can only be utilized by that one file, not shared across multiple projects.
The preferred way of storing ActionScript is with external .as files. These are ordinary text files that can either be created with the Flash IDE or with any text editor.
To create a new .as file from the Flash IDE, choose File > New > ActionScript File.
You can type code into this file just as you do into the Actions panel in the Timeline of a .fla file.
Including Code from External Files
There are a number of ways to include code from external files. One way is by using an include statement, like so:
include "Import.as";
This will cause the code in the .as file to be compiled with the contents of the .fla file just as if it was in the timeline. While effective, this is still not the best way to access your ActionScript, since the include statement still had to be placed on the timeline. Our ultimate goal is free ourselves from dependence on the timeline.
The Document Class
The document class is a concept that is new to ActionScript with CS3. The purpose of the document class is to specify which ActionScript should run when a Flash movie plays. We do this by associating a particular .as file with the main timeline. We’ll talk about what a class is in a minute.
To associate a particular .as file with a .fla file, in the .fla file open the Properties window. At the bottom right you will see a text field labeled “Document Class”. In this field, you enter the name (excluding the .as extension) of the .as file you wish to designate as the document class of this movie file. This is a file that must exist in the same directory as your .fla file.
Creating Your Own Classes
To create a new class, you are first going to create a new external .as file to hold the class. You can’t create a class directly in the timeline of your .fla.
The first thing that you must do in your class is define the package that your class is part of. This is required in ActionScript 3.0, but wasn’t in 2.0.
A package is defined with the package keyword, followed by curly braces. The class is defined within the curly braces:
package {
}
Next, within the package curly braces, you will give your class a name.
package {
public class FirstClass {
}
}
A few things to note here:
- You can only define one class per .as file
- The .as file must have the same exact name as the class being defined within it!
- Class names can contain only letters, digits, the underscore (_) and the dollar sign ($) characters
- Class names can not start with a number
- Class names must be unique
- Class names can not be a reserved word
- It is conventional to create class names with modified camel case notation: MyClass
- It is conventional to name classes using nouns
Now you can create a new Object instance based on your custom class from within your Flash file.
var myFirstClass:FirstClass = new FirstClass();
This isn’t very interesting, however, since our class has no properties or methods associated with it.
Adding Properties to Your Class
Without some properties, defining your own class is pretty pointless. So let’s look at the example from Foundation ActionScript 3.0 book:
package {
public class IPod {
public var name:String = "";
public var volumeLevel:uint = 10;
public var tracks:Array;
public var currentTrack:uint = 0;
public var shuffle:Boolean = false;
}
}
Now the IPod class has inherent properties that can hold values for each IPod instance:
var myIPod:IPod = new IPod ();
myIPod.name = "Steve's iPod";
myIPod.volumeLevel = 11;
myIPod.tracks = ["Miles Davis - Kind of Blue","Coldplay - Yellow","Gorrilaz - Dirty Harry"];
myIPod.shuffle = true;
Adding Methods to Your Class
Right now, our IPod object has some characteristics (properties) but can’t really do anything. To this end, we want to add some methods. Methods are defined as functions within the class:
package {
public class IPod {
public var name:String = "";
public var volumeLevel:uint = 10;
public var tracks:Array;
public var currentTrack:uint = 0;
public var shuffle:Boolean = false;
public function play():void {
trace("Playing: "+ tracks[currentTrack]);
}
}
}
Now we can call the play() method.
myIPod.play();
If you run this code you’ll see that it still doesn’t do that much, we always “play” the same track. But now, let’s create a new method for our IPod class, and invoke a method of the built-in Math class to make things a little more interesting, using the shuffle property we previously defined for our iPod.
public function next():void {
if (shuffle) {
currentTrack = Math.floor(Math.random()*tracks.length);
}
}
Now, if the current value of the shuffle property is true, the next function, when invoked, will randomly set the value of the current track. Note a couple of clever things about this construction – the Math.floor method is applied because the tracks array index starts with 0, and the random number generated by Math.random is multiplied by tracks.length to give the proper range of numbers.
Now if we invoke the next() method, then the play() method, we will get a random currentTrack value returned.
What if our shuffle properties is instead set to false? If we aren’t shuffling, then really what we want our iPod to do is play the next item in the tracks array. We should add logic in the next function to handle this case.
public function next():void {
if (shuffle) {
currentTrack = Math.floor(Math.random()*tracks.length);
} else {
if (currentTrack == tracks.length -1) {
currentTrack = 0;
} else {
currentTrack++
}
}
This will play the next track in the tracks array, unless the currentTrack is the last track, in which case it will reset currentTracks back to the beginning.
Constructor Methods
A constructor method is a special method within a class that allows you to “initialize” a new object instance when it is created. This allows you to set up an object before you do any outside property accessing or method calling. The constructor method is automatically executed when you create a new object instance. There are some rules for the constructor method:
- Only one constructor method per class
- The constructor has exactly the same as the class
What the constructor method actually does is really up to you as the programmer, just as what properties and methods are part of your class. In the book’s example, the constructor is used to initialize some properties of the IPod so that they can be set in the same line as the new object instantiation. The difference here between the way the properties were originally set is that you can set the specific to your new IPod instance without having to do it separately for each property.
package {
public class IPod {
// define properties
public var name:String;
public var volumeLevel:uint;
public var shuffle:Boolean;
public var currentTrack:uint;
public var tracks:Array;
//constructor method
public function IPod(name:String=" ",volumeLevel:uint=10,shuffle:Boolean=false){
this.name = name;
this.volumeLevel = volumeLevel;
this.shuffle = shuffle;
currentTrack = 0;
tracks = new Array();
}
public function play():void {
trace("Playing: "+ tracks[currentTrack];
}
}
}
Now we can set the values of name, volumeLevel, and shuffle at the same time as we make a new IPod:
var myIPod:IPod = new IPod ("Katy's Nano", 11);
Note that we if we don’t set an initial (or default) value for a properties passed in the constructor method, it becomes mandatory to set it when you create a new instance of the object.
Controlling Access to Properties and Methods
Livedocs > Class Property Attributes
So far, we have listed all our properties and methods as “public”. This means they are readable and modifiable from anywhere in our code. There are cases when we may not want to make the properties and methods of an object quite so accessible. We can manipulate these access attributes to limit the access like so:
- private – accessible only to methods of the class itself
- public – accessible to any code in the application where the class exists
- protected – can be accessed by the class and its children (subclasses or classes that extend the class)
- internal – accessible to any class in the same package
The last two won’t make too much sense until we talk more about packages and inheritance.
Now we’ll add a private variable to the IPod object – _serialNumber:
private var _serialNumber:String;
We can set the initial value of this new property using the constructor method, but if we try to access it later, say using trace, we’ll get an error when we try to compile the code.
Static Properties and Methods
The static attributes allow use to create properties and methods that don’t belong to a specific instance of a class. A good example of this is the Math class. There is no “Math” object that we work with in ActionScript, but the Math class is a useful collection of mathematical properties and methods that we can access when we need them.
We define static properties and methods like this:
public class StaticExample {
public static const PI:Number = 3.1415;
public static function doStaticStuff():void {
//take some actions
}
}
You can then access the properties and methods of the StaticExample class without creating an associated object:
trace(StaticExample.PI);
StaticExample.doStuff();
Using Inheritance
You can create an inheritance relationship between classes by using the extends keyword. An inheritance relationship is an “is a” relationship. In other words, my relationship to the Garnier family is thus: Katy “is a” member of the Garnier family. This means that I have all the attributes of a Garnier.
A subclass is a specialization of the base, or parent, class:
public class SubClass extends BaseClass {
}
Let’s relate this back to the IPod class:
package {
public class PhotoIPod extends IPod {
//define properties specific to the subclass
public var photos:Array ;
public var currentPhoto:uint;
//define constructor for the subclass
public function PhotoIPod (serialNumber:String, name:String=" ", volumeLevel:uint=10, shuffle) {
super(
serialNumber, name, volumeLevel, shuffle );
photos = new Array();
currentPhoto = 0;
}
//This function shows the number of the current photo
public function showPhoto():void {
trace("Showing: "+ photos[currentPhoto]);
}
public function nextPhoto():void {
if (currentPhoto == photos.length -1) {
currentPhoto = 0;
} else {
currentPhoto++;
}
showPhoto();
}
Now you can create new instances of the PhotoIPod class. The PhotoIPod has all the properties and methods of the IPod class, in addition to the properties and methods that are unique to itself.
Using Packages to Group Classes
So far we have been putting classes into the default package. This isn’t really the best way to organize things, what we really want to do is create logical custom packages to hold our code:
package name {
....
}
It is the convention to name your packages by reversing the domain name of the company (com.companyname) that the code is coming from. You should organize your classes in a way that best makes sense to you.
Importing Classes Into a Package
If you want to utilize the code from built-in or custom classes within your own packages, you must import those classes. For example, if I want to use MovieClip objects in my class, I need to add this code before my class definition:
package advancedActionScript.fall08.catherineGarnier.week3 {
import flash.display.MovieClip;
}
If I want to import all the classes in a given package, I use the * character (also called a wild card):
package advancedActionScript.fall08.catherineGarnier.week3 {
import flash.display.*;
}
This only imports the classes that are directly in that package, not in subpackages.
Homework
- Take the “MadLibs” and “Pick A Number” exercises from the past weeks and rewrite them as external classes. Create a flash file for each with the associated class as the Document class of the .fla.