Controlling AS2 swfs within an AS3 application.

Sometimes you’ll need to load an AS2 swf into your AS3 project, and this seems like it can be a nightmare. And it can be, depending on what it is. You loose some functionality, such as loadMovieNum and getURL. On top of that, you can’t control the movie, as in you can’t access any public functions. There can be a workaround, though. The trick is to write an AS2 shell that acts like a bridge. You’ll load the AS2 swf into that shell, and communicate with the swf from that file, then communicate to the AS2 swf  bridge from your AS3 project via localConnection. This comes from a problem I recently was required to tackle, so I fiugred I’d share my solutution.

In this example, we need to load an existing game written in AS2 into an AS3 website. We do not have any access to the source files, just the compiled swf, which needs to be properly disposed in order to stop its audio channel. The solution is to create an AS2 shell that can load and unload the game, and then communicate with the shell via localConnection.

Step 1. Setting up the AS2 shell

Make a new AS2 targeted flash file and on the stage create a new empty MovieClip and give it an instance name, in this case container_mc.

Now as much as this hurts, click on the first frame and open the ActionScript panel. Yes, we’re going to add some very simple code to the timeline. First we want to load the game using loadMovie, targeting the container_mc that we created on the stage. This will load our file into this empty MovieClip so we can easily remove it later. Since we’ll be bringing this into and AS3 swf, we cannot use loadMoiveNum. The one line of code should look like this: loadMovie(“game_as2.swf”,this.container_mc) .

Step 2. Setting up the LocalConnection listener

This file is basically going to wait for a command from a localConnection at some point, so we’ll set that up immediately after loading the movie. In this case, we named the connection ‘gameBridge’ and will need to use that string in out AS3 swf in order to sync the two together. The code looks like this:
var lc:LocalConnection = new LocalConnection();
lc.connect(“gameBridge”);

Now we need to set up a method that will be called from AS3. In this case, it’s a dispose method. In order for the method to be called, it needs to be a method of the localConnection, so the full function name is lc.dispose = function():Void. Remember that lc is our localConnection object, and that in AS2 the datatype for void is capitalized. All we want to do in this function is kill the game, so we’re going to unload it and kill the connection. Just two lines of code, which looks like this:
lc.dispose = function():Void {
unloadMovie(container_mc);
lc.close();
}

That’s it for the AS2 side.

Step 3. Setting up the load in the AS3 project

We load in the AS2 swf just like we do an AS3 one, the only difference is that instead of it being of type MovieClip, it will be a special class called AVM1Movie, which stands for ActionScript Virtual Machine 1 MovieClip. Remember, we’re loading our shell we just made, not the game. So my load method looks like this:

private var game:AVM1Movie;
private var loader:Loader;

private function loadGame():void {
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, hndlGameLoad);
loader.load(new URLRequest(“gameshell.swf”));
}

private function hndlGameLoad(e:Event):void {
game = AVM1Movie(loader.contentLoaderInfo.content);
addChild(game);
}

In this case, the game was set to a frame rate of 30fps, and my app is running at 71fps. That means that the loaded game will now run over twice as fast. There’s not much we can do about this, but we can set the overall stage frame rate to match the loaded game, and when the game is unloaded, just remember to set it back. It’s just one line of code: stage.frameRate = 30;

Step 4. Setting up the LocalConnection call method

The last thing to do is call the AS2 swf and tell it to dispose when we need it to. We just set up a new LocalConnection object and pass it the name of the connection we set up in the AS2 swf and the method that we want to call. Looks like this:

lc = new LocalConnection();
lc.send(“gameBridge”, “dispose”);

And that’s about it. Pretty simple and quick way to load and still be able to dispose of an AS2 file.

7 thoughts on “Controlling AS2 swfs within an AS3 application.”

  1. Hi, great solution ! Helps me a lot !

    I have problems with the addChild(game) part, when I try this, flashPlayer tells me that I can’t convert an AVM1Movie object into an UIComponent one (TypeError: Error #1034). Is there a workaround ? Why can’t I do a addChild() with an AVM1Movie ? If this doesn’t work, I can’t go further…

    Thanks.

    1. Are you doing this as a Flex project? I have no experience with Flex, so I can’t help you there, but it looks like the AddChild method in Flex (as opposed to addChild in AS3, note the case-sensitive difference) accepts a UIComponent as a parameter instead of a DisplayObject. The AVM1Movie is extended directly from the DisplayObject class, however the UIComponent is an extension of Sprite. So that would explain the type mismatch error. That’s the only thing I can think of – if that’s the case, I guess you would need to create a new UIComponent and add the AVM1Movie to that instance, and then add it to whatever you are trying to.

  2. Sorry, yes I’m building a Flex 3 project.

    So it makes sense. Well I think I just have to load the bridge simply into a SWFLoader, and go on with the LocalConnection trick… It would be more “Flex”-compliant, and the same SWFLoader can be used to load AS3 files too.

    I’ll try that. Thanks a lot !

  3. Hi irimi,
    This is how I did it.

    01. Create a loader component and load the AVM1 movie to loader first.

    02. in the complete handler of teh loader component create a new UIComponent and add the like,

    tempUIC = new UIComponent(); tempUIC.addChild(loader.content.parent);

    and add teh UIComponent where you want to add the AVM1Movie

  4. Hi, thanks Nish, it… almost works !

    In fact, I’m building an app that can load slides, as the user clicks on list items. The slides can be any kind of SWF (AS1/2/3).

    In my flex layout, I put an UIComponent tag (instead of intstantiate it in the code). Your technique works well, I can load successively a series of SWFs, and if I load an AVM1Movie, I use the same technique to load instead my “bridge” SWF and load the AS1/2 slide into it. But it works only the first time ! If I try to load another old SWF, the debug tells me my bridge loaded successfully, but nothing displays, and my LocalConnection.send() fails !

    Very strange, as the first time I load the bridge it works fine (successful send(), and I can see the slide)… And if I try to load an AS3 SWF it works well everytime.

    It’s quite hard to debug such an app, because of the LocalConnections. For example, I can’t use trace() in my bridge, I must use TextFields… But when there’s a problem, the TextField is not displayed :(

    note 1: every time I load a new slide, I empty the UIComponent with a loop of removeChildAt() calls.

    note 2: il my Loader y put an URLRequest with GET parameters (URLVariables object) : the URL of the slide and a random number to identify the LocalConnection. I thought that the random number would clear the cache too…

    Any ideas ?

Leave a Reply to Nish Cancel reply

Your email address will not be published. Required fields are marked *