2
votes

I am writing a program in AS3 and want to preload movie clips that will be needed in the future. Unfortunately, I'm running into a problem: the movie clips play their sound as soon as they are loaded (before I add them to the stage).

Stopping the movie clip as soon as it is loaded almost solves the problem, but sometimes I still hear the start of the clip. Apparently the clip doesn't wait for completed event handlers to finish before starting...?

// example of stopping a clip after it is loaded
// sound may still be heard for a moment
var loader: Loader = new Loader();
loader.addEventListener(Event.COMPLETE, function(e : *) : void {
    (loader.contentLoaderInfo.content as MovieClip).stop();
});
loader.load("a_loud_movie_clip.swf");

I've also considered muting everything while loading clips, but this places a pretty serious constraint on the rest of the program with respect to when sounds can be played.

Is there a standard solution to this problem? I feel like it should be a very common issue.

1

1 Answers

3
votes

Are you preloading because your SWF is located on a web server? If so, one option would be to preload the bytes from the server without actually interpreting them by using a URLLoader. Then later, when you need to display the MovieClip, inject the preloaded bytes (URLLoader.data) into a Loader using Loader.loadBytes to actually instantiate the MovieClip (and start playing, sound and all). There may be a small lag at instantiation-time, but it'll be much less than without a preloader.

Per your question about the type of the loader.content:

package
{
  import flash.display.Sprite;
  import flash.display.Loader;
  import flash.display.Bitmap;
  import flash.display.MovieClip;
  import flash.events.Event;
  import flash.utils.ByteArray;
  import flash.utils.getQualifiedClassName;

  public class tst extends Sprite
  {
    [Embed(source="any_image.png", mimeType="application/octet-stream")]
      private var img_bytes:Class;

    [Embed(source="any_swf.swf", mimeType="application/octet-stream")]
      private var swf_bytes:Class;


    public function tst():void
    {
      var b1:ByteArray = new img_bytes();
      var l1:Loader = new Loader();
      l1.contentLoaderInfo.addEventListener(Event.COMPLETE, function():void {
        trace(getQualifiedClassName(l1.content));
        trace(l1.content is Bitmap);
      });
      l1.loadBytes(b1);

      var b2:ByteArray = new swf_bytes();
      var l2:Loader = new Loader();
      l2.contentLoaderInfo.addEventListener(Event.COMPLETE, function():void {
        trace(getQualifiedClassName(l2.content));
        trace(l2.content is MovieClip);
      });
      l2.loadBytes(b2);

    }
  }
}

(NOTE: this is merely demonstrative code - DO NOT add event listeners with a function closure like this, it will cause memory leaks. I'm also skipping the URLLoader and simply embedding to get my bytes, but they're the same bytes either way).

And the output is:

flash.display::Bitmap
true
test_fla::MainTimeline
true

However, Bitmap and MovieClip aren't the only options for loader.content - loading a SWF compiled from code can be derived from Sprite and may show the fully qualified class name, though as www0z0k points out, they're all derived from DisplayObject. Though I believe any SWF output from Flash Professional is always derived from MovieClip.

Per your note that Loader bytes are always MovieClips

It turns out you're right - a Loader that loads a regular old image, the contentLoaderInfo.bytes property contains the bytes for a generated SWF that is a simple MovieClip wrapper with the image as a Child. Who would have guessed?!

  var l3:Loader = new Loader();
  l3.contentLoaderInfo.addEventListener(Event.COMPLETE, function():void {
    trace("- l3:");
    trace(getQualifiedClassName(l3.content));
    trace(l3.content is Bitmap);

    // This ByteArray is a SWF!
    var b3:ByteArray = l3.contentLoaderInfo.bytes;

    var l4:Loader = new Loader();
    l4.contentLoaderInfo.addEventListener(Event.COMPLETE, function():void {
      trace("- l4:");
      trace(getQualifiedClassName(l4.content));
      trace(l4.content is Bitmap);
      trace(Object(l4.content).getChildAt(0) is Bitmap);
    });
    l4.loadBytes(b3);
    addChild(l4);

  });
  l3.load(new URLRequest("any_image.png"));

Output is:

- l3:
flash.display::Bitmap
true
- l4:
flash.display::MovieClip
false
true