I'm new to AS3, and am trying to understand how externally loaded SWFs work in AS3. Since Flash 4/5, it was common to have one main SWF file in a Flash web project, and then load other SWF files into it, often for various "sections" of a website or web project. In the main file, we'd have masks animating the container movieclip(in which external sections/SWF files were loaded) and have animations and transitions play as the section finished loading and the loaded content was displayed.
In AS3, I've used the Loader class to load and display the external file, my main problem is in communicating with the loaded content, call it's functions, or call root functions from it.
In AS2, we could use someMovieClip.loadMovie("ExternalContent.swf") and the ExternalContent file would load inside someMovieClip. You could access functions on the "External.swf" main timeline using someMovieClip.function();. And inside the "ExternalContent.swf", we could use _root.function() to access functions in the main file ExternalContent was being loaded into. Doing this in AS3 seems bizarre and neurotic, and I feel like I'm missing something fairly basic here.
//Loading in ExternalContent.swf into the sprite
//ExternalContent has a movieclip called "boxes" on it's main timeline
//boxes has a boxesPrompt() function in it's timeline.
var sprite:Sprite = new Sprite();
addChild(sprite);
var loader:Loader = new Loader();
loader.load(new URLRequest("ExternalContent.swf"));
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoaded);
function onLoaded(event:Event):void
{
sprite.addChild(event.target.content);
sprite.boxes.boxesPrompt();
//Flash gives the following compiler error at the above
//Scene 1, Layer 'Layer 1', Frame 1, Line 21 1119: Access of possibly undefined property boxes through a reference with static type flash.display:Sprite.
//But when I comment out sprite.boxes.boxesPrompt() and use this, it works:
event.target.content.boxes.boxesPrompt()
}
The boxesPrompt() function inside the "ExternalContent.swf" just traces it's parent, grand-parent, and great grand-parent - trace(this.parent.parent.parent);. And when I call that function inside the onLoaded event-handler using "event.target.content.boxes.boxesPrompt()", it shows that the Boxes object(which was on the main timeline of External.SWF), has a parent movieclip, a grand-parent sprite, and a great grand-parent object mainTimeline.
I thought re-parenting the loaded content into the sprite would allow me to access the loaded content as easily as loadMovie() used to be - accessing loaded content like it was present directly inside the clip it was loaded in. But that doesn't work at all.
So to rephrase, my question is:
How do I communicate from the main "loader" SWF file, with the content that's loaded in. I don't want to communicate using event.target.content.{etc} because then I'd only be able to address the loaded content inside the Loader's event.complete event handler.
How do I "re-parent" loaded content, so I can place it inside some movieclip/sprite on the main timeline of the loader file, rather than using some really long convoluted way.
How to communicate from inside the loaded content, to the main/loader file. Previously, we'd use _root.functionName() to do stuff like play some animation transitioning from the current externally loaded "section" to another section. How'd I go about doing that.
AS2 & AS3 is vastly different. But you will have to swallow the fact that AS3 has been developed as an improvement over AS2. So any transition you make, is also for the better.
For eg : The _root in AS2 allowed global objects & variables to accessed & changed anywhere, which is a bad practice & leads to non maintainable code in a project.
Having said that, let me address your questions:
If you are able to get access to the loaded content with
event.target.content... you should save it inside a,say class
variable & may access it later elsewhere in the class.
You must understand that you will be able to access the content only
after loading it, so have to wait for it to complete anyway &
event.complete handler is probably your best bet.
I doubt if you can pick random content from a loaded swf & re-parent it into the current swf.As explained you might not have a long convoluted way.
Accessing the parent could be done in many ways. You can use .parent or actually call a function from the parent swf passing its reference to the child.
var sprite;
addChild(sprite);
var loader:Loader = new Loader();
loader.load(new URLRequest("ExternalContent.swf"));
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoaded);
function onLoaded(event:Event):void
{
sprite = event.target.content;
//This should work
sprite.boxes.boxesPrompt();
}
See this example for more info.
Related
how do i absolutely and completely unload a loaded SWF.
Here's the case. I have two different SWF, both have the same movieClips in the library with the same name and instance...but...both have different shape. So basically both are different but the names.
So i loaded the first.swf into the main.swf, in the first.swf contains button that order the loaded in the main.swf to unloadAndStop() and load the second.swf. But somehow the objects in the second.swf take the shape in the first.swf.
I hit the wall with this. How do i completely unload the first.swf
Thx guys
Try to load child swfs (first.swf and second.swf) into child application domains of the current application domain (Usage C in this Article Working with application domains, you can also find code sample from this article below). With this technique you'll get:
separate classes (all classes) of first.swf and second.swf from each other
unload all the class definitions for garbage collection after unloading swf
AS3 from the article:
var appDomainC:ApplicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);
var contextC:LoaderContext = new LoaderContext(false, appDomainC);
var loaderC:Loader = new Loader();
loaderC.load(new URLRequest("module3.swf"), contextC);
I made a Flash project in FlashDevelop to create an Ad.
The Preloader is setup by making use of the Additional Compiler argument:
-frame=NameOfLabel,NameOfMainClass
My main class is simply called "Main", at the top / default package level.
So frame #1, being the Preloader portion of the SWF, has:
Very few bitmaps, vector-graphics and text (to stay under 50kb);
A YouTube video player in the center (does not count in the filesize limit);
The frame #2 has everything else (the Main class basically embeds all it's dependencies). This includes:
Assets from precompiled SWF (Bitmaps, Symbols, Fonts, XML data);
All classes imported (this is recursive for every classes importing other classes);
Now my big problem is, my client requested the "replay" functionality long after I've completed 99.9% of the project.
I have the project more-or-less broken into different states (Intro, Ready, SlideMenu, etc.), but I'm not sure how I can easily reset the Flash movie back to the very beginning (where it was preloading and showing the YouTube video).
The easy solution would be to simply call an ExternalInterface JavaScript method that would refresh the Flash container, BUT I don't think I have control over what's going on the HTML / JavaScript side.
Is there an easy way to invoke a replay function from AS3?
Would not simply going back to frame 1 do the trick ?
The following seems to do the trick!
private function onReplayClick(e:MouseEvent):void {
var theStage:Stage = this.stage; //Temporarly store the stage.
//Kill any animations happening:
TweenMax.killAll(); //3rd party, may not be applicable for you :P
//Remove ALL containers / child DisplayObjects
SpriteUtils.recursiveRemove(theStage); //custom-made
// (this object is no longer attached to the stage at this point)
//Nullify any Singleton / Static variables:
Main.INST = null;
// Load the 'bytes' of the current SWF in a new Loader, then...
// add it to the stage
var swf:Loader = new Loader();
swf.loadBytes( theStage.loaderInfo.bytes );
theStage.addChild( swf );
}
By doing a deep recursive cleanup of the DisplayObjects, and any static variables (like Singleton instances), it leaves you with a blank stage.
After that, you can instantiate a new Loader that will load the SWF itself via the current LoaderInfo's bytes property.
Add the Loader to the Stage, and you're up and running again!
READY? Here it is:
var TheLoader:Object = parentObj.TheExit as Object;
This line gets me to the swf I loaded and I can now change the alpha, move it etc...
BUT HOW HOW HOW... do I get one of its children and control get that same control?
Example Code:
TheLoader.TheChild.alpha = .3; // Does not work!
5 days on this issue is WAY TOO LONG! Here is the 3rd post with the same issue but more detail. as3 externally loaded swf from network to control externally loaded swf from network
I just made this shorter to get attention to the ONE LINE I NEED!!!
THANKS!
If you look at the documentation for Loader, you'll see that it has a content property. This is how you access your loaded content. So, for example, if TheLoader is a Loader, and if TheChild was an instance on the timeline of the loaded SWF, you could do:
var child : Sprite = MovieClip(TheLoader.content).TheChild;
This child is not available until the content has been actually loaded, so be sure to listen to for the COMPLETE event on the Loader's contentLoaderInfo before accessing the content:
TheLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaded);
function onLoaded(event : Event):void
{
trace(MovieClip(loader.content).theChild);
}
Also note that you may run into security issues if the loader and loadee SWFs are not on the same domain. In this case, you will have to call Security.allowDomain in the SWFs to allow the cross-scripting.
I have Loader object containing loaded swf. I don't know how the shape of this swf looks like - it's not necessarily rectangular.
I want to add some light reflection on it. I need to mask this reflection with Loader, but in the same time I need this Loader to be visible.
I don't want to load swf twice, because it may contain some dynamic, script-generated content, which can produce different results in each Loader.
And that's quite a problem, isn't it? Any ideas?
Image: http://www.freeimagehosting.net/uploads/12e6b9cd63.jpg
you could add your instance of the loaded swf to the stage, and for the reflection use he same movieclip/sprite and draw it to a new BitmapData. do the transformations needed and then add to stage.
Or imagine the following situation, instead of having the swf that is loaded adding it's own graphics to library you could do this from the loading application, so for instance, give the instance name of MyDisplayObject to the movieclip in the loaded swf and export to actionscript. After you load the swf you could use the following code to access the library, so you can add this object number of times you need, in you case 2.
here is the code (from adobe live docs)
function initHandler(e:Event) {
var applicationDomain:ApplicationDomain = e.target.applicationDomain; // e.target is the loaderInfo object
var testClip:Class=applicationDomain.getDefinition("testClip") as Class;
var clip = new testClip();
addChild(clip);
var reflection = new testClip();
addChild(reflection);
reflection.y= 100;
}
Hope this get's you on the right track.
Give this scenario:
I have a cool graphic in Illustrator or Flash.
The graphic represents a figure, with various elements inside, shapes, lines, gradients, etc.
I export it to a swf file and I can view my nice graphic if I open it.
I have a (pure) as3 application, which loads swfs.
Then...
Can I manipulate the contents of the loaded swf. For example: Moving its contents, changing some elements inside, duplicating them. Deforming them with the transform matrix and things like that?
Can I, at least, read the contents and replicate them (the graphic data) inside the main application.
As far as I've been researching, I can only import the swf and use it as a whole display object, without any children, and I cannot modify it.
I want to, somehow, use the graphic information of the external swf to allow the main application deform it or use it to make new versions of the graphic.
No, sadly you can't retrieve or change compiled Graphics elements in detail, you can only use them as DisplayObjects and transform them through their public properties (scale, rotation, transform, etc...).
There is way of programmaticaly retrieve a single path coordinates by setting it as the "guide" of an object in the Flash IDE and within an onEnterFrame retrieve the object's position, but as you can imagine, its quite dirty.
You can replicate the clips by either setting them as classes within the loaded SWF (In Flash IDE: library>symbol>properties>export for AS) or using BitmapData to draw them as you please from the main movie.
Another solution would be to use a more open format, like SVG or FXG, but it can get quite complicated...
You can access loaded SWF's methods and properties if both are AVM2 movies.
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete);
private function onLoadComplete(e:Event):void
{
var content:Object = LoaderInfo(e.target).content;
//assuming there is a public someMethod() defined in
//the document class of the loaded SWF, you can call it as:
content.someMethod();
//you can access any property you wish
content.someObject.graphics.beginFill(0x00ff00);
content.someObject.graphics.drawCircle(10, 10, 10);
content.someObject.graphics.endFill();
}
SWF content can be readed by new function added to Flash Player 11.6 and AIR 3.6:
flash.display.Grapics.readGraphicsData()
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Graphics.html#readGraphicsData%28%29
Similar problem:
How to read data from shape/graphics object