AS3 101: OOP Introduction – Basix

Twice a month, we revisit some of our readers’ favorite posts from throughout the history of Activetuts+. This week’s retro-Active tutorial, first published in October 2010, is an introduction to object-oriented programming in AS3. Don't forget to check out the other AS3 101 tutorials!

Object-Oriented Programming is a bit of a hot topic. More and more programming languages are cropping up that support it (Ruby, for example), and more and more languages that previously didn't support Object-Oriented Programming (OOP for short) have been released with versions that do, like PHP and ActionScript. Some languages only work if you utilize the whole OOP thing to begin with, like Java and Objective-C.

It's actually been around for a long time, but came into the limelight in the 1990's primarily due to its advantages with programming GUIs and the rise of C++ and Objective-C. Wikipedia has an interesting section on the history of OOP, which is a great place to start learning.


Introduction

If you're new to Object-Oriented Programming, you have a bit of a learning curve ahead of you. However, embracing this technique isn't just the "in" thing to do; it can decrease your development time while also decreasing the number of bugs in your code. It keeps you organized and prevents needless duplication. But perhaps more compelling than those lofty promises is the fact that Adobe has certainly put all of their weight behind the concept of OOP when it comes to ActionScript. ActionScript 1 was not Object-Oriented at all, and AS 2 was only Object-Oriented as a developer convenience. In contrast, AS 3 supports full-bore Object-Oriented features, and if anything, will only do more so in the years to come. So, if you like programming Flash and don't want to get left behind, it would do you well to adopt OOP as a way of life.

In this tutorial we will gradually introduce the some of the core concepts involved in Object-Oriented Programming. The final product coming out of Flash will be a bit lackluster, but this is just Part 1. You will see some practical explorations of OOP techniques, even if this tutorial isn't really about building a specific project.

You will, however, learn to make a reusable button which can be used in cases where a quick-and-dirty button is required, or even, with modification, as a key element to your next project.


Step 1: The Big Question

So what is this Object-Oriented Programming all about?

First, let me explain what it is not. Object-Oriented Programming (or OOP for short) is not the only or even necessarily the best way to program in ActionScript 3. There seems to be a myth floating around ever since ActionScript 3 debuted that, in order to use AS3, you need to use OOP.

While it's true that AS3 is much better-suited to OOP than AS2 was, and that you are encouraged to move in that direction, it's not true that you have to learn to write classes and instantiate objects in order to build real applications in Flash. If you've followed the AS3 101 series up until now, you may have noticed that every line of ActionScript 3 that we wrote in the process was in the script panel, not a class file. This should help illustrate that it's perfectly acceptable to not utilize OOP as you work in Flash.

That being said, ActionScript 3 really does shine when you start to embrace OOP. And not just AS3, but any language that supports OOP can be utilized more effectively when OOP techniques are engaged. This is because OOP is really just a technique – a big, complex technique with lots of options to consider, but still, just a technique – and not a mandate. And it is a great technique, one that you should start mastering. And that's why you're here, right?


Step 2: Classes and Objects

Object-Oriented Programming really boils down to two fundamental units: classes and objects. The two are intrinsically related: a class begets an object.

Think of a class as a blueprint of a house, and an object as an actual house. The blueprint is more of a schematic for what the house will be like, not an actual house. When you write object-oriented code, you write the blueprints, the classes. Your code then creates the objects from these classes when it runs.

A blueprint can also be re-used to create more than one house. In certain housing developments, you can see this in action; a cost-saving technique that pays the architect for one blueprint, but generates several houses from that blueprint. These houses are all unique entities, and what goes on in one house is isolated from what goes on in another house. However, they share a lot of features in common, such as the layout of the plumbing and the electrical wiring, or where the stairs are located. The houses may all have a front door at the same location, but one house might have a metal door painted red, and another house might have an unpainted wooden door with a knocker.

A class, similarly, can create more than one object. These objects are all of the same type, but are all unique entities, like the houses. Again, they share many common features, but maintain separate identities. An object that loads data from an external source would have, as a common feature, the ability to load data and dispatch a complete event when it is ready. However, one instance of this loader would have a unique characteristic that loaded data from one URL, while another instance would load data from a different URL.

The term instance is a word that describes an object. When an object is created from a class, it is said to be instantiated, and thus an instance of the class is born. The word object is typically synonymous with instance.

If the terminology is troubling you, keep in mind the Library Symbol/Instance relationship that's been around since Flash 1. A symbol is a single item in the library. An instance is a particular manifestation of that symbol. There can be more than one instance of a given symbol, and changes to a single symbol's artwork will change all instance of that symbol. Yet each individual instance can maintain some unique properties, like position, rotation, color transformation, filters, and scale (to name but a few). This is directly analogous to class and objects (instances). In fact, it's more than just analogous, as we'll see in the next installment of this series.


Step 3: Meet the Document Class

Well, let's jump in, shall we? I think the best way to get your feet wet in OOP AS3 is to become familiar with the document class. The document class is a class like any other in AS3, except that it has a very special relationship with a Flash file. It is the class that represents the SWF that you publish. The document class gets instantiated when the SWF starts up. This is analogous to the idea of a "main" function if you have a background in C, or the "main" method of the main class in Java.


Step 4: Make a Project Folder

Let's make a document class, which will act as a basis for steps later in this tutorial. To do so, first create a folder on your filesystem that will house this particular project.

Now make a Flash file (ActionScript 3.0), and save it to this folder. The name isn't terribly important, but I'll be naming mine MeetTheDocumentClass.fla


Step 5: Document Class Text File

Now you need to make a text file. You can use Flash CS3+ for this, or you can use Flex/Flash Builder, or you can use any other capable text editor, really. FlashDevelop is a great (and free) choice, if you're on Windows. There are many choices in text editors, and there are no right answers (although, as I tell my students, there is one wrong answer. The text editor built into Flash CS3/4 is actually quite abysmal, and the sooner you embrace that fact the sooner you'll enjoy coding in a real editor). Personally, I'm fond of TextMate, but keep in mind that what matters is the text within the file.

All that being said, create a new file in the editor of your choosing (if you're using Flash CS3+, go to the File menu, choose New, and then choose ActionScript File from the list. If you're not, then I assume you're familiar enough with your editor to be able to do this without direction from me).

Save this file as DocumentClass.as in the same folder as your Flash file. This is important: the location and the name matter very much. The name doesn't have to actually be "DocumentClass.as" but it's what I'll be using and to prevent confusion, I recommend you just do what I do. The name can be anything you want (more or less), but my point is that the name plays an important role in AS3 OOP, so be paying attention. Same deal with the location of the file; technically it can be anywhere but for convenience just follow my lead. More options will be revealed by the end of this series.

To summarize, here's my project folder as it stands:


Step 6: Write the Document Class

You are now faced with an empty file. If you've ever suffered writer's block (I have, which regular readers might have guessed...), you can be comforted in the fact that the first thing you need to write is actually boilerplate. You'll need to write the following:

Wow, what is all that? Well, it's a bit more than we need to explain right now. I'll just point out a few places of interest.

First, note that the package wraps up the entire thing. Don't worry about what this is right now, just remember that it needs to be there, and the class needs to be contained within it.

Second, we have an import statement. You may not have seen a line of code like this before; if you've stuck to coding in the Script panel up until now and haven't made use of third-party ActionScript libraries, you've never needed to write an import statement. In OOP-world, each class needs to import the various classes it needs in order to do its thing. More on imports later.

Third, the next "wrapper" is the class itself. You can see the keyword "class" in the third line. The anatomy of this line is more than we need right now, just note that the word following the word "class" is the name of the class. You may have noticed that the name I used is the same as the name of the file, sans extension. This is not a coincidence. For classes to work in AS3, the name of the class must match the name of the file. Don't forget that.

We'll come back to the "extends MovieClip" bit in the next tutorial. For now, just know that this bit is required for a document class (you can also extend Sprite, a la "extends Sprite", if you don't need the timeline, and if you change the import line to "import flash.display.Sprite;")

Finally, we have the constructor.


Step 7: The Constructor

In the previous example, there is an (almost) normal function defined within the class. Almost normal, except for that "public" in front, and the missing datatype. Again, don't worry about "public" for now, that'll come in time. However, note the name of the function. That's right, it's the same as the file and as the class name. Hopefully you're not overly paranoid, because this isn't a conspiracy. It's just the way things work. By naming the function with the same name as the class, we create a special function called the constructor. The constructor gets executed during instantiation. Hopefully you're keeping up with the new terminology, because we just used two new terms in the same sentence. nerdCred++;

An object will be able to have other functions in it, which you are welcome to define, but the constructor is the only function that gets called automatically during instantiation. The constructor, therefore, is where you would want to put code that should execute to get an object ready for initial use. For example, if you're writing a class for an object whose job it will be to load some XML, parse it, then load thumbnail images based on that data, you might want to create a URLLoader, set up its event listener, and perhaps even start loading, all when you create the object. That logic could then go into the constructor.


Step 8: Hello, World!

As a practical example, we'll do a little "Hello World" program. We won't simply trace the words to the Output panel, no, that's a little mamsy and definitely too pamsy. We'll create a TextField, add it to the stage, and put some text into it. Expand your DocumentClass.as file to look like this (changes are in bold):

Note that in addition to the three lines added to the constructor, there is now an extra import line in anticipation of the TextField.

We could obviously take it further, positioning and styling the text, and you're welcome to do that on your own, but for now this serves the purpose. This code creates a text box with the words "Hello Word" in it, and displays it on stage. Except for one thing: The Flash file doesn't know that it's supposed to have a document class. If you try to run your Flash file now, you'll get an empty window. Let's fix that next.


Step 9: Assigning a Document Class

As mentioned at the end of the last step, the Flash file (MeetTheDocumentClass.fla in my case) doesn't yet know that it has a specific document class associated with it. Technically, it does have a document class, only the document class is just plain old MovieClip, so it's not going to do much.

It's good to know that, but what we really want right now is to let this Flash file know where the DocumentClass.as file we just wrote is. To do that, first make sure nothing is selected (you can click anywhere on the stage where there isn't a visual asset, or you can choose Edit > Deselect All, or press Command-Shift-A or Control-Shift-A).

Next, open up the Properties panel. If you've successfully deselected everything, the Properties panel should say "Document" at the top

Now, where it says "Class:" under the "Publish" section of the Properties panel, type in "DocumentClass" (or whatever name you used for your version of the class, if you insist on forging your own path). Note that this is without the ".as" – it's just the class name, not the file name.

If you've followed along with the directions so far, you should be able to press Return/Enter and all will be well. If somehow you got the class name wrong, or didn't save the files in the same folder, you won't get an error when you publish. You should have gotten this error when typing in the class name:

If you ignored it, or didn't see it because you had previously checked that "Don't show again" option, then the SWF will publish without error, but you'll get a plain white screen. If this happens, double-check the class name that you've entered into the Properties panel.

Once the document class is properly hooked up, you can verify that by clicking the little pencil icon next to the document class text field in the property panel. This will open up the file in Flash CS3+ for editing. Not that I'd recommend keeping it there, but verifying that you've got the right file can be a helpful troubleshooting tip.

Once everything checks out, go ahead and test your movie. You should see a plain window with the words Hello World in it:


Step 10: Properties

At this point, you are set up to put your application logic into the document class and start making a more interesting SWF. However, you will likely need more than just the constructor function to make said interesting SWF. Usually you need to create other objects, stick them in variables, use functions to listen for events and have these things interact in a meaningful way. Of course, in OOP you have such things as variables and functions, only they properly go by different names: properties and methods (we'll tackle methods in the next step).

Properties are, at their essence, simply variables. There is a slight difference between a property and a variable, though. It's subtle, and we'll have to illustrate it with an example, but we have some ground to cover before we get there.

First, a property is written identically to a variable, with two caveats. Here's an example:

The first caveat should be obvious: there's a big old "private" in front of the var keyword. "private" is similar to the "public" I asked you to ignore a few steps ago. I'm going to ask you to continue ignoring it. We won't get to those until the next tutorial.

The second caveat won't be obvious, because the snippet is out of context. This is more appropriate:

Notice the position of the property in relation to the structure of the class. The constructor function and the property are both at the same "level" and "belong" directly to the class (they are both nested into the class directly). This characteristic makes the variable a property (despite being declared by using the var keyword).

In contrast, the variable named "foo" in the snippet below is merely a variable:

Why? Because it's "owned" by the function, not by the class. When an variable or function gets declared within the confines of curly braces (which is technically every time), it exists for only as long the thing represented by the curly braces exists. So – and here is the subtle distinction – the property "tf" exists so long as the object "DocumentClass" is around, and "belongs" to a DocumentClass object, but the variable "foo" exists only as long as the function containing it runs, and ceases to exist once the function finishes executing.

There are, naturally, exceptions to that "curly brace" rule. Loops, for instance, don't affect the scope of a variable declared within, so take that rule with a grain of salt. You won't find it mentioned in programming books.

You might be asking,

but wait, doesn't the function exist in the object at the same level as the property? Doesn't it exist just as permanently as the property, and therefore wouldn't the variable inside the function exist as well?

You have a point, however, the distinction is that the potential to run a function exists within the object, while the actually running function exists only at the moment it gets called. The variable gets created during the run, and therefore ceases to exist once the run is done. I did say the distinction was subtle. But it is important, as we'll see soon.


Step 11: Methods

Before we get to that, I need to extrapolate what we just learned to functions and methods. Basically, methods are just functions that belong to an object, like the constructor function, only they aren't elevated to any special status. Here, we added another method:

Now, onButtonClick() is a pretty familiar function, except for that pesky public at the beginning. Once again, put that off. Otherwise, you should recognize this as a regular function. The only difference is that the same concept of "ownership" applies to methods as it does to properties, versus regular variables and functions. Finally, let's explore this with a working example.

In your DocumentClass, we'll flesh out the snippets we've seen. Make your class look like this:

Notice the changes and additions: We've added a property called "tf". In the constructor, we still create a TextField, but instead of creating the variable in the constructor like we did before, we simply use "tf" – the property. Our TextField is now stored in the property instead of a variable.

We also added a click listener to the stage (no, the stage isn't really a button, but in this case it saves us from having to create a MovieClip to act as a button). And that listener is a method called onButtonClick(), and other than being a method instead of a function, it's identical to any other event listener.

What this method does is significant: it replaces the text in the textfield with another string. This can only happen if tf retains it value over time. If the movie worked, then we know tf still references the TextField created in the constructor, even though several seconds probably passed between the creation of the TextField and the re-population of it.


Step 12: Exploring Scope

Now, if you remove the property and return the TextField creation to be a variable, you actually won't even be able to test it, as the compiler will give you an error saying it couldn't find a property called tf. That is, this code:

Produces this error:

What happened? Well, in ActionScript, a variable created in one function exists for the duration of the function (which is over a few lines later), and is gone once the second function runs. So if we create a variable tf in the constructor function and try to use it in the onButtonClick() function, we have a problem. tf no longer exists when onButtonClick() runs.

However, properties persist throughout the life of an object, so if we store the TextField in a property instead of a variable, we have access to that TextField in other functions, at pretty much any time.

In this context, variables are sometimes referred to as local variables because they are local to the function.

And this is the subtle point that started this marathon step. Hopefully it sunk in, because I find this point to be the cause of many "gotchas" for beginning OOP students.

Keep in mind that there is more going on with properties, methods, persistence and references. I feel I've belabored the point enough, and won't be doing you any favors by dissecting the finer points of references and delaying other essential knowledge.


Step 13: About That Button…

OK, in the last step I skipped the creation of a button and just used the stage as a clickable area. We'll change that, but not because clicking on the stage is wrong (it isn't, in certain circumstances), but because we can create a Button class to further explore OOP.

Our goal will be to create a Button class, from which we can create multiple Button objects. Each Button object will have some core functionality that is universal across buttons:

  • Hover and normal states
  • The cursor turns to a hand icon
  • A graphic background with a text label

At the same time, there will need to be things unique to each button:

  • The text of the label
  • The click action
  • The position of the button

We'll look at what it takes to create a second class involved in your project and incorporate these requirements as we go.


Step 14: Create a Button Class

We'll create a class that, when instantiated, draws a rectangle, puts text into a label, handles roll overs and outs, and can respond to clicks. Start by creating a new text file in your text editor. Save it as "Button101.as" in the same folder as your Flash file. This is important. Don't mess it up! I'm serious.


Step 15: Write the Boilerplate

In your new file, start stubbing in the class boilerplate:


Step 16: Add Some Properties

Next we'll add some properties to hold the background shape and the label:

The bgd property will hold a reference to a Shape which we'll draw programmatically to be a filled rectangle, and add as a child of the Sprite.

The labelField property will hold a reference to a TextField which we'll create with code, as well, and use to display a text label on top of the background.


Step 17: Add the Logic

And now we'll pop in the actual logic. For the constructor:

That's a lot of code, but it's nothing surprising for the most part. We're creating a new Shape and drawing a rectangle to into it. Then we create a TextField, set it up with some basic formatting. Next up, we add some rollover and rollout events (the listeners for which we'll add in the next step). Finally we set some properties to make the object behave more like a button.

The only part that might be causing confusion is the call to addChild(), and where the mouseChildren and buttonMode properties came from. I'll ask you to yet again wait for a more complete answer, as that will come in the next installment, but it has a lot to do with the "extends Sprite" we wrote earlier.


Step 18: Add Some Methods

Now, we can continue working on our class. After the constructor, create a function called setLabel:

And finally, create the two event listeners:

The final code should look like this:

One thing that is very important is to make sure your methods are declared at the class level. This is another rookie mistake: sometimes people don't pay attention to where their curly braces start and stop, and end up nesting what should be a method (that is, declared at the "root level" of the class) inside another method. This effectively turns a method (which should persist for the life of the object) into a local function (which only persists for the life of the running method in which it was declared).

Hopefully compiler errors will notify you of such a mistake, but the error itself might be cryptic. It would say "1114: The public/private/protected/internal attribute can only be used inside a package." If you get that, check the nesting level of your methods. Another thing to help prevent these errors is to pay careful attention to whitespace and indentation. A "real" text editor can help you with this, but just make sure all of your method declarations are at the same indentation level (typically two tab stops).

What we have now is a class ready roll, which, when instantiated, will create a customized display object that has a gray rectangle with a label. The label can be set using a method and the button will automatically respond to mouse roll overs and roll outs. All we need to do is actually instantiate it.


Step 19: Create a Button

Step back to your document class, and we'll add a button to the movie. This will be pretty easy compared to the previous step.

First, we'll add a new property to hold the button. Stick it below the line with your existing property.

It's not required to put all properties together, but for the organization of your file, it's helpful to keep things in consistent places. Personally, I always list properties at the very top of the class, before the constructor. This way, I always know where to go to find a property declaration. Where they go in the file isn't as important as coming up with your own standard and sticking to it.

Moving on, we can now instantiate the Button101 in the document class's constructor:

Note that we modified the line that set up a listener for clicks on the stage. We're shifting that interactivity to the button.

Now, you may be wondering how it is that we're treating this Button101 object as if it were a Sprite or MovieClip (see the AS3 101 tutorial on the Display List if you weren't wondering that). This has everything to do with that extends business I've asked to gloss over for now. I promise, we'll get to it soon (in the next part of this series).

At this point, we should be able to test it out. It should work similarly as before, except that you'll see the button appear, and instead of clicking anywhere on the stage, you need to click on the button.

For reference, here is the complete document class at this point, with additions and changes in bold:

So, what did that accomplish us? The big thing is that we got a pretty nifty button that we could use with very little effort (not counting the effort put into writing the Button101 class in the first place).

To accomplish the same functionality without classes and OOP, we'd have to write considerably more code in our main script. To illustrate this further, let's create a second button.


Step 20: Create Another Button

OK, now let's let OOP really shine. We'll create a second instance of the button, merely by adding a few more lines of code to the document class.

The changes involved will be extremely similar to the previous step. First, add a property:

Then set it up in the constructor:

You can, in fact, just copy and paste the first button's lines of code and just change button to button2, and also the x position of the second button (otherwise button2 will sit right on top of button1).

We've doubled the complexity of our application in just a few short lines of code, thanks to the reusability of the Button101 class. We have the class, which, if you remember, is the blueprint from which the actual instances are created. We now have two distinct buttons, yet they share that common "heritage." Even though there are many characteristics that are the same between these two buttons, like the rollover effect and the size, there are still aspects of individuality, namely the position.

Hopefully this starts to illustrate the usefulness and power of Object-Oriented Programming, in which we facilitate the reuse of code very easily.

Go ahead and test it out; you should have two buttons that do the exact same thing.

Naturally, you'll probably want to tweak the Button101 class so that it looks fancier, or has a slicker roll over effect, or what-have-you. By all means, take the Button101 class and make it more useful for your own needs. Our goal here was to demonstrate how a button class can be made, not to make the ultimate button class.


Step 21: Summary

There were two main themes in today's tutorial. To recapitulate, these are: the idea of blueprints (classes) and houses (instances); and the notion of scope.

Classes are the code files that we write, as well as the concept of an entity that serves as the blueprint for the objects that will get created from them. One class can beget any number of instances. Objects are the instances of classes, and tend to be the things that, when put together, comprise our application. Instances of the same type share functionality in common, but retain unique identities and can possibly contain variances in the data contained within.

Scope is an important concept through all of programming, and no less so in Object-Oriented Programming. Scope determines the "life span" of a variable or function, and also a "place to live." A variable at the object scope has a different life span than a variable at the method scope.


Until Next Time

This is, however, just scratching the surface of the tip of the iceberg. It's all we have time for right now, but in the soon-to-be-published Part 2 of the AS3101 OOP series, we'll dive a little deeper and finally get an explanation on all of things I was asking to put aside, like extends and public. Things will begin to make more sense. But when it comes to a complicated topic like Object-Oriented Programming, it's best to take things slow.

Tags:

Comments

Related Articles