goombas.org
menu
main
links
all items
rss feed

Topics:
coding
games
goombas.org
horror
judgement
life
minutiae
music
rants
software
fool.
 _-
 oO
 |/
/|
/ \
Ugh, stop twitching
how to embed SWF animations into your flex project
coding Posted 2011-09-12 21:01:17 by Jim Crawford
First, try embedding it like you would any other resource:
[Embed(source = "art/mosquito.swf"] private static const Mosquito:Class;
public static const mosquito:MovieClip = new Mosquito();
Then, try rendering it.
private function onFrame(e:Event):void
{
  screen.bitmapData.draw(Assets.mosquito);
}
It works! Bless the Flex API for being so straightforward and continue with your life, until you try calling one of the transport controls.
Assets.mosquito.gotoAndStop(0);
It will have no effect. Neither will any of the other transport methods. Be confused by this, then look at the object and realize that it has 0 frames. Consider that it may be a wrapper object, but note that it only has one child, which is a DisplayObject and doesn't have any transport controls. Just to make sure, try casting the child to a MovieClip and get a type coercion error.

Decide to do some research. Start spewing queries like “embed swf flex totalframes 0” at DuckDuckGo, eventually discovering that SWFs embedded in this fashion aren't interactable, and that you need to embed them as bytes and use the Loader class. Some people will say that you should use SWFLoader, but for some reason your copy of Flex doesn't come with the mx.* namespace, or maybe you just don't know how to import it, and either case, don't feel like barking up that particular tree right now.

Loader will turn out to work asynchronously. Presume that it was originally intended for loading data from URLs. Sigh and get to work turning it into a synchronous function, because fuck multithreading. Your first attempt should go something like this:

[Embed(source = "art/mosquito.swf", mimeType="application/octet-stream")]
private static const Mosquito:Class;
public  static const mosquito:MovieClip = load(Mosquito);
 
private static var temp:MovieClip = null;
private function load(asset:Class):MovieClip
{
  var loader:Loader = new Loader();
  temp = null;
  loader.contentLoaderInfo.addEventListener(Event.COMPLETE, done);
  loader.loadBytes(new asset);
  while(!temp);
  return temp;
}
 
private function done(e:Event):void
{
  temp = MovieClip(loader.content);
}
The compiler will scream at you about the while(!temp);. Assure it that you know what you're doing and run the code. Discover that no matter how long you wait, the callback never executes. Fuckin' threads, how do they work? Warn your artist that she may have to export her work to pngs after all, and go to bed.

The next day, realize that Flash might not actually do preemptive multithreading, in which case Loader would never get reached because of your busy loop. Grimace, realizing that in order to support multiple assets -- which you do have, despite the example code in this post -- you'll probably have to keep an actual data structure in memory per load. Actionscript doesn't have references, but consider storing all your assets in an array, maybe, and somehow passing an index to the callback so it knows where to put the data? Yeah, that might work.

Determine that there seems to be no mechanism for passing arbitrary data to the callback, barring storing the information in the class instance that the callback is a method of. Resign yourself to instantiating a class per load. Given that requirement, note that the most natural thing is to store the resulting data in the class as well, and that writing a container class to load and store each MovieClip is a cleaner solution than keeping track of array indices per asset. Write the class, which will end up looking like this:

public class ClipContainer
{
  private var m_loader:Loader    = new Loader();
  public  var m_clip  :MovieClip = null;
   
  public function ClipContainer(asset:Class) 
  {
    m_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, done);
    m_loader.loadBytes(new asset);
  }
 
  private function done(e:Event):void
  {
    m_clip = MovieClip(m_loader.content);
  }
}
Instantiate it like this:
[Embed(source = "art/mosquito.swf", mimeType="application/octet-stream")]
private static const Mosquito:Class;
public  static const mosquito:ClipContainer = new ClipContainer(Mosquito);
And render it like this:
private function onFrame(e:Event):void
{
  Assets.mosquito.m_clip.gotoAndStop(0);
  screen.bitmapData.draw(Assets.mosquito.m_clip);
}
This will throw up a null reference error. Click “dismiss,” and afterward the code will totally work. Since the error only happens once, figure that it must be doing the actual loading work on a per-frame event. Throw in some code to wait for everything to load:
public class ClipContainer
{
  private var m_loader:Loader    = new Loader();
  public  var m_clip  :MovieClip = null;
  
  public static var m_loading_count:int = 0;
  
  public function ClipContainer(asset:Class) 
  {
    m_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, done);
    m_loader.loadBytes(new asset);
    m_loading_count++;
  }
  
  private function done(e:Event):void
  {
    m_clip = MovieClip(m_loader.content);
    m_loading_count--;
  }
}
Then, per frame:
private function onFrame(e:Event):void
{
  if(ClipContainer.m_loading_count > 0) return;  
  Assets.mosquito.m_clip.gotoAndStop(0);
  screen.bitmapData.draw(Assets.mosquito.m_clip);
}
Run the code and discover that it still throws up the error once! Look at the value of ClipContainer.m_loading_count and see that it's 0, and put a breakpoint in the ClipContainer constructor to discover that it's only being called after the check in onFrame.

Decide that modules must only be loaded lazily, so you'll need to poke the Assets module to wake it up, then wait a frame before you can actually use anything in it. Throw a no-op Assets.mosquito; into an initialization function, and hope Flex doesn't optimize it out. Run the code and see that it works!

Shortly after writing this post, discover that you can ask the artist to export SWC files instead, which are much easier to embed.

And that's how you embed SWF animations into your Flex project!

[link to this] [See more on “coding”]

comments
Can assets be loaded dynamically?
Posted by Anonymous (Steve Ricketts) on 2013-08-26 07:27:34
I'd like to do something similar on a mobile device but will need to load the .swf's dynamically as they will constantly change. Can this be done?
no subject
Posted by Anonymous (Jim) on 2013-08-27 16:20:13
Yes, ContentLoader can also load from a URLRequest object. There might be filesystem support on AIR but I haven't looked into it.
add a comment
Only anonymous comments are available for now until I get the user system up and running again. Not many people were logging in anyway, so enh.
Permitted HTML tags: <b>, <i>, <u>, <tt>. Also permitted is the <q> pseudo-tag which is meant to delimit quotes from other messages.
name:
email:
subject:
body:
Preview
To prove you are sentient, please type "sentient" into this box

what's this?
This is Jim Crawford's blog. Details and contact information.

On Twitter: @mogwai_poet

recent comments
Rajasthan Tourism (Anonymous on may 2014 microblog digest)
phd thesis writing services (Anonymous on may 2014 microblog digest)
no subject (Anonymous on boxing: a history)
panchang (Anonymous on may 2014 microblog digest)
Packers and movers in Gurgaon (Anonymous on may 2014 microblog digest)
QuickBooks 24/7 Support Phone Number (Anonymous on may 2013 microblog digest)
no subject (Anonymous on may 2013 microblog digest)
no subject (Anonymous on boxing: a history)
QuickBooks Technical Support Phone Number @1844-640-1482
(Anonymous on may 2013 microblog digest)
phone number for quickbooks support (Anonymous on may 2013 microblog digest)
no subject (Anonymous on boxing: a history)
Accountancy (Anonymous on may 2013 microblog digest)
QuickBooks Technician (Anonymous on may 2013 microblog digest)
no subject (Anonymous on boxing: a history)
quickbooks support (Anonymous on may 2013 microblog digest)
Comments RSS