Friday, January 13, 2012

AS2 Farming out compile work to a swf

Thanks to Crystal's vivid imagination, the CLIPS team has created a Hops on Lines Tool that consists of 27 .as files averaging 25K or so.  When compiled, the .swf is about 700K.  When an activity uses the Hops Tool as well as other classes, the compile can be very slow or can max out available memory and fail.  We decided to farm out the job of compiling to another .swf and load it into any activities that require it.

Unfortunately, this means that the activity.swf cannot be run standalone.  Users will either have to be online, so that the Hops .swf can be found at mathclips.ca, or they will have to save the Hops .swf to a predictable location on their hard drive.



Originally, an instance of the Hops tool was created using a call to a static create method as described in a previous post.

     HopsOnLines.create(target, "instanceName", initObj);

To farm out this work and keep all the current code backwards compatible, we rename HopsOnLines to be OriginalHopsOnLines and make the new HopsOnLines.as contain:

class HopsOnLines extends MovieClip {

 public static function init(myCreatorReference:MovieClip){
  _root.theToolCreator = myCreatorReference;
 }

 public static function create(container:MovieClip, instanceName:String, initObj:Object, depth) {
  return _root.theToolCreator.create(container, instanceName, initObj, depth);
 }
}

In order to use this new version of the class, an initialization step must be performed to tell the class where the movieclip containing the compiled swf is.
The .fla used to create the .swf contains:

System.security.allowDomain("*");
import HopsOnLinesOld;
stop();

function create(target:MovieClip, toolName:String, initObject:Object, depth:Number){
 return HopsOnLinesOld.create(target, toolName, initObject, depth);
}

In this way, the .fla compiles the HopsOnLinesOld, with all its imported classes and exposes a create method that simply shuttles the job to the legacy creator.  This is one of the few times when the .fla is many times smaller than the compiled .swf.

In order to use this compiled swf. An activity must load it into a movieclip. When it is completed, call init to tell it where that movieclip is, and then any HopsOnLines.create statements will work without any modifications. Here is some sample code from an activity .fla:

import HopsOnLines.as;
System.security.allowDomain("*");

var testingLoader:MovieClipLoader = new MovieClipLoader();
var testingListener:Object = new Object();

testingListener._parent = this;
testingLoader.addListener(testingListener);

this.createEmptyMovieClip("testingContainer", this.getNextHighestDepth());
this.createEmptyMovieClip("testingLooper", this.getNextHighestDepth());

testingLoader.loadClip("http://www.myDomain.ca/HopsOnLinesCreator.swf", this.testingContainer);

testingListener.onLoadInit = function(which){
 trace("onLoadInit with "+which);
 this._parent.testingContainer.init(this._parent.testingContainer);
 this._parent.testingContainer.create(this._parent, "myHops_mc", {_x:50, _y:50});
 if (this._parent.myHops_mc == undefined){
  trace("onLoadInit has an error not picked up by onLoadError");
 }
}

There are a couple of things that I still wonder about. I get incompatible context errors related to security and sometimes they seem to make it not work. Also, if the file does not exist, onLoadInit seems to be called rather that onLoadError.  Also, I seemed to have the make the reference in the new .as file to _root - I had tried a static property and a _global but that did not work as well, I am not sure why.

No comments: