Again – must preface as always with not the expert!
I spent alot of time last year learning design patterns, specifically MVC. The basic premise is having a Model that holds and controls the non-visual or data-based stuff, a bunch of Views that make up the visual pieces we interact with, and a Controller that manages the state of the system and what needs to happen when. The general theory – I think – is that the Model is the data and the Controller manages the graphics (Views). Unfortunately, most design pattern descriptions then go straight into much more detailed definitions of precisely what these things should look like in code, what each class MUST and MUST NOT do and that if you don’t follow such rules, you’re a moron.
But what I’ve learned is that these rules are meant to be broken. Building a strict design pattern can be alot of work, making your simple little project take alot longer than it should.
Fortunately, I’ve found ways to implement these theories slowly without going too deep into pattern mechanics. And yes, you should absolutely learn the detailed stuff about patterns because it teaches you when to divvy up into classes and when not to – but I’ll show here some basic code here that I use to keep a small sized project small, manageable, and easily updateable and scalable.
The “Main” class
Open a new FLA file and save it someplace.
The first wierdness when it comes to developing with Flash and MVC is how the Document class plays a part. Most design pattern books I’ve read do not cover this very well. When building apps with Flash and AS3, its typically best to have all of your code external from the FLA itself, including the Document class. This is linked to in one of three places:
- the Properties Panel of the FLA Document – left click a blank area of the stage, and open the Properties Panel
- choose the Modify Menu -> Document
- choose the File Menu -> Publish Settings… -> Flash Tab -> Settings… button next to the “Actionscript version” drop-down box
The file you’re linking to in the Document box is going to be the base class for the FLA. Its an external file that will setup the bare root of the entire project. Most of the time, this is “Main.as” or “Document.as,” but you need to type in only the class itself, not the full filename. Almost 99% of the time this is the filename without the extension.

Assigning the Document Class in the Actionscript 3.0 Settings Panel
Now that the class is linked, we have to create the file “Main.as” and place it in the same folder as the FLA. Its going to start out like this:
package {
import flash.display.MovieClip;
public class Main extends MovieClip {
public function Main() {
}
}
}
This is a bare class that does nothing but get constructed. Note that since we’re developing in the Flash IDE, we must extend the MovieClip class for the document class.
The basic flow for our MVC is the Document class is going to instantiate our Model and Controller, and the Controller, with direct reference to the Model, is going to instantiate the Views. Lets start with the Model.
The “Model” class
Create a new actionscript file called “Model.as” in the same folder as your FLA. This is going to handle our data and it might look something like this:
package {
import flash.events.Event;
import flash.events.EventDispatcher;
public class Model extends EventDispatcher {
private var _data:Array = new Array();
public function Model() {
}
public function initData():void {
for (var i:uint=50; i<59; i++) {
var lineOfData:uint = i;
_data.push(lineOfData);
}
dispatchEvent(new Event(Event.COMPLETE));
}
public function get data():Array {
return _data;
}
}
}
Model is non-visual so it really doesn't need to extend anything. But since we are going to dispatch Events from it with dispatchEvent(), we have to extend the class from EventDispatcher.
When the Model is instantiated, it'll do nothing. But when initData() is run, the Model will populate the _data array with some data (consisting of 10 values with the numbers 50 through 59), and dispatch a Complete event when its done. Our Main class is going to listen for that Complete event. This allows us to have a chain of events (no pun intended) occur so that things get done in a specific order. More on that later.
Note also the get data function. This is done so that our _data Array is easily accessible to other classes. We don't need a set _data because we only want the Model to control it - basically a read-only permission to the Array.
Lets look at the Controller next.
The "Controller" class
Create a new Actionscript file and call it "Controller.as" in the same folder as your FLA. Our Controller is going to create views when they need to be created and tell them what to do as we interact with our project. Here's a starting point:
package {
import flash.display.Sprite;
import flash.events.Event;
public class Controller extends Sprite {
private var _model:Model;
private var _views:Object = new Object();
public function Controller(model:Model) {
_model = model;
}
public function initViews():void {
// setup default views here
dispatchEvent(new Event(Event.COMPLETE));
}
private function addView(view):void {
_views[view.name] = view;
addChild(view);
}
private function removeView(view):void {
removeChild(view);
delete _views[view.name];
view = null;
}
}
}
Firstly, note the addView and removeView functions, as mentioned in my previous posting. We need to extend the Sprite class because the Controller is going to hold visual stuff. Note also that the Controller is getting a reference to the Model in its constructor, and its placed in a variable that can be accessed from anywhere in the class. We are creating a direct link to the Model from our Controller, even though the Model knows nothing about the Controller.
Finally, lets add a View.
The first "View" - a Circle class
We'll call this view "Circle.as" and all it'll do is draw a circle:
package {
import flash.display.Sprite;
import flash.display.Shape;
import flash.events.Event;
public class Circle extends Sprite {
private var _views:Object = new Object();
public function Circle() {
}
public function drawCircle(radius,color):void {
var circle:Shape = new Shape();
circle.name = "circleA";
circle.graphics.beginFill(color,1);
circle.graphics.drawCircle(0,0,radius);
circle.graphics.endFill();
addView(circle);
dispatchEvent(new Event(Event.COMPLETE));
}
private function addView(view):void {
_views[view.name] = view;
addChild(view);
}
private function removeView(view):void {
removeChild(view);
delete _views[view.name];
view = null;
}
}
}
Once again, we have addView() and removeView() and are extending the Sprite class. drawCircle() is expecting two arguments to decide what the radius and color of the circle is going to be. The x and y values are zero, but we can simply assign x and y on the circle class when its instantiated by the Controller. Not much else to our circle.
Completing the circle of events
Now, let's move backwards and start instantiating everything. In the Controller's initViews(), we'll instantiate the Circle class, add a listener for its Complete event, and run the drawCircle method. We also need a new function, viewsInited, to handle the Complete event:
...
public function initViews():void {
var myCircle:Circle = new Circle();
myCircle.name = "myCircle";
myCircle.x = 100;
myCircle.y = 100;
myCircle.addEventListener(Event.COMPLETE,viewsInited,false,0,true);
addView(myCircle);
myCircle.drawCircle(50,0x000000);
}
private function viewsInited(evt:Event):void {
dispatchEvent(new Event(Event.COMPLETE));
}
...
So - when Controller's initViews() runs, it instantiates the circle and waits for the Complete event. When the circle sends its Complete event, the Controller in turn sends its own Complete event in viewsInited() to its parent, Main.
So, in the Main class, we need to instantiate the Model and Controller and listen and handle Complete events from both. Here's our new Main.as:
package {
import flash.display.MovieClip;
import flash.events.Event;
public class Main extends MovieClip {
private var _model:Model;
private var _controller:Controller;
public function Main() {
_model = new Model();
_model.addEventListener(Event.COMPLETE,modelInited,false,0,true);
_controller = new Controller(_model);
_controller.addEventListener(Event.COMPLETE,controllerInited,false,0,true);
addChild(_controller);
_model.initData();
}
private function modelInited(evt:Event):void {
_controller.initViews();
}
private function controllerInited(evt:Event):void {
// all done!
}
}
}
Notice that I've turned to the path of simplicity here with using addChild() instead of addView(), because, as of now, I know I'll never do much of anything else with the Document Class (which has actually backfired on me before, but lets keep it simple...). I will never need to remove either the Model nor the Controller since they form the structure of my project. Note too that the Model is being passed as an argument into the Controller's constructor to create that direct communication between the Model and Controller. You're ready to run your project and should see a circle on the stage.
Keep it sequential!
So you might be wondering what exactly is going on here. So much work for a single circle? And why all of the Events?
Again, the goal is to keep things sequential and leave room for scalability. Lets look at keeping it sequential first.
Say the radius value of the circle is something we want to have dynamically in the data array of the Model. Maybe each of our data Array's values are different radii of circles? Since we have a reference of the Model in the Controller, we could get those values directly from it and use it when we draw the circle in the Controller:
... myCircle.drawCircle(_model.data[0],0x000000); ...
The first value in the Model's data Array is 50, so that's going to be the radius of the circle. But what if the Model's initData() function hasn't run yet? You'll get an error. Thus the need for this chain of events to occur.
So here's the final order of things:
- The Document Class, Main, is constructed
- Model is constructed
- Controller is constructed
- Main tells the Model to retrieve and build some data and waits for a response
- Model sends a Complete event to Main when its done
- Document tells Controller to initialize its views and waits for a response
- Controller constructs a Circle and waits for a response
- Circle sends a Complete event to Controller
- Controller sends a Complete event to Main
And that's about it! In my next post, we'll add more views, talk about scalability, and create a new circle of direct communication from Views to the Model as well as create Sub-Controllers of the Controller.
Here's a zip of the source for this post:
A Little Bit of MVC Source Files
- AS3 My Way: Intro
- AS3 My Way: Name Everything!
- AS3 My Way: Adding, Removing, and Memory Usage
- AS3 My Way: A little bit of MVC
Have a question or comment?