Have you ever tried extending the MovieClip class? The standard way is to create your actionscript class extending from MovieClip, adding a MovieClip symbol to the library, setting a Linkage Identifier and specify the Actionscript 2 class. To create an instance of your class on the stage, you have to use attachMovie(). Problems of this method are: it requires a great deal of “work” to create class file, create library symbol & set it up and your code is more difficult to port between projects (recreate the library stuff in each projects). However, there are ways to extend MovieClip, without using the library directly.
classic way
We start with a basic MyRectangle class
class MyRectangle extends MovieClip { private var __width:Number; private var __height:Number; public function set width(value:Number) { __width = value; draw(); } public function get width():Number { return __width; } public function set height(value:Number) { __height = value; draw(); } public function get height():Number { return __height; } public function MyRectangle() { trace("created MyRectangle instance"); } public function onLoad():Void { trace("loaded"); __width = (width) ? width : 100; __height = (height) ? height : 100; draw(); } public function draw():Void { clear(); moveTo(0, 0); beginFill(0x000000, 100); lineTo(width, 0); lineTo(width, height); lineTo(0, height); lineTo(0, 0); endFill(); } }
To start, we use the classic way:
- create a new movieclip symbol in your library
- right click, choose linkage and fill in the linkage identifier & Actionscript 2 class (MyRectangle)
- drag an instance of the MyRectangle MovieClip on your stage
By default, it will create a 100×100 rectangle on the stage. Notice the constructor and onLoad event and the order of (auto) execution when you run the swf…
getting rid of the library symbol
Now, we’re gonna get rid of the library symbol. We don’t want to create empty library symbols for each class extending MovieClip. We will use attachMovie to create an instance of our MyRectangle class. However, as we don’t have a linked library item, we can’t use attachMovie… or can we?
When a linked class is compiled into the swf, it gets a linkage name of “__Packages.” followed by the full package name and class name. We can do this trough code aswell! By linking that linkage name to the class constructor, using Object.registerClass, we can use attachMovie again…
class MyRectangle extends MovieClip { static var symbolName:String = "__Packages.MyRectangle"; static var symbolOwner:Function = MyRectangle; static var symbolLinked = Object.registerClass(symbolName, symbolOwner); private var __width:Number; private var __height:Number; //... }
We now use attachMovie on our main timeline to create an instance of our rectangle class:
this.attachMovie(MyRectangle.symbolName, "rectangle_mc", this.getNextHighestDepth());
Hooray! We don’t have a library item anymore! But I still don’t like the attachMovie outside of our class. Instead, you could write a static create method, that does the attachMovie and returns an instance of our MyRectangle. You could also pass a parameter object to the function…
public static function create(container:MovieClip, initObj:Object):MyRectangle{ container.attachMovie(symbolName, "rectangle_mc", container.getNextHighestDepth(), initObj); return MyRectangle(container["rectangle_mc"]); }
To create a rectangle, you could use:
var rect = MyRectangle.create(this, {_x:100, _y:100, height:200});
Using this method, you could create classes extending from eachother and MovieClip as the root class. I’m thinking about adding eventdispatching to all your MovieClips, basic animations (flyTo(x,y)),…
Enjoy!


waarom zo’n blog? en niet iets meer persoonlijks … leef niet om te werken .. werk om te leven :)
hmm… this looks very interesting.. I have yet to try it.. but you are bookmarked.. I too was hating the idea of a library instance to get this done… and no one else had a sample.
Say there, when doing this.. did you have trouble with “Attribute used outside class.”… ?
thanks
Hey Robert,
Where did you declare your attribute? You didn’t happen to declare a variable outside the class{} braces?
Wouter,
Thanks for the quick reply…. and this code is a wonderful start.. I may use it quite often..
Now…. to be honest, not really sure why it did not work when I wrote previous comment.. BUT..
I got it to work after much intense trial and error…
Now here is the next question:
How can this be made to work with subclasses using a dynamic create function?
Unless I have misunderstood everything here, one has to change the symbolName, symbolOwner vars and the create function in order to change the name of this class for subclassing.
This seems to be logical… ie.. make the subclassing require less effort.
I have been trying for a few hours today to create a dynamic create class with no luck.
I had some things which looked as tho they should work.. but they did not..
Any ideas? Am I missing something?
Mind you, I have been with actionscript for only last few months.. so if I ask a silly question, please be patient.
Thanks again..
Robert
Robert,
Sure, you can subclass classes like this. Basic example:
//Top level Shape class:
class MyShape extends MovieClip {
static var symbolName:String = “__Packages.MyShape”;
static var symbolOwner:Function = MyShape;
static var symbolLinked = Object.registerClass(symbolName, symbolOwner);
public static function create(container:MovieClip, initObj:Object):MyShape{
container.attachMovie(symbolName, “shape_mc”, container.getNextHighestDepth(), initObj);
return MyShape(container["shape_mc"]);
}
}
//A class extending this Shape:
class MyRedShape extends MyShape {
static var symbolName:String = “__Packages.MyRedShape”;
static var symbolOwner:Function = MyRedShape;
static var symbolLinked = Object.registerClass(symbolName, symbolOwner);
public static function create(container:MovieClip, initObj:Object):MyRedShape{
container.attachMovie(symbolName, “shape_mc”, container.getNextHighestDepth(), initObj);
return MyRedShape(container["shape_mc"]);
}
}
The static create function is not necessary, but handy to create instances of our custom class. The thing that does the actual trick is:
static var symbolLinked = Object.registerClass(symbolName, symbolOwner);
With symbolName being the __packages.CLASSNAME and symbolOwner CLASSNAME (without quotes).
Good luck!
This was really useful to me and I have been able to create classes using it. I still have two nagging questions:
1. Why can’t I use something like
var newRect:MovieClip = new MyRectangle();
with a parameter maybe?????
instead of
this.attachMovie(MyRectangle.symbolName, “rectangle_mc”, this.getNextHighestDepth());
or the create function (which is what you prefer and I have been implementing)
2. What does the parameter in the
return MyRectangle(container["rectangle_mc"]);
really do – is it a form of the MovieClip constructor? Your constructor does not take a parameter…
Thanks.
rossisen
1. You could do something like this, but you would have to pass a reference to the movieclip parent through the constructor.
2. This is not a constructor, but a class cast, to indicate to the AS2 compiler that we are working with the correct class type (which is specified as return type in our function definition).
We have been having some trouble with having Array properties of a class. We have been getting one instance changing the values of another instances’ array. Here is an example boiled down to its most basic:
The .as file
class edu.clips.ArrayTester extends MovieClip {
static var symbolName:String = “__Packages.edu.clips.ArrayTester”;
static var symbolOwner:Function = ArrayTester;
static var symbolLinked = Object.registerClass(symbolName, symbolOwner);
//private var Shapes:Array; //can be used with the commented line below
private var Shapes:Array = new Array();
private var num:Number = new Number();
private var initShapes:Array;
public static function create(container:MovieClip, instanceName:String, initObj:Object) {
container.attachMovie(symbolName,instanceName,container.getNextHighestDepth(),initObj);
return ArrayTester(container[instanceName]);
}
public function ArrayTester(target:Object) {
//this line is necessary or the various instances use the same Array – how weird is that
//Shapes = new Array();
for (var ii = 0; ii<initShapes.length; ii++) {
trace(”setting “+ii);
this.Shapes[initShapes[ii]] = ii*ii;
num=initShapes[ii];
}
}
public function traceArray():Void {
trace(”Shapes “+this.Shapes);
trace(”initShapes “+initShapes);
trace(”num “+num);
}
}
The calling .fla
import edu.clips.ArrayTester;
ArrayTester.create(this,”at1_mc”,{initShapes:[1,7,9]});
at1_mc.traceArray();
ArrayTester.create(this,”at2_mc”,{initShapes:[2,3,10]});
at1_mc.traceArray();
and the output:
setting 0
setting 1
setting 2
Shapes undefined,0,undefined,undefined,undefined,undefined,undefined,1,undefined,4
initShapes 1,7,9
num 9
setting 0
setting 1
setting 2
Shapes undefined,0,0,1,undefined,undefined,undefined,1,undefined,4,4
initShapes 1,7,9
num 9
Notice that the Shapes Array for at1_mc is different after at2_mc is created. This is not the case for a similarly treated Number object. If the commented lines are switched in then this behaviour does not occur. Is this an expected thing or a bug?