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.
Related
I am making an application to test art from a game I volunteered for. Right now the example I am posting will only touch the armors but the loading process is the same throughout the program. I have a movieclip ready to hold the loaded file but it adds it to the container via the class. It works how it should however my issue is that if you use another file with the same classes then it will default to the first file loaded. Even i use loaderr.unloadAndStop() and remove everything from the stage, it will always load the first file that corresponds to the class I am loading by. Since the armor pieces are loaded by class it makes it a hassle to test multiple changes to an armor file without changing the classes on each export. Here is an example of the code that is being used and I am curious if there is any way that I can improve this. `
public class Test extends MovieClip
{
public var mcChar:Display;
public var btnTest:SimpleButton;
public var btnTest2:SimpleButton;
public var ldr:Loader = new Loader();
public var strSkinLinkage:String;
public var strGender:String;
public function Test()
{
btnTest.addEventListener(MouseEvent.CLICK, TestP);
btnTest2.addEventListener(MouseEvent.CLICK, TestP2);
}
public function TestP(e:MouseEvent)
{
mcChar = new Display();
stage.addChild(mcChar);
mcChar.x = 789.6;
mcChar.y = 604.75;
mcChar.width = 667.15;
mcChar.height = 478.55;
strSkinLinkage = "CNC";
strGender = "M"
this.ldr.load(new URLRequest("CNC.SWF"), new LoaderContext(false, ApplicationDomain.currentDomain));
this.ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, this.onLoadSkinComplete);
}
public function TestP2(e:MouseEvent)
{
mcChar = new Display();
stage.addChild(mcChar);
mcChar.x = 789.6;
mcChar.y = 604.75;
mcChar.width = 667.15;
mcChar.height = 478.55;
strSkinLinkage = "CNC";
strGender = "M"
this.ldr.load(new URLRequest("CNC2.SWF"), new LoaderContext(false, ApplicationDomain.currentDomain));
this.ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, this.onLoadSkinComplete);
}
public function onLoadSkinComplete(e:Event):*
{
var AssetClass:Class;
try
{
AssetClass = (getDefinitionByName(((strSkinLinkage + strGender) + "Head")) as Class);
mcChar.head.addChildAt(new (AssetClass)(), 0);
}
catch(err:Error)
{
AssetClass = (getDefinitionByName(("mcHead" + strGender)) as Class);
mcChar.head.addChildAt(new (AssetClass)(), 0);
};
AssetClass = (getDefinitionByName(((strSkinLinkage + strGender) + "Chest")) as Class);
chest.addChild(ldr.content (AssetClass)());
mcChar.chest.addChild(new (chest)());
this.ldr.contentLoaderInfo.removeEventListener(Event.COMPLETE, this.onLoadSkinComplete);
}
}
`
I don't think its well formatted on this site but this is the core code. I have separate removal functions and my imports are all there. Like I said I cant seem to get it to format correctly. This is my test scenario and isn't my full dynamic tester where I can choose the file. Any help in figuring out how to use the most recent file is appreciated. Also for some background I am more of a self taught novice in as3.
When it gets to loading and unloading assets in AS3, there are several things to learn.
ApplicationDomain is a container for class definitions. The getDefinitionByName(...) method is basically the same as calling the ApplicationDomain.getDefinition(...) on the current ApplicationDomain (or maybe on the main ApplicationDomain, I never tried to do it in the loaded content). As the side result, you cannot have two classes with the same names inside the same ApplicationDomain (or rather you can, but one of them is inaccessible, who knows).
When you load another SWF which falls into the "same domain" category (same www domain, or same/nested local folder), AS3 automatically mixes all the definitions from the loaded SWF into the main ApplicationDomain. If you are willing to have some advanced control over loading/unloading stuff, or/and there are "skin" libraries that have similar sets of classes, you need to put the loaded files into separate ApplicationDomains or their definitions will collide and the result will be unpredictable (yet obviously not satisfactory).
The Loader.load(...) method has a second argument that allows you to do so:
// If there are no mandatory constructor arguments,
// you are free to omit the () brackets. I like doing so.
var aLoader:Loader = new Loader;
var aRequest:URLRequest = new URLRequest("mylibrary.swf");
// Documentation states that passing no argument here is
// the same as passing ApplicationDomain.currentDomain.
var childDomain:ApplicationDomain = new ApplicationDomain;
var aContext:LoaderContext = new LoaderContext(false, childDomain);
aLoader.load(aRequest, aContext);
Thus, when external SWF library is loaded, you can obtain its classes/definitions as following:
var aClass:Class;
// If you get things from the loaded SWF's Library
// then it is Sprite or MovieClip for the most cases.
var anAsset:Sprite;
aClass = aLoader.contentLoaderInfo.applicationDomain.getDefinition("MyAssetClass") as Class;
anAsset = new aClass;
When you do not longer need some of the loaded libraries, you call the Loader.unloadAndStop(...) method on the relevant Loader instance. Combined with the loading SWF into separate ApplicationDomain you can be sure that all of the loaded content (graphics, classes, sounds) is unloaded, destroyed and removed (that one I actually checked):
// Passing "true" also forces the Garbage Collector
// to actually do its job for a change.
aLoader.unloadAndStop(true);
Can variables be created dynamically without declaration when we write as Document class in AS3?
For example, from a library I'm importing sound files. Some 20 sound files.
If the code is in fla itself, we can assign in for loop like:
this["SOUND"+increasingNumber]
But in documentClass this is not working , since this refers the class here not the stage.
Any method to create variables?
When imported into your library, right click the sound file and go to its properties. Click the actionscript tab and check 'export for actionscript'. Give it a class name which you can then use in your document class to instantiate that sound.
If you named it Sound1:
var sound:Sound = new Sound1();
sound.play();
more detailed info here
[Edit to loxxy's reply] above shows how to create the variables in the document class.
To dynamically create all the sound variables, I'd recommend using an array, like so:
Suppose you named all your sounds in your library Sound1 to Sound20
import flash.utils.getDefinitionByName;
var sounds:Array = [];
var soundClass:Class;
for(var i:int = 1; i<21; i++){
soundClass = getDefinitionByName("Sound" + i) as Class;
sounds.push(new soundClass());
}
In fla when you add code, you add it into a framescript.
A framescript is a block of code repeated at a regular interval (framerate).
You can achieve that using addFrameScript like this.
However a better approach would be to not mix up framescript & the regular class methods.
You can access the 'stage' from the code but only after the added_to_stage event to be sure.
addEventListener(Event.ADDED_TO_STAGE, init);
function init(e:Event):void{
// Access 'stage' here
}
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.
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.
I have two SWFs: main.swf and external.swf. main.swf needs to access some methods in external.swf, so it loads external.swf into itself and uses getDefinitionByName("package.Class") to access the class and one of its methods:
var ExternalClass = getDefinitionByName("package.Class") as Class;
var ClassInstance = new ExternalClass();
var NeededFunction:Function = ClassInstance["NeededFunction"] as Function;
var response:String = NeededFunction(param);
Now, I need to extend the functionality of NeededFunction (which is a public method)... I know it's possible to override public methods, but how would I go about this with a dynamically loaded class?
I was thinking I could do something like this, but it doesn't work:
var ClassInstance["NeededFunction"] = function(param1:uint):String {
var newString = "Your number is: "+param1.toString(); //New functionality
return newString;
}
Another way to deal with this could be to have the classes in a package that's accessible by both SWFs. Just add the classes' root folder to your Actionscript path .
Instead of getting a class by using getDefinitionByName , you simply import it. As for overriding , you can create a Class that overrides one of the classes , or you can create an Interface.
import com.yourlocation.ExternalClass;
var external:ExternalClass = new ExternalClass();
Using FlashDevelop this is pretty simple to fix.
Right click your included swc from the Project list.
Choose options then "include library (complete library)".
..you can now use getDefinitionByName to get a unreferenced class from your swc file.