Is it possible to create dynamic embed function? - actionscript-3

Is it possible to create dynamic embed function in ActionScript3
for example like this
public function embedImage(path:String):Bitmap{
[Embed(source = path, mimeType = "image/png")]
var NewBitmapClass:Class;
var image:Bitmap=new NewBitmapClass();
return image;
}// tried it, it doesnt work
or maybe in some other way, or even if it is at all possible?

The closest you can get with the "dynamic" part, is to create a wrapper class, where you define your images, and you can get them as Bitmap later on by an id.
Unfortunately the properties are public, otherwise the hasOwnProperty function doesn't return true. (If someone finds a better way, please let me know)
See below:
package {
import flash.display.Bitmap;
public class DynamicEmbed {
[Embed(source = "../images/cat.jpg")]
public var cat : Class;
[Embed(source = "../images/parrot.jpg")]
public var parrot : Class;
[Embed(source = "../images/pig.jpg")]
public var pig : Class;
[Embed(source = "../images/quail.jpg")]
public var quail : Class;
public function DynamicEmbed() {
}
public function getBitmap(id : String) : Bitmap {
if(hasOwnProperty(id)) {
var bitmap : Bitmap = new this[id]();
return bitmap;
}
return null;
}
}
}

Embedded elements are embedded at compile time. You can't dynamically embed something at compile time... If you want to load resources dynamically, use the Loader.

No, embed source is embedded at compile time. You can not embed anything at run time. That's what embed means, embedding during building the swf.

Related

as3 Call function in document class from child swf

I have a loader swf acting as the main swf that is responsible for loading and rendering external swf's.
In the document class of the loader swf, I have a function named test.
public function test() {
ExternalInterface.call("console.log", "Test");
}
I want to call this function from the child swf that is being loaded in using an external class known as StateManager. A new instance of the StateManager class is being created in the document class of the loader swf as can be seen below.
import com.xxxx.state.StateManager;
public class Loader extends MovieClip {
private static var _instance:Loader;
public static function get instance() { return _instance; }
public var stateManager = new StateManager();
// Other code has been ommited obviously.
}
A function is then called in StateManager which renders the new swf.
public function setActiveState(url) {
var request = new URLRequest(url);
var loader = new Loader();
loader.load(request);
addChild(loader);
}
In the child swf's document class, I have attempted to call the loader swf's test function using many different methods, all of which have resulted in nothing happening and no error being produced (I have confirmed that the child swf is rendering properly). I have tried using the following code.
public class ChildSWF extends MovieClip {
public function ChildSWF() {
MovieClip(parent.parent).Loader.instance.test();
}
}
As well as
public class ChildSWF extends MovieClip {
public function ChildSWF() {
MovieClip(parent.parent.parent).Loader.instance.test();
}
}
and many other pieces of code that I have seen when researching this problem. If anyone could help, that would be greatly appreciated.
First. Never, absolutely never name your classes as the already existing classes. You're, like, welcoming future troubles with the huge neon WELCOME display with the occasional firework blasts in the background.
Then. Your class Loader is not a member (nor a variable) of any display object and just cannot be accessed the way you try it. Classes do not work like that. They are definitions of the ApplicationDomain. You might want to find and read about it: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/system/ApplicationDomain.html#getDefinition()
The rest is pretty simple.
public var callBack:Function;
public function setActiveState(url, handler)
{
callBack = handler;
var request = new URLRequest(url);
var loader = new Loader;
loader.load(request);
addChild(loader);
}
Then in the loaded content:
public class ChildSWF extends MovieClip
{
public function ChildSWF()
{
(parent.parent as Object).callBack();
}
}
The loaded content will call whatever method reference you will have in the callBack variable;

ActionScript 3 not showing jpg

Im working with Starling and im trying to show a jpg on my background, but it doesnt shows up. Here is the embed code:
[Embed(source="../media/img/backgroundmenu.jpg")]
public static const BgWelcome:Class;
Later on I cast it into a bitmap and make it a texture. Im getting the following error at the getter of the bitmap:
ReferenceError: Error #1069: Property metaData not found on resources.Assets_BgWelcome and there is no default value.
The jpg is at the exact folder, tried to place it with the absolute path, but nothing apears.
Thanks in advance.
Here's a nice way to go about creating a convenient container for all your graphics using starling:
public class Art {
[Embed(source = "../textures/foo.jpg")] private static const FooBitmap:Class;
public static var FooTexture:Texture = MakeTexture(FooBitmap);
private static function MakeTexture(_Texture:Class):Texture {
var bitmap:Bitmap = new _Texture();
return Texture.fromBitmap(bitmap);
}
}
Usage:
var foo:Image = new Image(Art.FooTexture);

AS3 Starling Framework Texture Atlas TypeError #1007

I'm new to the starling framework and am currently learning how to use it.
I've created textures from embedded PNG files with the starling framework that work perfectly and display on the screen, but I am trying to get a spritesheet (Texture Atlas) to work and it is giving me this:
"Error #1007: Instantiation attempted on a non-constructor."
From all of the research I have done the code I have should work.
Here is the applicable code from my Assets class.
public class Assets
{
[Embed(source="assets/sky.png")]
private static var SKY_CLASS:Class;
public static var SKY:Texture;
[embed(source="assets/generalsheet.png")]
private static var GENERAL_SHEET_CLASS:Class;
[embed(source="assets/generalsheet.xml", mimeType="application/octet-stream")]
private static var GENERAL_ATLAS_CLASS:Class;
public static var GENERAL_SHEET:TextureAtlas;
public static function init():void
{
SKY = Texture.fromBitmap(new SKY_CLASS());
GENERAL_SHEET = new TextureAtlas(Texture.fromBitmap(new GENERAL_SHEET_CLASS()), XML(new GENERAL_ATLAS_CLASS())); // this is where Flash Builder tells me there is an error
}
You just need to write the Embed tag in upper case, just change:
[embed(source="assets/generalsheet.png")]
private static var GENERAL_SHEET_CLASS:Class;
[embed(source="assets/generalsheet.xml", mimeType="application/octet-stream")]
private static var GENERAL_ATLAS_CLASS:Class;
to:
[Embed(source="assets/generalsheet.png")]
private static var GENERAL_SHEET_CLASS:Class;
[Embed(source="assets/generalsheet.xml", mimeType="application/octet-stream")]
private static var GENERAL_ATLAS_CLASS:Class;
On a side note, class names are usually written in UpperCamelCase, and ALL_CAPITALIZED is reserved for constants. Variable names are usually written in lowerCamelCase or lowercase_separated_by_underscore. This is a convention followed by most ActionScript3 (and Java) programmers and if you stick to it your code will be more readable and thus it should be easier to help you next time ;)
So I recommend:
[Embed(source="assets/sky.png")]
private static var SkyClass:Class;
public static var sky:Texture;
[Embed(source="assets/generalsheet.png")]
private static var GeneralSheetClass:Class;
[Embed(source="assets/generalsheet.xml", mimeType="application/octet-stream")]
private static var GeneralAtlasClass:Class;
public static var general_sheet;
public static function init():void
{
sky = Texture.fromBitmap(new SkyClass());
general_sheet = new TextureAtlas(Texture.fromBitmap(new GeneralSheetClass()), XML(new GeneralAtlasClass()));
}

I Want Access To a Public Static Const in my Actionscript Without Instantiating an Object... Is That Possible?

I've got a static property I would like to access by importing it's class without instantiating an object of that class. Is this possible?
Essentially I'm writing a bunch of styleSheet Objects over and over. I figure If I have a class called CSS and like this:
package com
{
import flash.text.*;
public class CSS
{
public static var STYLE_SHEET:StyleSheet = new StyleSheet();
and assign all of it's properties in the constructor like:
public function CSS
{
//NAV BUTTON
var navButtonBlock:Object = new Object();
navButtonBlock.color = "#000000";
navButtonBlock.fontSize = "25";
navButtonBlock.fontFamily = "Arial";
navButtonBlock.marginLeft = "5";
navButtonBlock.kerning = "true";
navButtonBlock.fontWeight = "bold";
//TITLE
var titleBlock:Object = new Object();
titleBlock.color = "#CCCCCC";
titleBlock.fontSize = "25";
titleBlock.fontFamily = "Arial";
titleBlock.marginLeft = "5";
titleBlock.kerning = "true";
titleBlock.fontWeight = "bold";
STYLE_SHEET.setStyle("code", titleBlock);
STYLE_SHEET.setStyle("navButton", navButtonBlock);
}
If I import the class into the class I wish to make use of it like:
package{
import com.CSS;
and inside my class use the variable like:
textField.styleSheet = CSS.STYLE_SHEET;
I can save some headaches.
The thing I find weird is that I have create an instance of that class to access it's const. So in the class header I have to write:
private var css:CSS = new CSS();
even though I never end up making use of this object...
Does this make sense? Am I going about this the wrong way?
-J
p.s. Who wishes the tab key worked in this question editor window?
You can write static init() function, which you will have call only once or you can use "static initializers":
package com
{
import flash.text.*;
public class CSS
{
public static var STYLE_SHEET:StyleSheet = new StyleSheet();
// Static init block
// This block is run once when the class is first accessed
{
var navButtonBlock:Object = new Object();
/*...*/
var titleBlock:Object = new Object();
/*...*/
STYLE_SHEET.setStyle("code", titleBlock);
STYLE_SHEET.setStyle("navButton", navButtonBlock);
}
}
}
Now import class and just use static var STYLE_SHEET
import com.CSS;
...
textField.styleSheet = CSS.STYLE_SHEET;
You don't have to make an instance of the class to ACCESS its static members, but you are initiating your static variable inside the classes constructor.
This mean that at the time you access the static variable like this:
textField.styleSheet = CSS.STYLE_SHEET;
The STYLE_SHEET property is not set yet!
Usually the way to get around this kind of thing is to have an "init" static method.
CSS.init();
The init method would set STYLE_SHEET, like you have done in your constructor.
This does mean that in you application you will have to call CSS.init() once before you use STYLE_SHEET anywhere else.
ALSO:
What you refer to as a "const", is not a const at all. It is just a static. Const means the value is constant (never changes).
Thanks to both ivann and TandemAdam for leading me down the right path. Ultimately I figured out that first, the reason I had to instantiate an instance of my class is because I was defining my variables properties in the constructor function. So I built a static constructor function which eliminated the need to instantiate, but I still had to call the function (rather than just import).
Then, ivann pointed out, I don't need to call the function at all If I just build a static init() function. Awesome idea except missing one bit of information. You cannot declare variables in a static initializer. So, the ultimate solution was to call my private static function that CAN declare variables from my static initilaizer function.
example:
package com.atJascha
{
import flash.text.*;
public class CSS
{
public static var STYLE_SHEET:StyleSheet = new StyleSheet();
{
init();
}
private static function init()
{
//NAV BUTTON
var navButtonBlock:Object = new Object();
navButtonBlock.color = "#FFFFFF";
//TITLE
var titleBlock:Object = new Object();
titleBlock.color = "#00FFFF";
STYLE_SHEET.setStyle("navButton", navButtonBlock);
STYLE_SHEET.setStyle("title", titleBlock);
}
}
}

custom AS3 Loader class that uses a custom LoaderInfo class?

This is a question specifically about creating a custom Loader class as a followup to How do I modify existing AS3 events so that I can pass data?. If this wasn't the right way to go about this, let me know.
I have a custom Loader class and a custom LoaderInfo class. What I can't figure out is how to have the Loader class use the custom LoaderInfo class as it's contentLoaderInfo property.
package com.display {
import flash.display.Loader;
import com.display.CustomLoaderInfo;
public class CustomLoader extends Loader {
public var customData:*;
public function CustomLoader(passedData: *= null) {
customData = passedData;
}
}
}
^ Have to do something in there to make it have the new CustomLoaderInfo
package com.display {
import flash.display.LoaderInfo;
import flash.events.Event;
import com.events.CustomEvent;
public class CustomLoaderInfo extends LoaderInfo {
public var customData:*;
public function CustomLoaderInfo(passedData: *= null) {
customData = passedData;
}
override public function dispatchEvent(event:Event):Boolean {
var customEvent:CustomEvent = new CustomEvent(event.type, customData, event.bubbles, event.cancelable);
return super.dispatchEvent(customEvent);
}
}
}
^ That might work, but since I can't get CustomLoader to use it, I don't know yet.
I don't know how it fits into what you're doing, but you could not bother making an extended LoaderInfo at all. Loader.contentLoaderInfo has a property called loader that will return the Loader (or in this case CustomLoader) that was used. In theory you can just do this with the CustomLoader class that you have:
var loader: CustomLoader = new CustomLoader("Extra Data");
loader.load(new URLRequest("file.swf"));
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderComplete);
function loaderComplete(event: Event) : void
{
var customData:* = (event.target.loader as CustomLoader).customData;
trace(customData); // Extra Data
}
You would have to override the function where the loaderinfo instance is created, and that might be in a private function. In the new function you could then instanciate your custom loaderInfo class instead, but you would also have to do anything else that the overwritten method does. You might run into some security sandbox problems with loadinfo as well. Overwriting a function like this is usually only posible when the function written with this in mind.
Alternatively you could use the prototype chain (read here) to change the loaderInfo class at runtime. But I wouldn't recommend it. It's not good practice in my opinion.
If you get this to work you still have the problem that your custom event will not work with any event that has properties not inheritet from the Event class (like the ProgressEvent that has progress related properties).
I would say you properly should look for another solution.
In the question you link to you talk about sending movieclip with your event. Have you thought about reaching the other way? When you recieve the event, you get a reference to the object that dispatched it (Event.target). Can you not use that reference to get the movieclip?
Perhaps you could explain your problem in more detail (maybe in a new question so you still keep this open), I am sure there is a better / easier way to solve it.
I needed something like this because I wanted to carry an index with the info ... ie - have something like event.target.index available after an event is triggered .. anyway i designed a class that contained the loader and the loader info... heres the class
public class LoaderBox extends Sprite {
public static var PROGRESS:String = "progress"
public static var COMPLETE:String = "complete"
public var id:int
public var index:int
public var loader:Loader
public var info:LoaderInfo
public var isOpen:Boolean
//
public var percent:Number = -1
public function load(path:String,idx:int=-1,nm:String=null){
loader = new Loader()
if (nm != null){
name = nm
}
index = idx
var req:URLRequest = new URLRequest(path)
info = loader.contentLoaderInfo
info.addEventListener(Event.COMPLETE,complete)
info.addEventListener(ProgressEvent.PROGRESS,progress)
isOpen = true
loader.load(req)
}
private function complete(e:Event):void{
isOpen = false
dispatchEvent(new Event(LoaderBox.COMPLETE))
}
private function progress(e:ProgressEvent):void{
if (e.target.bytesTotal>0){
percent = Math.floor(e.target.bytesLoaded/e.target.bytesTotal * 100)
}
dispatchEvent(new Event(LoaderBox.PROGRESS))
}
}
A potential issue with the flagged answer: if contentLoaderInfo spits out a IOError, you can't access the .loader property to access your custom loader class.
What I did is the following:
* in my custom loader class, create the following method:
public function requestError(event:Event):void {
dispatchEvent(event);
}
when adding a listener to contentLoaderInfo for the IOerror, point to the custom loader class's method:
_loaderCls.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, _loaderCls.requestError);
Then, add the same listener to your loader class and make it call any method you need. At that point, the event.target would be that of your custom loader class and you can add any extra info you need to that class:
_loaderCls.addEventListener(IOErrorEvent.IO_ERROR, requestError);
or you can do a better thing to pass data into the Loader class:
package com.display
{
import flash.display.Loader;
public class Loader extends flash.display.Loader
{
private var _obj:Object;
public function Loader():void
{
super();
}
public function get obj():Object
{
return _obj;
}
public function set obj(o:Object):void
{
_obj = o;
}
}
}