duplicateMovieClip() is back to as3



5 Comments

Share







I noticed that lots of people (as3-developers) ask on forums/blogs
How do i create a copy of a MovieClip after loading it?.
And they usually get an answer like
In as3 you can only instanciate, no copy method available

So, to demolish those myths, i’ve decided to create a small util class for duplicating Loaders through binary raw data.


Download source files

Here’s a sample usage code:


import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.events.Event;
import com.chargedweb.utils.LoaderUtil;

var myLoader:Loader = new Loader();
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, dataLoaded);
myLoader.load(new URLRequest("http://www.google.com/intl/en_ALL/images/logo.gif"));
addChild(myLoader);

function dataLoaded(event:Event):void
{
     var copyLoader:Loader = LoaderUtil.copy(event.target as LoaderInfo);
     copyLoader.y = 200;
     addChild(copyLoader);
}

And here’s the class source in case you don want to download the as.


////////////////////////////////////////////////////////////////////////////////
//
//  Copyright 2009 Julius Loa | jloa@chargedweb.com
//  All Rights Reserved.
//  license: GNU {http://www.opensource.org/licenses/gpl-2.0.php}
//  notice: just keep the header plz
//
////////////////////////////////////////////////////////////////////////////////

package com.chargedweb.utils
{
	import flash.utils.ByteArray;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.events.Event;
	import flash.events.EventDispatcher;

	/**
	 * LoaderUtil class [static]
	 */
	public class LoaderUtil
	{
		/** dispatcher */
		private static var _DISPATCHER:EventDispatcher = new EventDispatcher();

		/**
		 * Creates an exact copy of a Loader; copies the entire Loader object's content
		 * (no matter graphics/swf animation).
		 *
		 * @param	source:LoaderInfo	the source LoaderInfo of the target Loader to be copied.
		 * @return	Loader			the exact copy of the source loader
		 *
		 * @example
		 * <pre>
		 * import flash.display.Loader;
		 * import flash.display.LoaderInfo;
		 * import flash.events.Event;
		 * import com.chargedweb.utils.LoaderUtil;
		 *
		 * var myLoader:Loader = new Loader();
		 * myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, dataLoaded);
		 * myLoader.load(new URLRequest("http://www.google.com/intl/en_ALL/images/logo.gif"));
		 * addChild(myLoader);
		 *
		 * function dataLoaded(event:Event):void
		 * {
		 * var copyLoader:Loader = LoaderUtil.copy(event.target as LoaderInfo);
		 * copyLoader.y = 200;
		 * addChild(copyLoader);
		 * }
		 * </pre>
		 */
		public static function copy(source:LoaderInfo):Loader
		{
			var sourceBytes:ByteArray = source.bytes;

			if(sourceBytes.bytesAvailable == 0)
			{
				throw new Error("LoaderUtil.copy("+source+") doesn't appear to have any bytes available");
				return null;
			}

			var copyLoader:Loader = new Loader();
			copyLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, LoaderUtil.onContentLoaded);
			copyLoader.loadBytes(sourceBytes);
			return copyLoader;
		}

		/**
		 * @see flash.event.EventDispatcher
		 */
		public static function addEventListener(type:String,
												listener:Function,
												useCapture:Boolean = false,
												priority:int = 0,
												useWeakReference:Boolean = false):void
		{
			_DISPATCHER.addEventListener(type, listener, useCapture, priority, useWeakReference);
		}

		/**
		 * @see flash.event.EventDispatcher
		 */
		public static function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
		{
			_DISPATCHER.removeEventListener(type, listener, useCapture);
		}

		/**
		 * @see flash.event.EventDispatcher
		 */
		public static function hasEventListener(type:String):Boolean
		{
			return _DISPATCHER.hasEventListener(type);
		}

		/**
		 * @private Content loaded handler (loading bytes takes time)
		 * @param	event:Event
		 */
		private static function onContentLoaded(event:Event):void
		{
			_DISPATCHER.dispatchEvent(event.clone());
		}
	}
}

5 Comments (+add yours?)

  1. Mamzelle
    Apr 06, 2010 @ 08:25:15

    Hi,

    Nice idea for your class.

    Is it not be more efficient to create a BitmapData than to create a second loader. The BitmapData will surely take less memory than a Loader object.

    Did you try ?

  2. Mamzelle
    Apr 06, 2010 @ 08:46:18

    It could be useful in some case(when you can’t use bitmapData and you have no choose)

    I used the same solution when I had problem to copy my 3d model with the native method in Papervision 3D.

  3. jloa
    Apr 06, 2010 @ 15:27:06

    Yes, but my solution wan’t random.
    Why? How would you make copy of a loaded swf animation using the BitmapData? :-)
    And as far as i know the api, there’s no other method, but using the ByteArray.

  4. Brett Levine
    Jul 14, 2010 @ 15:09:41

    If you want to avoid security exceptions you should use a SWFLoader and set the loader context as follows:
    var myLoaderContext:LoaderContext = new LoaderContext();
    myLoaderContext.allowLoadBytesCodeExecution = true;

    copyLoader = new SWFLoader();
    copyLoader.loaderContext = myLoaderContext;

  5. jloa
    Jul 14, 2010 @ 15:40:55

    I forgot to tell that the loadBytes method is a bit risky and insecured using.
    Really nice tip though.

Leave a Reply

Spam protection by WP Captcha-Free