Actionscript 3 getDefinitionByName not seeing classes - actionscript-3

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().

Related

Need some help getting started with OOD in ActionScript 3

So being new to AS3 but not development in general, during a recent project that I just started I hit an immediate snag where my normal method of OOD is causing errors in AS3.
I created a layer in Adobe Flash called code just to keep everything separate and in frame one under actions I used the following code to get started:
var GameContainerSize:int = 400;
class GameInfo {
var GameID:int;
var HomeTeam:String;
var VisitingTeam:String;
function GameInfo()
{
}
}
This simple code immediately causes an error though
Scene 1, Layer 'Code', Frame 1, Line 4 1131: Classes must not be nested.
And my best guess is this is because the timeline and all code on it exists within a class already. So what should I be doing if I want to develop this program using class objects, or is this even possible in flash?
You can't define classes on the timeline. Each timeline is exported as a class, var and function declarations become members of the class, and frame code is moved to its own frame functions which are called when the timeline reaches that frame. Thus the error is saying "you can't put a class in a class" because the timeline already is a class.
To define classes you must use external .as files with package blocks:
// GameInfo.as
package {
public class GameInfo {
public var GameID:int;
public var HomeTeam:String;
public var VisitingTeam:String;
public function GameInfo(){ }
}
}
In Flash Pro you can link a class to a timeline (document or symbols). Such a class must extend Sprite or MovieClip.
You can also refer to any of your classes from any frame script. For example, you could put on frame 1 of your main timeline:
var gameInfo:GameInfo = new GameInfo();
Typical OOP would involve using external .as class files for almost everything, with only minimal function calls on your timeline frames, like stop() at the end of a timeline or calling a custom function you've added to the class linked to the timeline.
I created a layer
That's not ideal. The problem is that it will not get you any closer to understanding the code, because it isn't code. It's a feature of the flash authoring environment. You might as well spend a day with the drawing tool drawing something.
to keep everything separate and in frame one under actions
Organisation is important, but layers aren't the way to go. As each class definition goes into its own external file, you have to create additional files anyway if you want to create more classes. And you want to create more classes because having only one is horrible object oriented design. Being consistent here is important. That's why people in the comments suggested to use a document class and have no code on any frames. All code is organised in classes. No exceptions1.
Having said all that, I highly advice against using Adobe Flash to learn As3. There's too much obfuscation going on behind the scenes. If you want to learn how to code As3, use a code editor. (or plain text editor + compiler if you prefer). Learning what settings dialog has to be adjusted in order to get what you want is not going to get you any closer to understanding OOD in As3.
I also see package, is this kind of like a namespace and does it need to be named, if not what is its purpose?
No, packages are packages and namespaces are namespaces. Apples and oranges.
Packages are used to organize classes just like a structure of
folders is used to organize the .as fiels of those classes. In fact,
the package is pretty much exactly that folder structure, for example:
flash.display is for all display related classes
flash.events is for events
A namespace allows you to control access to members of a class. Namespaces are very rarely used in As3. Here's an article from grant skinner about namespaces. Personally, I never needed to use namespaces. If you are jsut getting started, you can very well ignore them for now.
That sounds perfect! except I cannot get it to launch on my Win10 machine. I may just end up outsourcing this at this ratio
flash develop is the alternative editor. It's free, fast and lightweight.
my normal method of OOD
You want to extend your definition of normal with
always explicitly specify the access control modifiers
member names start with small letters
public class GameInfo {
private var gameID:int;
private var homeTeam:String;
private var visitingTeam:String;
function GameInfo()
{
}
}
1admittedly, there are top level functions that are pretty much free floating functions without a class. If you want to do oop, this is not what you want. It's for the occasional independent utility function. Stick to classes for now.

How to extend class that is inside a loaded swf

I've got an swf loaded externally to my app with loader component. It is loaded to the Application Domain of my loader. I've got a class in that swf wich I would like to extend and override some functions from it. Is it possible somehow?
Here is some code to explain what I want(of course, it is fully incorrect and wold not work):
public var ClassFromLoadedSwf:Class = ApplicationDomain.currentDomain.getDefinition("path.to.needed.class") as Class;
public class MyClass extends ClassFromLoadedSwf
{
override protected function initMovie() : void
{
//function logic goes here
}
}
Thank you for your answers and sorry for my bad english.
No you can't. Basically you don't understand the meaning of ApplicationDomain. Using a loader and Applicaiton Domain you just merge some code to your SWF in Runtime. Before it reaches the Runtime state, it can't be accessed. So at the Compile time you can't do what you're trying to do now. But you can try to use SWC instead of SWF. You just include it in your Project Library and that's all. You'll be able to access all the classes at compile time. Try reading this Article. It will help you understand the meaning of SWCs.

Link symbol from loaded swf to custom class dynamically

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.

What is the data type from the source of an image

another flashbuilder brainbreaker for me...
I have a class with a contstructor that should only change the source of an image.
[Bindable]
[Embed(source='../pictures/test.jpg')]
private var _picture:Class;
public function Test(newSource:*****)
{
_picture.source = newSource;
}
(the image is not an image, but a class, I am aware of this, it is meant to be so :-) )
The problem is that when I call the constructor, let's say:
var test:Test = new Test(pictureAtStage.source);
Flashbuilder will give an error, becouse I can't tell the compiler what data type "newSource" at the constructor will have...
*edit:
When i use _picture.source, the embedded source does not seem to be changed...?
Anyone knows an answer?
Are we talking about mx.controls.Image? if so, then the source of an image can be: a Class, a Bitmap (not a BitmapData), a String (in which case it is assumed that you wanted to load it instead of using an embedded one). If you want to find a common denominator for all these, then Object is that class, however, I would rather limit it to something particular to your use case.
However, if I may advise anything... don't use mx.controls.Image, it's too bloated, even for Flex framework. If it must be a UIComponent - extend UIComponent and let the source be of type BitmapData - this way you will be able to manage resources better - you could reuse the same actual image for example. You could then use graphics property of the control to display the image.
Another advise, if you are still here :) Don't use [Bindable], especially the short version of it, especially not on a private variable - you will save yourself the frustration of countless hours of debugging it... Besides, in your case you aren't going to change the value of that variable anyway...
Are you still here? Well, don't use [Embed] on variables, use it on class definition - slightly more work for you, but this will, potentially, make your code more portable. If you embed on class the compiler will not generate a silly "something-something-Asset" class, it will use Bitmap or BitmapData - whichever your class extends. Thus, you will not introduce a dependency on Flex framework, and, in general, you will have more control over your code.
EDIT: the above was written assuming that _picture (class) variable and _picture (some variable used in a function) are not the same thing. But if they are the same thing, then Class class is dynamic, which means that you can add to it properties at runtime (don't know why, it's a design decision by Adobe...), however, the compiler will act as if it's not possible, so you would work around that by adding the property through reflection:
var _picture:Class = Sprite;
_picture["source"] = whatever;
trace(Sprite["source"]);
This is indeed slightly confusing, It will be of the type BitmapAsset which extends Bitmap. So any of those will work.
Since I'm very new to flashbuilder I didn't see the obvious solutions...
The solution for the first part of my question (before the edit):
Setting the data type to Object did the trick:
[Bindable]
[Embed(source='../pictures/test.jpg')]
private var _picture:Class;
public function Test(newSource:Object)
{
_pucture.source = newSource;
}

Better way to include images in AS3 than embed?

I am putting together a Flash game (using Flixel) and I have a lot of sprites whose images (.png format, mostly) I need to include in my game. I'm used to using code like:
[Embed(source = "../../lib/ship-0001.png")]private var _ship0001Sprite:Class;
in order to include an image file. Is there a way I can do this other than embed? I'd like to use a for loop if possible, grabbing every needed file by number. This way instead if having several lines for each ship type (to grab its sprite, icon, store view, etc), I can just change a variable (eg NUM_SHIP_TYPES) and add the files by number for the new ship.
Is embed the only way to do this where the files are included in the .swf, or is there another way I can do this? Or is there a way I can use a for loop with embed?
This may not be a popular answer. But it depends on preferences. I'm not trying to start a best practices discussion, just listing a possibility.
If you have multiple images for each ship. And its the same number of images per each ships then the below could be a possibility. Of not, then completely ignore what I suggest.
Have a folder for each one of your ship types and then a class file within that folder and place your images within that folder along side the class files..
package shipimages.ship1 { class Ship1Images {
[Embed(source="0001.png")] public var img0001:Class;
[Embed(source="0002.png")] public var img0002:Class;
[Embed(source="0003.png")] public var img0003:Class;
} }
.
package shipimages.ship2 { class Ship2Images {
[Embed(source="0001.png")] public var img0001:Class;
[Embed(source="0002.png")] public var img0002:Class;
[Embed(source="0003.png")] public var img0003:Class;
} }
But as I said, this is only beneficial in a small case scenarios but it does mean everything is more sub divided and if you were to make an Interface it could be easily done for factory pattern.
If you have lots of assets, the best way is to leave them as external files and use Loader to load them.
That way you can display a progress bar and, as you said, it also makes it easier to manage your assets.
Do you want to have the objects readily available within the same swf or do you want to load them externally. Would be the first question, that comes to my mind.
If you want to embedd images inside the swf : Add them all in an fla, create a swc from it and use them in your project. When you want to change something, change the fla. Regenerate the swc. Recompile.
If you want the images to be loaded on runtime, use UrlLoader, personally I prefer using LoaderMax, which is part of the greensock package. It gives you more options to work with loading. Here is an example to help you out : http://www.greensock.com/loadermax-tips/