So I’m sure you’re thinking "well that’s a pretty stupid flash app," –and you’re right!!  It’s very small and insignificant however it involves a huge frigging workaround since AS3 doesn’t have a clone function for MovieClips.

Warning: If you don’t code AS3 this is going to get really boring really fast.

Okay so all I wanted was "newMovieClip = SomeRandomMovieClip.clone();"  I wanted to clone the frames, the timing, the current x/y location, rotation, scale, etc, etc.  I just wanted it to work but "clone" doesn’t exist.  It’s what you might call a huge frigging oversight in the language’s framework.

So I look up on google and found lots and lots of people are all having this same problem.  What’s worse is each time someone asked the question "there’s no MovieClip.clone()? what should I do?" they are met with answers that don’t help at all.  Like the following:

Answer #1: "duh!  just use the new operator!  don’t waste our time on this forum you noob!"

What they are trying to say is, if you want to make many copies of a movie clip, then set it’s linkage properties via the flash editor and then you can do stuff like:  "newMovieClip = new SmilingSquare()"

This answer just shows the person missed the reasoning behind wanting a clone function to begin with.  For example, if I have a movieclip that I’ve created and exposed to as3 via the linkage props call "SmilingSquare" and I have a second movieclip called "FrowningSquare".  How would I do this?

var mcSomeUnknownClip:MovieClip = (Math.random() > .5) ? (new SmilingSquare()) : (new FrowningSquare());
var mcNewRandom:MovieClip = mcSomeUnknownClip.clone();

Basically, if you have a list of 100 unknown movieclips and for some reason or another, you need to clone one (because you want it’s visual contents, current position, scale, rotation) you can’t.  So the "new" operator doesn’t magically solve the issue because the issue comes into play when we start trying to make use of sub classes and OO Design.

so answer 1 is pretty much not helpful.

Example Source:

Answer #2: "use a loader"

So this is a workaround that ultimately gives the same results as answer 1.  Basically, you take the asset out of your fla and put it into it’s own swf.  then you can load that swf with the asset in it as many times as you want.

Again, this is not really the answer to the clone question.  You pretty much get the same result as using "new", which is a new instance of the movie clip that doesn’t have any of the current properties of the object you’re trying to clone.

So answer 2 is the same problem as answer 1, plus you have to put each of your assets in a separate swf (which sounds pretty time consuming)

Example Source (same thread as Answer #1)

Answer #3: "try this tricky ByteArray function that doesn’t work"

//this didn't work for me ~Danny
private function clone(obj:*):* {
//registerClassAlias('mySprite', getDefinitionByName(getQualifiedClassName(obj)) as Class);
  var ba:ByteArray = new ByteArray();
  ba.writeObject(obj);
  ba.position = 0;
  return ba.readObject();
}

I had high hopes for this one.  It’s basically doing a memcopy.  That line that’s commented out was introduced by someone later on the thread who said it would let ba.readObject() return the correct class.  But with or without that line, it just doesn’t seem to work for me (run time conversion errors, etc)

Source:

Answer #4: "create your own clone interface!"

basically, you’ll see a bunch of answers that involve creating and implementing interface functions.  Which is fine and all, I love Object Oriented code too, but the key element to unraveling this issue is in the next answer.  So read answer 5, *then* see if you want to make your own clone interface or just get on with your day.

Example Source (same as Answer #1):

Answer #5: "here’s how you instance the correct class. after that, manually copy everything you can."

Note: in this following code, I’ve replace the original author’s use of the word "target" with "source".

/**
 * duplicateDisplayObject
 * creates a duplicate of the DisplayObject passed.
 * similar to duplicateMovieClip in AVM1
 * @param source the display object to duplicate
 * @param autoAdd if true, adds the duplicate to the display list
 * in which source was located
 * @return a duplicate instance of source
 */
public function duplicateDisplayObject(
                                source:DisplayObject,
                                autoAdd:Boolean = false
                                ):DisplayObject
{
    // create duplicate
    var sourceClass:Class = Object(source).constructor;
    var duplicate:DisplayObject = new sourceClass();
  
    // duplicate properties
    duplicate.transform = source.transform;
    duplicate.filters = source.filters;
    duplicate.cacheAsBitmap = source.cacheAsBitmap;
    duplicate.opaqueBackground = source.opaqueBackground;
    if (source.scale9Grid) {
        var rect:Rectangle = source.scale9Grid;
        // WAS Flash 9 bug where returned scale9Grid is 20x larger than assigned
        // rect.x /= 20, rect.y /= 20, rect.width /= 20, rect.height /= 20;
        duplicate.scale9Grid = rect;
    }
 
    // add to source parent's display list
    // if autoAdd was provided as true
    if (autoAdd && source.parent) {
        source.parent.addChild(duplicate);
    }
    return duplicate;
}       
 

So that first line is key.  Once you know which class you want to create, you can actually use the new operator to create a new instance of that class.  However, after that, we’re just manually copying everything we can (so if there is private data we don’t know about, we can’t clone it).

In the end I went with this, only I used "source:MovieClip" instead of "source:DisplayObject". 

The trade off was, you can’t duplicate anything you draw using MovieClip.graphics.  So I had to make sure all my assets were 100% drawn in flash rather than in as3 via graphics.drawRect or something.

Example Source:

 

In Summary

I hope you can read/skim this and get all this info in 10 minutes instead of having to spend an hour or two reading online and trying solutions that don’t work. 

Remember, the big things to take away from this are:

  • var sourceClass:Class = Object(source).constructor;
  • you can’t copy/clone anything you make with MovieClip.graphics (see more info on that below).

Good Luck,
~Danny

PS: my browser crashed on me, so I lost most of the history that let me to the solutions/code posted above… I’m going to go back and try to track down the sources.  My apologies if I don’t link back to you.

Bonus Sources! Making a Proxy to catch all the graphics commands and play them back when you do the clone:

(I didn’t implement this graphics proxy because I spent all day on this cloning tangent and I just want to get back to what I was originally trying to do before MovieClip.clone() failed me)

 

January 25th, 2009 | Tags: , , , | Category: Lessons Learned |

4 Comments

  1. [...] you change the size, rotation, layer depth, etc.  It was a little tricky –remember that big long post I made about having to work around AS3 not having a MovieClip.clone() function?  Either way, I think [...]

    Pingback by Toon Portrait Maker v0.1 | DannyBurbol.com — January 25, 2009 @ 11:50 pm

  2. [...] any rate, the solution comes from Danny Burbol’s blog, which apparently came from a Experts Exchange thread (damn people charging for information). I [...]

    Pingback by Ben Snider » Blog Archive » Copying a Flash MovieClip, or The Flash Holy Grail — May 15, 2009 @ 11:42 pm

  3. [...] after reading this blog I found out [...]

    Pingback by CuriousFind » Blog Archive » Ultimate Reset of a Loaded AS3 MovieClip — January 27, 2010 @ 5:16 am

  4. [...] after reading this blog I found out [...]

    Pingback by Ultimate Reset of a Loaded AS3 MovieClip « The Joe Lake Blog – joeylakey.com — January 14, 2011 @ 5:25 am

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.