Archive for July, 2009
Being a Successful Development Team in Flash with Application Domains
A somewhat common problem I’ve run into a few times was how to “play nice” with other developers when working on projects that were quite big - and required a team effort. I’ve stumbled across a pretty cool way to build projects. Maybe others are aware of this, but I wasn’t, so maybe this can help you.
What I’m not talking about, is how to write better code so there aren’t any merge problems - or how to get along better. What I’ll explain is how you can alleviate pains with managing FLA files, and which developer can work on which FLA.
Here’s the situation: you have a shell file that loads some shared assets but more than one developer are trying to work in this assets FLA at the same time. You know version control presents a problem so you try to coordinate when and who is allowed to work on the FLA. Does that sound familiar? If not, maybe you’re already doing it right - maybe I can learn something from you.
Let’s think about this problem a little bit more, this is how I broke it down: we need a way to write code linked against some assets - which happen to live in a swf. The swfs will be used for part of a bigger application, but “the bigger application” doesn’t care which swf contains the assets or components.
The answer: write code that makes no assumptions about which swf the assets live in. How can you do that? Application domains. (I don’t really want to take the time to explain application domains - you can look through the livedocs for that.)
I’ll start to paint a very simple picture. We’ll have two final swfs:
main.swf (from main.fla) assets.swf (from assets.swf)
We have two developers on the team:
David, Sam
To start the project out, one developer will need to write some basic startup code, to kick everything off in the main swf. That startup code could do many things, but to keep this simple, let’s assume it just contains some assets for a preloader and the code to kick off the application when the required assets are loaded.
Once you get to that point, you can start to break things up. Here’s what you do: each developer creates his own FLA sandbox for developing components - which will be a work in progress FLA.
So now you have three FLA’s:
assets.fla assets_david.fla assets_sam.fla
This is where application domains, (with or without the help of guttershark) comes in. While your initially building the app, you load all three asset swfs. The model xml file would look like this:
<?xml version="1.0" encoding="utf-8"?> <model> <assets> <asset libraryName="assets" src="assets.swf" preload="true" /> <asset libraryName="assetsDavid" src="assets_david.swf" preload="true" /> <asset libraryName="assetsSam" src="assets_sam.swf" preload="true" /> </assets> </model>
The PreloadController loads in all assets into the same application domain - which means your application code doesn’t need to do any extra work, or extra logic - just to get clips out of the libraries.
As developers are hitting milestones with building components, they can come back to the main application code and fit in their components. Naturally one developer will fall into being the maintainer of the overall application, or architect.
This is what you’ll start to see happen: the architect will be able to work on building the entire application, using the components from the other developers’ sandboxes, and whatever milestones are ready in the main assets swf - without disturbing the other developers, and the other developers won’t conflict with each other.
Can you see how that shapes up? All developers contribute to code, using version control systems to merge your application code together - which is standard. But, while each developer is doing his individual efforts, he builds out components and visual assets in his sandboxed FLA. The architect can use all those pieces, and nobody has to worry about conflicts. Yes!
Each developer will naturally hit milestones with the components he’s building. When this happens, he makes sure it’s clear to merge in his milestone into the final assets swf. Delete those clip assets from his sandbox, and continue.
The cycle is perfect. Now it’s all about individual milestone’s and quick merges vs. merge and conflict resolution at every commit or update because of crappy fla conflicts.
Obviously this is a very basic example, and I have by no means come up with some perfect team model. But I’ve successfully been doing this on one project I’m working on, and let me tell you - we haven’t had any major FLA conflicts, and we haven’t had to plan or even think about who, when, or where someone edits an FLA.
Do you have any experiences with team development? Do you have team techniques that eliminate conflicts with FLA’s? I’d definitely like to hear about them.
3 commentsThe Guttershark DocumentController
Continuing on from assets and the model, Let’s take a look at the DocumentController.
The DocumentController does quite a few things. I’ll show you three of them: loading model xml files, handling flashvars, and kicking off your app after everything is done.
The most important thing when writing flash websites, is that you pass in paths from flashvars. For example, passing in asset locations, xml locations, and of course, what the model xml file is.
Flashvars are great - they allow you to put path configuration in javascript, which gives you a hook right before the swf is embedded. That can be used for making decisions based off of the url it’s being embedded at. That can also lead to a problem - how do I handle flashvars when I’m publishing the FLA in the Flash IDE? Should I just publish, but then close the window and open the browser? Or should I put some hard coded information in the main class, for that situation?
This problem is fixed with the guttershark DocumentController. The method DocumentController.flashvarsForStandalone is called when you run the swf in the Flash IDE, or as a standalone swf.
For the first example, let’s assume you are setting it up to only run from HTML.
Here’s the HTML snippet:
<!-- ... -->
<div id="flash"></div>
<script>
var vars={
model:"assets/xml/model.xml"
}
var params = {scale:'noScale'}
var attributes = {id:'flaswf',name:'flaswf'}
swfobject.embedSWF("main.swf","flash","600","400","9.0.0",null,vars,params,attributes)
</script>
<!-- ... --> Simple right? The guttershark document controller looks for a flashvar called “model”, if found, the doc controller will load that xml, and give it to the Model.
Here’s the document controller:
package { import net.guttershark.control.DocumentController; public class TestPreloader extends DocumentController { override protected function setupComplete():void { trace( ml.xml ); } } }
The setupComplete method is a hook for you. It’s essentially your “constructor” for the application, it runs after all startup logic is done. And in our case, it’s only loading the model xml.
If you try this out, you’ll notice that when you’re in the Flash IDE, the trace will give you “null” - there’s that problem I mentioned. We need some way of giving the document controller “alternative” flashvars when running in standalone mode. Here’s how to integrate that:
package { import net.guttershark.control.DocumentController; public class TestPreloader extends DocumentController { override protected function flashvarsForStandalone():Object { return { model:"assets/xml/model.xml" } } override protected function setupComplete():void { trace( ml.xml ); } } }
The flashvarsForStandalone method is called as one of the first method calls in the doc controller startup process - and it only get’s called if the swf is indeed running as the standalone player. If the swf is embedded on an HTML page, this method is ignored.
So, with this in mind, let’s integrate our “path” logic from the previous post.
Here’s the updated HTML snippet:
<div id="flash"></div>
<script>
var vars={
model:"assets/xml/model.xml",
assets:"assets/",
bitmaps:"assets/bitmaps/",
}
var params = {scale:'noScale'}
var attributes = {id:'flaswf',name:'flaswf'}
swfobject.embedSWF("main.swf","flash","600","400","9.0.0",null,vars,params,attributes)
</script> Here’s the updated code:
package { import net.guttershark.control.DocumentController; public class TestPreloader extends DocumentController { override protected function flashvarsForStandalone():Object { return { model:"assets/xml/model.xml", assets:"assets/", bitmaps:"assets/bitmaps/" } } override protected function initPaths():void { //"ml" is already a protected property on doc controller. ml.addPath("bitmaps",flashvars.bitmaps); } override protected function setupComplete():void { trace( ml.xml ); } } }
The document controller has a property called “flashvars”. If the swf is in standalone, it will be set to the object you return from flashvarsForStandalone, or if the swf is embedded in HTML, it will be set to the flashvars that are embedded on the swf.
There’s one new method to point out - initPaths. This method is a hook that the doc controller gives you. It’s called early in the setup process (but after flashvars are ready). Because the initPaths is called after the flashvar logic, all you need to do is add paths to the Model from flashvars. So, in our case, the only path we need is “bitmaps”.
One other key piece of information - the flashvars from HTML and flashvarsForStandalone don’t need to define the exact same values. This is very important. What if when you’re developing in the FlashIDE, you need to change the paths to be relative, but when you deploy the site, the paths need to be absolute? This is exactly why you have an “alternative” way to define flashvars for standalone.
Now, let’s go ahead and integrate everything from the last two posts.
Here’s the model xml:
<?xml version="1.0" encoding="utf-8"?> <model> <assets> <group id="pictures"> <asset libraryName="myPicture" src="myPicture.jpg" path="bitmaps" preload="true" /> <asset libraryName="myOtherPicture" src="myOtherPicture.jpg" path="bitmaps" preload="true" /> </group> </assets> </model>
Make note of the new “preload” attribute above.
Here’s the HTML again:
<!-- ... -->
<div id="flash"></div>
<script>
var vars={
model:"assets/xml/model.xml",
assets:"assets/",
bitmaps:"assets/bitmaps/"
}
var params = {scale:'noScale'}
var attributes = {id:'flaswf',name:'flaswf'}
swfobject.embedSWF("main.swf","flash","600","400","9.0.0",null,vars,params,attributes)
</script>
<!-- ... -->And finally, here’s the entire document controller code:
package { /* .. */ public class TestPreloader extends DocumentController { public var progress:MovieClip; override protected function flashvarsForStandalone():Object { return { model:"assets/xml/model.xml", assets:"assets/" bitmaps:"assets/bitmaps/" } } override protected function initPaths():void { ml.addPath("bitmaps",flashvars.bitmaps); } override protected function setupComplete():void { trace( ml.xml ); preloadAssets(); } private function preloadAssets():void { pc = new PreloadController(300); pc.addEventListener(Event.COMPLETE,onPreloadComplete); pc.addEventListener(PreloadProgessEvent.PROGRESS,onProgress); /* new method - getAssetsForPreload() */ pc.addItems(ml.getAssetsForPreload()); pc.start(); } private function onPreloadComplete(e:Event):void { trace("preloading complete"); addChild( am.getBitmap("myPicture") ); } private function onProgress(ppe:PreloadProgessEvent):void { trace(ppe); progress.width=ppe.pixels; } } }
This is starting to shape up nicely.
There was one method added here, getAssetsForPreload(). This method returns an array of all Asset definitions from the model that contain the “preload=true” attribute.
Hopefully you can see how helpful this all is, and how guttershark makes it simple!
It’s also very important to note that there isn’t anything “hard-coded” anymore, with the exception of the initFlashvarsForStandalone - which is only for flash IDE development anyway.
And, sure, we still have the string “myPicture” hard coded. But, what you start to see is that you change everything around the asset “myPicture”. myPicture is now just an ID to some asset, and we can easily change everything else about the application, and as long as the paths from flashvars are pointing to the right location - it will all work.
Conclusion
It’s great! We went from having quite a bit of code with hard coded assets in it. To less code, that does everything for me.
You can also start to see how nothing in Guttershark is really bound to anything else. If you wanted to write a new document controller to replace guttersharks built in doc controller - you certainly could do that. All while being able to use the rest of guttershark - like the model, asset manager, preloaders, etc.
Where do you go from here? I would strongly suggest reading the source code for the DocumentController, Model, PreloadController, and AssetManager, CoreClip, and CoreSprite. Those are the most important pieces of Guttershark. Everything else is gravy on top.
11 commentsAssets and the Model Class
Continuing on from Preloading and Asset Management. Let’s look at how the model can help with asset definitions, and removing hard coded assets.
The Model class in Guttershark is one of a couple “brains” in the library. It can do lots of stuff for you, but today, we’ll just focus on assets and paths. I’m going to continue using the example from Preloading and Asset Management - just adding and removing some code.
Before we get too far into this, make note of the PreloadController.addItems method. Notice that it takes an array of items (Asset instances).
Now take a look at these methods on the Model class. (getAssetByLibraryName, getAssetsByLibraryNames, getAssetGroup).
The Model class works with an XML object - which must be structured a certain way, then the model can do all this work for you.
To start getting this all setup, let’s first look at the most basic XML file, which defines some assets. This xml will show you how to use two of the model methods.
<?xml version="1.0" encoding="utf-8"?> <model> <assets> <!-- for the model method, getAssetsByLibraryNames --> <asset libraryName="myPicture" src="assets/myPicture.jpg" /> <asset libraryName="myOtherPicture" src="assets/myOtherPicture.jpg" /> <!-- for the model method, getAssetGroup --> <group id="pictures"> <asset libraryName="myPicture" src="assets/myPicture.jpg" /> <asset libraryName="myOtherPicture" src="assets/myOtherPicture.jpg" /> </group> </assets> </model>
Ok, so with that in mind - here’s our first example of using this:
package { import flash.events.Event; import flash.net.URLRequest; import flash.display.MovieClip; import flash.display.Sprite; import net.guttershark.control.PreloadController; import net.guttershark.support.preloading.Asset; import net.guttershark.support.preloading.events.PreloadProgressEvent; import net.guttershark.util.XMLLoader; import net.guttershark.model.Model; public class TestPreloader extends Sprite { private var ml:Model; private var am:AssetManager; private var pc:PreloadController; private var assets:Array; private var xmlLoader:XMLLoader; public var progress:MovieClip; public function TestPreloader() { am = AssetManager.gi(); loadModelXML(); } private function loadModelXML():void { xmlLoader=new XMLLoader(); xmlLoader.contentLoader.addEventListener(Event.COMPLETE,onModelLoaded); xmlLoader.load(new URLRequest("model.xml")); } private function onModelLoaded(e:*):void { ml=Model.gi(); ml.xml=new XML(xmlLoader.data); preloadAssets(); } private function preloadAssets():void { pc = new PreloadController(300); //remember.. 300 = the pixelsToFill. pc.addEventListener(Event.COMPLETE,onPreloadComplete); //when preloading all items complete. pc.addEventListener(PreloadProgessEvent.PROGRESS,onProgress); //progress for all items as a whole. /* first way to get assets, using getAssetsByLibraryNames */ assets = ml.getAssetsByLibraryNames("myPicture","myOtherPicture"); /* second way, using groups */ assets = ml.getAssetGroup("pictures"); pc.addItems(assets); pc.start(); } private function onPreloadComplete(e:Event):void { trace("preloading complete"); addChild( am.getBitmap("myPicture") ); } private function onProgress(ppe:PreloadProgessEvent):void { trace(ppe); progress.width=ppe.pixels; } } }
It’s simple right? But wait, there’s more!
The model xml has some room for improvement - getting rid of the asset paths. For example, in the model xml, each asset defines the “src” attribute to equal something like: “assets/XXX”. It would be nice to not have to define that all the time. So how can we change it?
The Model and Paths
The Model class has two methods for working with paths. addPath and getPath.
Before we integrate these methods into the code, here’s a sand-boxed code example of how the path methods work:
var ml=Model.gi(); //the preferred way: ml.addPath("root","http://example.com/"); ml.addPath("assets", ml.getPath("root")+"assets/") ); ml.adddPath("xml", ml.getPath("assets")+"xml/") ); trace( ml.getPath("xml") ); // http://example.com/assets/xml/ //but, you can also define just the pieces of a path, and use ...rest parameters with the getPath method. ml.addPath("root","http://example.com/"); ml.addPath("assets","assets/"); ml.addPath("xml","xml/"); trace( ml.getPath("root","assets","xml") ); //http://example.com/asset/xml/
By convention, you should always add trailing slashes at the end of a path. This makes sure you never have to write parse code to remove double slashes (//), or testing to see if the index of a slash is the last character, etc.
That’s pretty easy right? We can integrate that into the model xml, and code.
Here’s the new model xml, note that I’m only going to use one style for grabbing assets - the group ids.
<?xml version="1.0" encoding="utf-8"?> <model> <assets> <group id="pictures"> <asset libraryName="myPicture" src="myPicture.jpg" path="bitmaps" /> <asset libraryName="myOtherPicture" src="myOtherPicture.jpg" path="bitmaps" /> </group> </assets> </model>
Notice the new attribute, “path”. All of the methods on the Model class that help with getting you assets, will look for this path attribute, and then look in the model for path definitions that match that, and prepend it onto the src attribute.
Here’s our updated example:
package { import flash.events.Event; import flash.net.URLRequest; import flash.display.MovieClip; import flash.display.Sprite; import net.guttershark.control.PreloadController; import net.guttershark.support.preloading.Asset; import net.guttershark.support.preloading.events.PreloadProgressEvent; import net.guttershark.util.XMLLoader; import net.guttershark.model.Model; public class TestPreloader extends Sprite { private var ml:Model; private var am:AssetManager; private var pc:PreloadController; private var assets:Array; private var xmlLoader:XMLLoader; public var progress:MovieClip; public function TestPreloader() { am = AssetManager.gi(); loadModelXML(); } private function loadModelXML():void { xmlLoader=new XMLLoader(); xmlLoader.contentLoader.addEventListener(Event.COMPLETE,onModelLoaded); xmlLoader.load(new URLRequest("model.xml")); } private function onModelLoaded(e:*):void { ml=Model.gi(); ml.xml=new XML(xmlLoader.data); /** define paths. **/ ml.addPath("bitmaps","assets/bitmaps/"); preloadAssets(); } private function preloadAssets():void { pc = new PreloadController(300); //remember.. 300 = the pixelsToFill. pc.addEventListener(Event.COMPLETE,onPreloadComplete); //when preloading all items complete. pc.addEventListener(PreloadProgessEvent.PROGRESS,onProgress); //progress for all items as a whole. assets = ml.getAssetGroup("pictures"); pc.addItems(assets); pc.start(); } private function onPreloadComplete(e:Event):void { trace("preloading complete"); addChild( am.getBitmap("myPicture") ); } private function onProgress(ppe:PreloadProgessEvent):void { trace(ppe); progress.width=ppe.pixels; } } }
There’s only one minor change to the code, I’ve added one line that defines the “bitmaps” path with the model.
Conclusion
That’s all there is to assets and paths with the model class. Hopefully you begin to see how much work Guttershark can really do for you. Guttershark is all about eliminating code. I hate writing code, don’t you? I actually love writing code, but the code that I hate writing is the same code i’ve already written on another project.
You may have noticed, there’s even more room for improvement. There are a few things here that should definitely not have to be written again. And there’s still a few things that are “hard coded”.
What I’ll show you next is the DocumentController. It takes care of loading your model xml, and gives you hooks to initialize paths with the model.
With Guttershark and the DocumentController, you’ll see that this example we’ve been working on will be significantly reduced - imagine that, event less code?
9 commentsPreloading and Asset Management with Guttershark
I thought I’d share a quick article on how and why preloading, and asset management is so simple with guttershark.
The preload controller is designed to be the one access point for loading any type of files. As some of you might be snooping through the guttershark library - you’ll see that there are multiple classes that help do the work for the PreloadController, which are called “Workers”. Don’t be fooled by all the support classes - you don’t ever need to use them.
Basic example
Let’s look at an example, this only sets up the preloader to load in some assets, we’ll look at getting them out in a bit.:
package { import flash.events.Event; import net.guttershark.control.PreloadController; import net.guttershark.support.preloading.Asset; import net.guttershark.support.preloading.events.PreloadProgressEvent; public class TestPreloader extends Sprite { private var pc:PreloadController; private var assets:Array; public function TestPreloader() { pc = new PreloadController(); pc.addEventListener(Event.COMPLETE,onPreloadComplete); //when preloading all items complete. pc.addEventListener(PreloadProgessEvent.PROGRESS,onProgress); //progress for all items as a whole. //pc.addEventListener(AssetProgressEvent,onAssetProgress); //fired for every asset's individual progress. //**there are move events available. see docs for those.** //now let's add some assets assets=[]; assets.push( new Asset("assets/myPicture.jpg") ); assets.push( new Asset("assets/myOtherPicture.jpg") ); //add the assets pc.addItems(assets); //now let's kick off the preloader pc.start(); } private function onPreloadComplete(e:Event):void { trace("preloading complete"); } private function onProgress(ppe:PreloadProgressEvent):void { trace(ppe); } } }
What you’re looking at is the most basic form of preloading with guttershark. In the above example, we’re loading jpg’s. Internally to the Asset class, it uses a “BitmapWorker” to load in the asset. This is something you don’t have to specify, it will figure out what type of content your asset is based off of the file extension.
That raises a question - what about loading files that don’t have an extension? With asset instances, you can specify a “forced file type”, which informs the Asset of which worker to use. For example:
var rssAsset:Asset = new Asset("http://example.com/rss?feed=atom",null,"xml");
Ignore the second “null” parameter for now, I’ll get to that. The third parameter, is how you set a “forcedFileType”. So this asset will be loaded with the XMLWorker.
Showing progress
Guttershark has some cool conventions on multiple classes, which will automatically give you a pixel value based on some other type of value, such as progress, time, etc.
The PreloadProgressEvent has a property called “pixels”. This value is based off of what you tell the preloader to “fill”. For example, let’s say we wanted our preloader to fill 300 pixels. Keep in mind, what you do with this “pixel” value is up to you. It could be mapped to height, width, etc. Here’s the example (this is in addition to the above example):
package { /*..*/ public class TestPreloader extends Sprite { /*..*/ public var progress:MovieClip; public function TestPreloader() { pc = new PreloadController(300); //(this is key, it specifies the "pixelsToFill") /*..*/ } private function onPreloadComplete(e:Event):void { trace("preloading complete"); } private function onProgress(ppe:PreloadProgessEvent):void { /*..*/ progress.width=ppe.pixels; } } }
In the above example, the first argument to the preload controller constructor is the “pixelsToFill” property. Which is how the pixel value is delivered to you in the event handler.
There are a few other classes that offer this same type of behavior. The FLV class is another example - it will give you a “pixelsPlayed” property. Which you map to a progress bar. Read more of the guttershark docs for that.
Ok, that covers the majority of working with the preload controller. There are a few other methods, and properties that may be of use. You can check those out in the docs.
On to using the assets.
Accessing Assets with the AssetManager
Every preload controller you use stores all of the assets loaded in the AssetManager. The asset manager is a singleton - this creates a globally accessible asset library, so it doesn’t matter in which class, or in what scope assets are loaded - they all get into the asset manager.
The preload controller also (by default), loads all assets into the same application domain. You’ll see what that does in a bit.
Remember that “null” parameter for the Asset class from a few paragraphs ago? That parameter is called the “libraryName”. When you specify the library name for an asset, it registers that asset in the asset manager by that id.
So, to slightly alter the example so far, to attach a bitmap onto the stage. It would look like this (here’s the complete example):
package { import flash.events.Event; import net.guttershark.control.PreloadController; import net.guttershark.support.preloading.Asset; import net.guttershark.support.preloading.events.PreloadProgressEvent; public class TestPreloader extends Sprite { private var am:AssetManager; private var pc:PreloadController; private var assets:Array; public var progress:MovieClip; public function TestPreloader() { am = AssetManager.gi(); pc = new PreloadController(300); pc.addEventListener(Event.COMPLETE,onPreloadComplete); pc.addEventListener(PreloadProgessEvent.PROGRESS,onProgress); //now let's add some assets assets=[]; assets.push( new Asset("assets/myPicture.jpg", "myPicture" ) ); assets.push( new Asset("assets/myOtherPicture.jpg", "myOtherPicture") ); //add the assets pc.addItems(assets); //now let's kick off the preloader pc.start(); } private function onPreloadComplete(e:Event):void { trace("preloading complete"); addChild( am.getBitmap("myPicture") ); addChild( am.getBitmap("myOtherPicture") ); } private function onProgress(ppe:PreloadProgessEvent):void { trace(ppe); progress.width=ppe.width; } } }
Again, the important piece of code in this example, is the addition of the second parameter to the Asset instance. Each one has a library name, which will make that asset available in the asset manager.
For another example, let’s look at how you can load swfs, and grab assets out of the swf’s library, I’ve altered the asset that is loaded, and what happens when the preload is complete.:
package { /**/ public class TestPreloader extends Sprite { private var am:AssetManager; private var pc:PreloadController; private var assets:Array; public var progress:MovieClip; public function TestPreloader() { am = AssetManager.gi(); pc = new PreloadController(); /*..*/ //now let's add some assets assets=[]; assets.push( new Asset("assets/myAssetsSWF.swf", "assets" ) ); /*..*/ } private function onPreloadComplete(e:Event):void { trace("preloading complete"); addChild( am.getMovieClipFromSWFLibrary("assets", "myMovieClip") ); } /* .. */ } }
You should hopefully start to see some of the elegance with the preload controller, and asset manager.
How do application domains play into this picture? In the above example, I’m calling the method “getMovieClipFromSWFLibrary”. This method does like it sounds, it grabs an asset out of that swf’s application domain. There are other methods to get other assets as well, like getBitmapFromSWFLibrary, getSpriteFromSWFLibrary, etc.
That’s well and good, but we can take this further - because the preload controller loads everything into one application domain, technically you don’t have to tell the asset manager which swf that asset is in. So, we could alter this example like this:
package { /**/ public class TestPreloader extends Sprite { private var am:AssetManager; private var pc:PreloadController; private var assets:Array; public var progress:MovieClip; public function TestPreloader() { am = AssetManager.gi(); pc = new PreloadController(); /*..*/ //now let's add some assets assets=[]; assets.push( new Asset("assets/myAssetsSWF.swf", "assets" ) ); /*..*/ } private function onPreloadComplete(e:Event):void { trace("preloading complete"); addChild( am.getMovieClip("myMovieClip") ); } /* .. */ } }
Now you can see, that it doesn’t matter which swf the clip “myMovieClip” is defined in, because the swf is merged into one application domain.
This does raise one problem. Multiple library items, with the same export name, in different swfs. For example, if I have two swfs (swf1, swf2), and they both have the clip “GlossButton”. The last one to be loaded in will be discarded. If swf2 is loaded after swf1, the GlossButton in swf2 will be discarded. That’s the only pitfall to watch out for when using one application domain.
Conclusion
The PreloadController can load anything for you. It can load bitmap, swf, flv, xml, audio, and stylesheet (css) files.
Let me quickly note - manually creating Asset instances is a no-no! I never actually create Asset instances in code, the examples were to illustrate how the preload controller works.
So, in the next post, I’ll show you how to get rid of that annoying code that requires you to manually create Asset instances - we’ll do that with XML and the Model class.
And as always, read the docs.
2 comments