Access children of embedded aswf - actionscript-3

I am embedding an swf file that has some children on its timeline. Like this:
[Embed(source="assets/skyscraper200x600.swf")]
private var Skyscraper :Class;
All children in the swf have an instance name, I double checked that when creating the swf in Flash CS5.
I am trying to access those children by name like this:
_bg = MovieClip(new Skyscraper());
_pig = MovieClip(_bg.getChildByName("chara_pig"));
_arrow = MovieClip(_bg.getChildByName("arrow_banner"));
However, both _pig and _arrow end up being null.
What's even stranger is that when I look at the Skyscraper object in the debugger, it shows a rather strange class name and a Loader as its only child (which in turn has no children). What's up with this?
.
I can access them like above if I do not embed the swf, but load it with a Loader. But I cannot do it in this case. I need to embed the swf.
So, how can you access children of embedded swfs?
I am not talking about accessing classes in the library of the embedded swf, but the instances on the timeline.

Here is a solution. You can also see the steps who helped me find this solution (describeType is your friend) :
public class Demo extends Sprite {
[Embed(source="test.swf")]
private var Test:Class
public function Demo() {
//first guess is that embed SWF is a MovieClip
var embedSWF:MovieClip = new Test() as MovieClip;
addChild(embedSWF);
//well, emebed SWF is more than just a MovieClip...
trace(describeType(embedSWF));//mx.core::MovieClipLoaderAsset
trace(embedSWF.numChildren);//1
trace(describeType(embedSWF.getChildAt(0)));//flash.display::Loader
var loader:Loader = embedSWF.getChildAt(0) as Loader;
//the content is not already loaded...
trace(loader.content);//null
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(){
var swf:MovieClip = loader.content as MovieClip;
var child:MovieClip = swf.getChildByName("$blob") as MovieClip;
//do nasty stuff with your MovieClip !
});
}
}

At the end of this tutorial http://jadendreamer.wordpress.com/2010/12/20/flash-as3-embedding-symbols-from-external-swf-game-tutorial there is an example of how it can be done

One solution is to embed the swf as an octet stream and reconstitute its bytes. However, I seem to remember reading somewhere that if you just set the mimeType to "application/x-shockwave-flash", you get a MovieClip that works as normal.

Related

As3 instances from imported swf not recognized

I have made something like a level in flash editor. made some classes inside the editor that inherited from the classes in my project. next I export my swf to later be loaded by my main code.
the thing is that once I have the swf loaded I try doing some traces to check if the instances are the correct class.
trace(map.getChildAt(i)+" D "+(map.getChildAt(i) as PointerImage));
witch outputs this: [object PointerBall] D null.
PointerBall(from flash) inherites from PointerImage(from my main code).
now if I trace this
trace((new PointerBall())+" Y "+(new PointerBall() is PointerImage));
witch outputs this: [object PointerBall] Y true
so the problem is only with instances imported from the swf.
This worked for me when I tried it. Assuming your referenced .swf is in the same application domain as the parent. The key is to have the classes that you're referencing be in a specific package. Classes that aren't in packages are in their own namespace, in both the loaded .swf and the parent. So PointerImage in your loaded .swf is not the same PointerImage that exists in your parent. It all has to do with namespace.
Just move these classes into a package folder named game and rename the package and you should be set.
package game{
import game.PointerImage
public class PointerBall extends PointerImage{
//Class code
}
}
This is what I'm working with:
function onLoad(evt:Event):void{
var c:MovieClip = evt.target.content as MovieClip;
addChild(c);
var t:BigTest = c.getChildAt(0) as BigTest;
trace(t); //[object LitteTest]
}
You have to use a LoaderContext and set the domain you want to use for either overriding the current class definitions or overriding the loaded swf ones:
var context:LoaderContext = new LoaderContext();
context.securityDomain = SecurityDomain.currentDomain;
context.applicationDomain = ApplicationDomain.currentDomain;
var ldr:Loader = new Loader();
ldr.load(urlRequest, context);
Working with class inheritance is ok but easier is working with Interface.

MovieClip doesn't dispatch mouse event after nesting MovieClip loaded from external SWF

Mostly, problem is described in the title... I tried to load an external SWF file that contains some named MovieClip instances (exporting and naming is done by Flash CS5 software) and to add some of externaly loaded (named) MovieClip-s in MovieClip object which is created in my code. Problem appears when i add MOUSE_CLICK listener to parent MovieClip. Simply, it does not dispatch event when i click on it at the stage...
private var loader:Loader;
public function Example(){
loader = new Loader();
var request:URLRequest = ... // URL to external SWF
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadingCompleted)
loader.load(request);
}
private function loadingCompleted(event:Event):void{
var mc:MovieClip = loader.content as MovieClip;
var myMovie:MovieClip = new MovieClip();
myMovie.addChild(mc.getChildByName("object_name"));
myMovie.addEventListener(MouseEvent.CLICK, myMovieClicked);
addChild(myMovie); // myMovie (with nested mc) appears on the stage
}
private function myMovieClicked(evt:Event):void{
//never reached
}
EDIT: I didn't mention that i'm working in Flex using FlashBuilder 4.5 where i created ActionScript project. Code above is body of Example class, which is main SWF class.
EDIT AFTER ANSWER: myMovie.mouseChildren = false solves the problem. Earlier i tried to set mouseEnabled = true, and it didn't fix the problem. But i'm confused about event flow now... Even if child is target node, why mouse listener on parent MovieClip doesn't recieve event (in capture phase) when parent is still on event flow? Moreover, when i create another movie clip in my code (whit some simple shape inside) and add it to myMovie, everything works fine. What is so special when i obtain movie clip from externaly loaded SWF?
Have you tried doing myMovie.mouseEnabled = true and myMovie.mouseChildren = false ?

remove external swf file as3

I have loaded an external swf file which plays a flv file by default as swf is loaded. Now the problem is how do i remove the swf file from memory. my code :
var myLoader:Loader = new Loader();
var url:URLRequest = new URLRequest("ExternalSWF.swf");
myLoader.load(url);
detailMovieClip.movieHolder.addChild(myLoader);
I have tried many combinations of removeChild, unload and unloadAndStop but none works. I figure its all about not referencing correctly.
Update:
I went with the answer from Jegan, but it only work when i am testing in a dummy project which has only 1 numChildren, howver in real world code example numChildren reported 22 so i am not sure if that would be an issue. here is the real world code:
var myImageLoader:Loader;
var myImageRequest:URLRequest;
var theImagePath:String;
//part from xml processor function
theImagePath = "flash/"+myXML..item_video_link[n];
loadTheMovie(theImagePath);
function loadTheMovie(theImagePath):void{
myImageLoader = new Loader();
myImageRequest= new URLRequest(theImagePath);
myImageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,showMeTheVideo);
myImageLoader.load(myImageRequest);
}
function showMeTheVideo(evt:Event):void{
detailsMovieClip_mc.details_video_holder.dynamicVideoHolder.addChild(myImageLoader);
}
stopVideo(sectionname):viod{
if(detailsMovieClip_mc.details_video_holder.dynamicVideoHolder.numChildren !=0){
trace("what is the number of children: "+numChildren);
myImageLoader.unloadAndStop();
detailsMovieClip_mc.details_video_holder.
dynamicVideoHolder.removeChild(myImageLoader);
}
}
stage.addEventListener(MouseEvent.CLICK, removeSWF);
function removeSWF (e:MouseEvent):void
{
if(detailMovieClip.movieHolder.numChildren !=0){
myLoader.unloadAndStop();
detailMovieClip.movieHolder.removeChild(myLoader);// empty the movieClip memory
}
}
OR
Name your Loader instance and then search by using getChildByName
myLoader.name = "myloader";
function removeSWF (e:MouseEvent):void
{
if(detailMovieClip.movieHolder.numChildren !=0){
Loader(detailMovieClip.movieHolder.getChildByName("myloader")).unloadAndStop();
detailMovieClip.movieHolder.removeChild(detailMovieClip.movieHolder.getChildByName("myloader"));// empty the movieClip memory
}
}
I guess this is because you are adding the loader to the scene itsef.
Either you want to keep this behavior, in this case there is a quick fix, remove the loader from the MovieClip by using removeChild(), then set the reference to null, or use the delete keyword.
Either you want to do it properly, in this case, listen for the LOADED event, adds the MovieClip contained by the loader.content to the target MovieClip. Then, when you want to unload it, remove the clip from the container using removeChild(), then loader.unload().

How to get all definitions in an ApplicationDomain of a loaded SWF?

When you load a SWF into another, the loader SWF can get specific definitions from the loaded SWF using ApplicationDomain.getDefinition(name:String). For example:
package
{
// ... imports
public class SWFLoader extends Sprite
{
private var loadedAppDomain:ApplicationDomain;
public function SWFLoader()
{
var request:URLRequest = new URLRequest("test.swf");
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onTestLoadComplete);
loader.load(request);
}
private function onTestLoadComplete(event:Event):void
{
var loaderInfo:LoaderInfo = LoaderInfo(event.target);
loadedAppDomain = loaderInfo.applicationDomain;
// Here we can get ANY defined symbol (class, namespace or function according to Adobe Flash help)
var someSymbolClass:Class = Class(loadedAppDomain.getDefinition("SomeSymbol"));
var someSymbolSprite:Sprite = Sprite(new someSymbolClass());
addChild(sprite);
}
}
}
How can I get all of the definitions in a SWF, without specifying each explicitly?
As of Flash Player 11.3, you can use ApplicationDomain.getQualifiedDefinitionNames().
See the official documentation for the method and this blog post about the Flash Player release.
EDIT: This is the quickest solution to your problem : http://www.bytearray.org/?p=175
Hi, you could use this library : https://github.com/claus/as3swf/wiki/
Don't have the time to do deeper test, but here is what i found :
1 - I have created a .swf containing in the library 2 exported MC, $Test and $Test2
2 - Once the .swf loaded by a Loader, i run this code :
var swf : SWF = new SWF(loader.contentLoaderInfo.bytes);
trace(swf);
3 - In the output you'll notice theses lines :
[76:SymbolClass]
Symbols:
[0] TagID: 2, Name: $Test2
[1] TagID: 1, Name: $Test
I think that there is a way to obtain this info directly thru the library API
You have to put the loaded SWF in the current ApplicationDomain.
Use ApplicationDomain.currentDomain to do that, on the ContextLoader info.
loader.load(request, new ContextLoader(false, ApplicationDomain.currentDomain));
It should work.
Following from the answer I received from a previous question I asked here a few days ago (it's about SWC , but in your case, it doesn't really make a difference )
Working with SWCs - getDefinitionByName issue
If both SWFs share the same ApplicationDomain, you should be able to access the loaded SWF classes directly by doing this:
//provided that SomeSymbol extends Sprite...
var someSymbolSprite:Sprite =new SomeSymbol();
On the other hand, you won't be able to do this
var SomeSymbol:Class = getDefinitionByName("SomeSymbol");
unless you create a library of objects from the loaded SWF
var ssym:SomeSymbol;
Check the above link for more details.

Load AS2 SWF Into AS3 SWF and pass vars in URL

I've got an AS3 SWF that I'm going to be loading other SWFs into. These child SWFs all take a single parameter on the URL. I can't seem to get it working when loading an AS2 child, and it needs to be able to handle both.
so I have
var request:URLRequest = new URLRequest();
var loader:URLLoader = new URLLoader();
request.url = "http://domain/as2.swf?param=foo";
loader.load(request);
// etc on to the eventListeners, addChild, etc
When the as2 SWF gets loaded, it can't see the parameter I've passed to it. It's looking for _root.param. Am I doing this wrong or am I attempting the impossible?
EDIT: I should add that I can load a SWF with those URL params from an AS2 loader and it works just fine.
It's not trivial to communicate between AS2 and AS3 since they run in different virtual machines. Check this http://www.gskinner.com/blog/archives/2007/07/swfbridge_easie.html for some hints.
Edit: If you cannot change the loaded as2 content your only options is creating a 'wrapper' as2 loader that uses the linked example above to communicate with the as3 and interfaces with the loaded as2 content using _root.varname This is not pretty but it might just work.
It might be worth trying to assign the variables dynamically after the SWF has loaded but before you add it to the stage. Ie.
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, movieLoaded);
function movieLoadedHandler(event : Event) : void
{
var loaderInfo : LoaderInfo = event.target as LoaderInfo;
var clip : DisplayObject = loaderInfo.content;
for each(var prop in varsToTransfer)
{
clip[prop] = varsToTransfer[prop];
}
// add to parent
}
Let me know how that goes.
AS3 -> AS3
Movie 1(www.domain1.com):
Load the external movie when click a "buy" button...
buy.addEventListener(MouseEvent.CLICK,function(){
var ldr:Loader = new Loader();
var url:String = "http://www.domain2.com/movie.swf?a=b&c=d";
var urlReq:URLRequest = new URLRequest(url);
ldr.load(urlReq);
addChild(ldr);
});
Movie 2(http://www.domain2.com/movie.swf):
var mc:MovieClip = this as MovieClip;
var ldi:LoaderInfo = mc.loaderInfo;
var lobj:Object = ldi.parameters as Object;
for (var l in lobj) {
dumper.htmlText += l+" => "+lobj[l]+"<br />";
}
"dumper" is the name of the Dynamic Textbox field located in Movie2.
The output should look like:
a => b
c => d
Instead of looking for _root.param, use _root._url then parse out your parameters by hand.
var url: String = _root._url;
var param: String = 'param=';
var paramStart: Number = url.lastIndexOf(param);
var paramValue: String = url.substring(paramStart + param.length, url.length);
trace(paramValue);
SWFBridge is awesome and overkill for something like this.
You are doing it wrong.
"http://domain/as2.swf?param=foo"
Is a request for the file named as2.swf, on the server named domain. Any ?param=foo parameters that are part of that http request are lost when the request is complete. If the server needed to do something according to these variables, it would, but you are asking a .swf file to detect these variables, that's just silly.
Put a variable in your Global object (Global namespace) for the flash player, then when the as2 .swf is loaded into that flash player it will have access to the variable you set in your Global object.
I am not proficient in as2, but in as3, the Global object can be accessed with the this keyword, at the package level (probly is the same for as2, just dont worry about setting it at a package level).