This website uses cookies to improve user experience. By using our website you consent to all cookies in accordance with our Cookie Policy. X

From AS2 to AS3: duplicateMovieClip() in ActionScript 3 [advanced]

Programmers that decide to switch to AS3 from AS2 will find sooner or later that the latest ActionScript iteration lacks duplicateMovieClip() function equivalent. It might seem odd, since it is hard to imagine Adobe having problems with implementation of such function. My guess is they are trying to kill wrong AS habits. In any case, sometimes you just have to duplicate a MovieClip and that is why I compiled a list of most common solutions:

1. Custom class.
I think around 90% of people looking for the duplicateMovieClip() alternative should find this solution sufficient. In brief: it is about creating a MovieClip's sub-class and then linking it graphics we want to duplicate. So for example, if we were to create an application with falling stars in the background we of course would start by creating a single MovieClip star and then copying it multiple times. To do this open the properties of that MovieClip star and in advanced settings check "Export for ActionScript".
Export for ActionScript
From now on "Star" class contains the star graphics and can be duplicated by writing:

var mc:MovieClip = new Star();
addChild(mc);
That is it.

2. Using the loadBytes() function within the Loader class.
Well sure, #1 method is pretty nice but what if we want to make copy of externally loaded file? In this case lets start by looking how to load the graphics from outside:

import flash.display.Loader;
import flash.events.Event;
import flash.net.URLRequest;

lLoad = new Loader();
lLoad.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoaded);
lLoad.load(new URLRequest("your_file.swf"));

function onLoaded(e:Event):void {
	addChild(lLoad.content);
}
Okay, so at first glance Loader doesn’t seem to have that many functions we could use after loading an external SWF file - we could pretty much either unload it or load different file. The second options is out of the question (except if user has local caching enabled Flash will actually load the content from there rather than connecting to the server again) unless we use loadBytes(). The trick here is that loadBytes() can load any file-type supported by load() but does the reading from a ByteArray. The questions now is: where do we get that ByteArray of a loaded MovieClip from? The answer is actually very simple:
function onLoaded(e:Event):void {
	addChild(lLoad.content);
	lLoad.loadBytes(lLoad.content.loaderInfo.bytes);
}
The lLoad.content.loaderInfo.bytes property holds the loaded animation as ByteArray, so it is only a matter of putting it into the loadBytes() and then again catching the onLoaded event resulting in another MovieClip copy without actually establishing any outside connections.
However there is one problem, onLoaded event won't be called instantly... which means we will get our duplicated MovieClip only after few or more milliseconds (depends on FPS value).

3. Using the constructor property for objects loaded with Loader.
Alternative way to duplicate externally loaded SWF is by using the constructor property available for every object created in Flash. Lets just go ahead and see how it works:

function onLoaded(e:Event):void {
	var d:DisplayObject = new lLoad.content["constructor"]();
	addChild(d);
}
(Because constructor property is dynamic this is the only way to access it. Also, don't forget the keyword new!)
Unfortunately it is not a perfect solution. The code will work only when the loaded movie has a custom "Document Class" (it can be anything as long as "Document Class" is not empty), which basically means you have to be the author of the target file.

To save some work in future I've implemented all those solution into a single class - should have no problem with duplication of any MovieClips (and not only): foras_clone.zip
It is used in the following way:

import foras.utils.ForCloner;
import flash.display.DisplayObject;
if(stage==null) return;
var fas_Clone:ForCloner = new ForCloner();
var d:DisplayObject = fas_Clone.cloneMovie(my_mc,onClone);
if(d!=null) {
	d.x = stage.stageWidth*Math.random();
	d.y = stage.stageHeight*Math.random();
	addChild(d);
}

function onClone(d:DisplayObject):void {
	d.x = stage.stageWidth*Math.random();
	d.y = stage.stageHeight*Math.random();
	addChild(d);
}
Because ForCloner class uses the loadBytes() method (mentioned as second solution on the list) cloneMovie() requires a callback function to take over the duplicated MovieClip. Of course it is entirely possible it won't be need and cloneMovie will instantly return a copy. However in most cases it will result in the null value, which is where the callback function is used (onClone in the example above) - it will be given the copy of target MovieClip.
One last thing, if(stage==null) return; line stops the code for executing twice - if everything else fails whole application will be duplicated along with its source code (but at the end only target MovieClip will remain, everything else is deleted).