Link symbol from loaded swf to custom class dynamically - actionscript-3

I have a project where I load an external file with asset symbols (assets.swf) into the main swf and then add the symbols to the display when needed. I want the classes associated with each symbol to be linked to a custom class at runtime in the document class. I'd really like to avoid defining the custom classes in the assets fla through the symbol properties.
In AS2, this was possible with Object.registerClass as below:
Object.registerClass("assetID",AssetClass);
this.attachMovie("assetID", "asset_mc", 0);
So the symbol was independent of the class it is linked to at runtime.
In AS3, I'm seeing references to registerClassAlias but there is very little reliable documentation of it available online.
Does anyone know of a way of doing what I'd like to do with registerClassAlias or any other way?
thanks!!!
matt

First, you need to load your asset symbol and keep a reference to the loader.
assetsLoader.load(new URLRequest("assets.swf"));
When the loading is done you can retrieve your assets within the loaded SWF ApplicationDomain.
var assetClass:Class = assetsLoader.contentLoaderInfo.applicationDomain.getDefinition("MyAssetClass") as Class;
var asset:* = new assetClass();
Note: MyAssetClass should be defined inside assets.swf!
If you want further informations, you can read this article.

Related

What is the equivalent of the Adobe Flash symbol library for Haxe?

I'm trying to cross over to HaxeFlixel after learning of Flash's demise, but I'm not entirely sure how to bridge my understanding between the two. I'm currently using Visual Studio Code on a Mac.
In Flash(now Animate CC), you have a library full of symbols:
You can right-click and edit those symbols, such as setting a base class:
I have all of the .as base classes in my project folder and each one controls the Symbol(s). When I'm in VSC, I can create .hx files and I have a folder dedicated to images with all my game bitmaps in it. From there, I do not know how to recreate my game. What is a library of symbols, that I can assign base classes to, when coding in Haxe?
You can use assets created in Animate with the Haxe library OpenFL. Here is an overview of how this can be done: http://blog.peteshand.net/load-swfswc-assets-into-haxe-flash-or-html5-targets/
Also you could read official guide: http://www.openfl.org/learn/tutorials/using-swf-assets/
There's no library as you know it from Flash in OpenFL. If you look for "native" OpenFL asset handling look at the openfl.Assets class. It provides functions to load and parse several asset file formats.
If you need a class for your HaxeFlixel project that allows you to extend the basic functionality of a sprite you can extend FlxSprite and load the graphic/sprite sheet inside the constructor:
class Block extends FlxSprite{
public function new(){
super();
loadGraphic("assets/images/block.png", false, 64, 64);
}
}
You don't want to extend but just load the bitmap/spritesheet into a FlxSprite? Not much of a difference:
var block = new FlxSprite();
block.loadGraphic("assets/images/block.png");
add(block);
See also:
http://haxecoder.com/post.php?id=52
http://haxeflixel.com/documentation/flxsprite/
http://haxeflixel.com/documentation/tutorial/ (it's excellent!)

Actionscript 3 getDefinitionByName not seeing classes

I've worked around this with a hack for now, but would rather know if there's a right way to do it. I have a function that churns out MovieClips, which are tiles for a map that I then attach to the stage. It determines which class of tile to use based on a string variable, like this:
// symbolID holds our class name, determined by logic above
var newClass:Class = getDefinitionByName(symbolID) as Class;
var newtile:MovieClip = new newClass();
This works, but only if an instance of the class already exists somewhere else in the code. It could be anywhere-- in the document class, in some buried function of a helper class, it doesn't seem to matter. If not, Flashdevelop throws error 1065, "Variable (the variable) is not defined". I mention that I'm using Flashdevelop because it seems like it might be compiler-specific, but I'm not sure.
My hack fix is to do this:
var a:baseTile;
a as anotherTile;
a as aThirdTile;
and so on, which works, but definitely isn't ideal if I'm going to have hundreds of these tile classes eventually.
Edit: I should add that these movieclips are coming from a .swc file, which comes from Flash Professional.
You have to use the 'hack'.
getDefinitionByName() can only work with classes that exist at runtime. Unfortunately, if you don't make use of a class, it won't be compiled and won't exist at runtime.
Library symbols make getting around this a little easier. If you check the box that has them available automatically at a given frame, you can just make sure your getDefinitionByName() calls are done during or after that frame.
While SWC libraries can include specific classes to include in the build path, Flash compiler will not link unreferenced classes to a SWF; therefore, requires a linkage library.
Example linkage to retain classes:
/** linkage library */
private static const classA:ClassA;
private static const classB:ClassB;
private static const classC:ClassC;
Another option would be to load the classes from a RSL (Runtime Shared Library).
Basically yes, you need to have a strict reference of that class somewhere in your code. You can even make that reference "unreferenced" elsewhere. I have a hundred of classes like this, and I had to make a single Array of these classes, located somewhere inside the project. I have placed it aside the function that calls getDefinitionByName() to make sure the classes are available in that function.
private static const dummy:Array=[Rock01, Rock02,...,Gem01,Gem02,...];
So you can use such an Array listing all your tiles that you have in your project and want to be accessible by getDefinitionByName().

FlashBuilder: how to embed graphics for preloader?

I develop a project in FlashBuilder. The graphics and UI elements i create in the Flash IDE and give them Export Classnames. then I put the SWC in the library paths of the FlashBuilder project and create the UI elements by instanciation.
Now I want to add a Preloader for the application. I follow this article, which works:
http://pixelpaton.com/?p=4642
My question is now: I also need some graphics for the preloader. But how do I ensure that the graphics for the preloader will be loaded first, such that the preloader class can start as soon as possible?
The compiler will figure out the dependencies for your preloader class, and load them first.
For example:
public function Preloader()
{
addChild(new UIElementFromFlash());
}
Flash Builder will know UIElementFromFlash needs to be loaded before Preloader. It will also load Preloader before your main class and its dependencies as long as you have the Frame metadata tag from the article.
I'd suggest to make 2 swf files if it's possible. Make a loader.swf which loads your application swf and displays the progress and your loading animation/graphics.
See an example here: http://www.republicofcode.com/tutorials/flash/as3preloader/
Then you'll have to add URLLoader class and load your application.swf.
Try looking here: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/URLLoader.html
Like Gio suggested, having two SWF files is the best practice.
However, one other solution is to use the -frame two argument of the Flex compiler. All your definitions (code and assets) will be added to the second frame of the movie, allowing your main class to listen for the loading progress of the application and display animations.
Be careful to not reference anything from the main application in your first frame, to prevent adding more weight to it.
More detail on this technique here:
http://www.andymoore.ca/2009/08/flexsdk-3-3-how-to-make-a-flash-preloader-in-as3/

Is it possible to extract the symbol out of swf file which was downloaded using URLLoader (and not embedded))

I am trying to download a heavy swf dynamically to my site using URLLoader class. I'd like to know if it is possible to use a symbol inside the swf as a separate object?
The code used right now uses the embed statement as follows:
[Embed(source="/Fight.swf", symbol="Kungfu")]
public class Kungfu extends MovieClip
{ ... }
Embedding the swf increases the initial load time of my site and I want to make it dynamic. How can I access the Kungfu symbol from Fight.swf after it is downloaded using the URLLoader class?
You need to get the class definition from the loaded SWF. Few months ago I summarized the process here. The example used bitmaps, but you can use movie clips as well.
... Why not use SwfLoader? It's Flex native. If you're not in Flex, why not use a Loader?
Either way, I don't think that URLLoader is what you really want here.

What is the correct way to add components to the library of a Swf?

I've been having a problem that's plagued me many times in the course of developing a Flash project. It looks something like this:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at fl.containers::BaseScrollPane/fl.containers:BaseScrollPane::drawBackground()
at fl.controls::TileList/fl.controls:TileList::draw()
at fl.core::UIComponent/::callLaterDispatcher()
TypeError: Error #2007: Parameter child must be non-null.
at flash.display::DisplayObjectContainer/addChildAt()
at fl.controls::BaseButton/fl.controls:BaseButton::drawBackground()
at fl.controls::BaseButton/fl.controls:BaseButton::draw()
at fl.core::UIComponent/drawNow()
at fl.controls::ScrollBar/fl.controls:ScrollBar::draw()
at fl.core::UIComponent/::callLaterDispatcher()
Now, in my case, this error stems from initializing components in code when they have not been explicitly added to the fla's component library in CS4. In the past, I have run into this issue when trying to dynamically create ScrollPanes in code. I have solved it by adding ScrollPane components to my Main.fla's library. This seemed to work for a while.
Now, I am trying to use an AstraFlash AutoComplete box. I have imported the proper fla files into CS4, and placed an AutoComplete box into my Swf. Everything builds fine, but the above error occurs when the Swf is loaded. My thought is that the AutoComplete box is trying to create a ScrollPane as part of its functionality. Ok, I understand this, so I add the ScrollPane component to the library as well with the same results.
Usually I would just mess with the library components/settings until I get rid of the error, but I'm sick of running into this, and I want to know the correct way to solve the problem. So, here are a few questions I have:
When are you required to add a component to a Fla's library rather than just creating the component in code?
Which Flas do you need to add the component to? Just the one using it? Or all of parents of that Fla as well?
Let's say the Autocomplete component requires a ScrollPane component. Why isn't this dependency recognized when I add the one component? Why must I explicitly add it?
What is the difference between adding a component to the library, and adding it to the library's 'Component Assets' folder? What is this folder's purpose?
I really need this AutoComplete component to work. Assuming the AS3 code is correct, and I am still getting the above error, what settings do you think are probably incorrect? Out of frustration, I have tried adding every possible component to the library, as well as to the library's component assets folder just to have a starting point, but I still get the error.
Any help is appreciated.
I'm not sure I understand you're setup. What I'm assuming is you have a child fla that contains some components and you need to create instances of those components in a parent(loader) fla.
It should work if you compile the classes from the child fla into the parent fla, but that would duplicate things.
The issue is when you load a swf, the classes sit in a different ApplicationDomain.
Simply put, that's the thing that manages classes in a swf so you don't have class collisions between a loader and loaded swf and some other security stuff.
I made a simple fla that holds a Button component(fl.controls.Button) and loaded that from a loader fla. I didn't add the Button component to the loader fla, but did create a button instance, using the loaded swf's application domain. Here's how:
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaded);
loader.load(new URLRequest('componentContainer.swf'));
function loaded(event:Event):void {
addChild(loader.content);
var SWFButton:Class = loader.contentLoaderInfo.applicationDomain.getDefinition('fl.controls.Button') as Class;
var button = new SWFButton();
button.label = 'Test';
addChild(button);
}
There is a page in Programming Actionscript 3.0 about thise kind of issues and how to use ApplicationDomain, but I didn't fully understand it to be honest.
HTH,
George