How to embed MultiDPIBitmapSource objects in Flex library project - actionscript-3

I currently store embedded images in a flex library project (swc) like so:
public class BitmapAssets
{
[Embed(source="/assets/icon_160.png")]
public static const icon_160:Class;
[Embed(source="/assets/icon_240.png")]
public static const icon_240:Class;
[Embed(source="/assets/icon_240.png")]
public static const icon_240:Class;
}
And then i reference the images in other projects. For example:
<s:Button>
<s:icon>
<s:MultiDPIBitmapSource source160dpi="{BitmapAssets.icon160}"
source240dpi="{BitmapAssets.icon240}"
source320dpi="{BitmapAssets.icon320}" />
</s:icon>
</s:Button>
What i would like to do is embed the MultiDPIBitmapSource in the library project; then i could reduce the code to this:
<s:Button icon="{MultiDPIBitmapAssets.icon}" />
However, i can't figure out how to embed a MultiDPIBitmapSource object with source160/240/320 values filled.
Any solutions gratefully received ;)
Edit:
As an alternative to 'true' embedding, i'm wondering whether mxml compiling could provide an answer. For instance, if i have an mxml declaration:
<fx:declarations>
<s:MultiDPIBitmapSource id="icon"
source160dpi="{BitmapAssets.icon160}"
source240dpi="{BitmapAssets.icon240}"
source320dpi="{BitmapAssets.icon320}" />
</fx:declarations>
Then the mxml compiler will turn it into:
var icon:MultiDPIBitmapSource = new MultiDPIBitmapSource();
icon.source160dpi = BitmapAssets.icon160;
icon.source240dpi = BitmapAssets.icon240;
icon.source320dpi = BitmapAssets.icon320;
And i can then reference it as i'd like:
<s:Button icon="{MultiDPIBitmapAssets.icon}" />
Technically, its not embedded. But for practical purposes, it is (at least in my mind). The question is, where do i put the declarations tag? Can i define a non-visual class in mxml?

MultiDPIBitmapSource is an object created at runtime, not at compile-time. You won't be able to embed an instance of it in the app.
However, you could create a static reference to an object. It would require a bit more code, but it would be less code to write every time you need to use it.
public class Assets {
private static var _asset:MultiDPIBitmapSource;
public static function get asset():MultiDPIBitmapSource {
if ( !_assets ) {
_assets = new MultiDPIBitmapSource();
_assets.source160 = "url";
_assets.source240 = "url";
_assets.source320 = "url";
_assets.source480 = "url";
}
return _assets;
}
}
And then to use it:
<s:Button icon="{Assets.asset}"/>
So it basically treats the source as a mini-Singleton. I'm personally not a fan of this method. The only gain you get is slightly less code in each class, but you lose flexibility and it goes against general OOP practices. But it should work.

Related

ActionScript: making a variable `[Bindable]` causes crashes

I have this singleton that I'm using as a wrapper for global variables and constants, but as soon as I make some [Bindable] I get a crash on start up w/a bunch of red text in my console.
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at BrandGlobals$/get COLOUR_EVERYTHING_BACKGROUND()[C:\MyProject\src\BrandGlobals.as:14]
at BrandGlobals$cinit()
at global$init()[C:\MyProject\src\BrandGlobals.as:2]
at _mainWatcherSetupUtil/setup()
at main/initialize()[C:\MyProject\src\main.mxml:0]
at mx.managers::SystemManager/http://www.adobe.com/2006/flex/mx/internal::childAdded()[C:\autobuild\3.5.0\frameworks\projects\framework\src\mx\managers\SystemManager.as:2131]
at mx.managers::SystemManager/initializeTopLevelWindow()[C:\autobuild\3.5.0\frameworks\projects\framework\src\mx\managers\SystemManager.as:3400]
at mx.managers::SystemManager/http://www.adobe.com/2006/flex/mx/internal::docFrameHandler()[C:\autobuild\3.5.0\frameworks\projects\framework\src\mx\managers\SystemManager.as:3223]
at mx.managers::SystemManager/docFrameListener()[C:\autobuild\3.5.0\frameworks\projects\framework\src\mx\managers\SystemManager.as:3069]
BrandGlobals:
package {
public final class BrandGlobals {
[Bindable]public static var COLOUR_EVERYTHING_BACKGROUND:uint = 0xE010FF;
If I remove that [Bindable] and turn var to const there's no problem (except the obvious problem of not being able to set the variable outside of this file) but this doesn't work. Also, making the whole class [Bindable] instead of this one didn't work. When I hover my mouse over the COLOUR_EVERYTHING_BACKGROUND definition, it says "<exception thrown by getter>". 'Don't know what to think about that.
I might have guessed it was because it has no package, but I'm using another similar singleton which has [Bindable] variables and seems to work fine.
I never did get that [Bindable] twaddle.
I'm using the Flex 3.5 SDK.
I tried Brian's suggestion below, but it gave me pretty much the same error. I even tried:
{
_COLOUR_EVERYTHING_BACKGROUND = 0xE010FF;
trace("Var set."); //Breakpoint here
bLoadedFerCryinOutLoud = true;
}
[Bindable]private static var _COLOUR_EVERYTHING_BACKGROUND:uint;
private static var bLoadedFerCryinOutLoud:Boolean = false;
public static function get COLOUR_EVERYTHING_BACKGROUND():uint {
trace("Returning EVERYTHING background");
if (bLoadedFerCryinOutLoud)
return _COLOUR_EVERYTHING_BACKGROUND;
else return 0xFFFFFF;
}
What's more, if I put a breakpoint at that trace("Var set.");, Flash Builder complains that a break is not possible, because there is no executable code there.
I also noticed that in that call stack that I'm shown when this crash happens during a set and it seems to be the one that sets _COLOUR_EVERYTHING_BACKGROUND. But the only place where it is set is:
public static function SetBackground(oApp:UBIApplication):void {
_COLOUR_EVERYTHING_BACKGROUND = oApp.nBackgroundColour;
}
and breakpoints indicate that this is never called.
The documentation on using the tag has the following to say:
Using static properties as the source for data binding
You can use a static variable as the source for a data-binding expression. Flex performs the data binding once when the application starts, and again when the property changes.
You can automatically use a static constant as the source for a data-binding expression. Flex performs the data binding once when the application starts. Because the data binding occurs only once at application start up, you omit the [Bindable] metadata tag for the static constant. The following example uses a static constant as the source for a data-binding expression:
<fx:Script>
<![CDATA[
// This syntax casues a compiler error.
// [Bindable]
// public static var varString:String="A static var.";
public static const constString:String="A static const.";
]]>
</fx:Script>
<!-- This binding occurs once at application startup. -->
<s:Button label="{constString}"/>
Edit: You need to make sure that your variable is initialized before you try to read it. A static initializer is the way to go:
package {
public final class BrandGlobals {
{
_COLOUR_EVERYTHING_BACKGROUND = 0xE010FF;
trace("Var set."); //Breakpoint here
}
[Bindable]private static var _COLOUR_EVERYTHING_BACKGROUND:uint;
public static function get COLOUR_EVERYTHING_BACKGROUND():uint {
trace("Returning EVERYTHING background"); //Breakpoint here
return _COLOUR_EVERYTHING_BACKGROUND;
}
Putting in breakpoints in the places specified will let you verify that things are executing in the expected order
It turns out that the problem was assigning COLOUR_EVERYTHING_BACKGROUND to a static const elsewhere in the code, as a temporary measure. Hopefully I'll remember that assigning [Bindable]s to static consts is bad and if I don't, I'll remember the meaning of that particular cryptic reaction Flash Builder had. I'm starting to choke StackOverflow w/my questions about cryptic error messages.

AS3 | Dynamically assets embedding

I'm trying to add generic content while embedding my game assets but came up with nothing so far. What I usually do is:
public final class AssetsManager
{
[Embed(source="../assets/game1/icon.png", mimeType = "image/png")]
private static const Icon:Class;
}
However, I want to do something like this:
public final class AssetsManager(gameName:String)
{
[Embed(source="../assets/"+gameName+"/icon.png", mimeType = "image/png")]
private static const Icon:Class;
}
I'm not able to transfer params via the class, so I believe there's another way.
Embedding happens at compile-time so this isn't possible. Instead, you can load in assets at runtime, for example using a URLLoader as a ByteArray, or Loader as Bitmap, or a Flex Image control.

Can I still create Global variables in AS3

Following the answer here, I have created a file called MyGlobals.as and placed some global variables and functions so that I can access it from anywhere within my project just like AS3 buil-in functions such as trace() method.
This is MyGlobals.as which is located in the src folder (top level folder)
package {
public var MessageQueue:Array = new Array();
public var main:Main;
public var BOOKING_STATUS_DATA:Object;
public function postMessage(msg:Object):void {
MessageQueue.push(msg);
}
public function processMessage():void {
var msg:Object = MessageQueue.pop();
if (msg) {
switch (msg.type) {
}
}
}
Looks like my IDE (FD4) is also recognizing all these functions and variables and also highlighting the varibles and functions just like any other built-in global functions. However, I am getting compilation errors "Accessing possibly undefined variable xxx". The code is as simple as trace(MessageQueue) inside my Main (or another classe).
I am wondering if there was any change Adboe has done recently that it can't be done now or am I missing something? I am not sure if I need to give any special instructions to FD to include this MyGlobals.as?
I am using FD4, Flex SKD 3.1, FP12.0
I am aware of the best practices which suggests to avoid using this type of method for creating global variables but I really need it for my project for my comfort which I feel best way (right now) when compared to take any other path which involves daunting task of code refactoring. I just want do something which can be done in AS3 which I guess is not a hack.
I've done some playing around; it looks like you can only define one (1) property or method at package level per .as file. It must be the same name (case-sensitive) as the .as file it is contained in.
So no, nothing has changed since the older Flash Versions.
In your case that would mean you need five separate ActionScript files along the lines of:
MessageQueue.as:
package
{
public var MessageQueue:Array;
}
main.as:
package
{
public var main:Main;
}
...etc. As you can see this is very cumbersome, another downside to the many others when using this approach. I suggest using the singleton pattern in this scenario instead.
package{
public class Singleton{
private static var _instance:Singleton=null;
private var _score:Number=0;
public function Singleton(e:SingletonEnforcer){
trace(‘new instance of singleton created’);
}
public static function getInstance():Singleton{
if(_instance==null){
_instance=new Singleton(new SingletonEnforcer());
}
return _instance;
}
public function get score():Number{
return _score;
}
public function set score(newScore:Number):void{
_score=newScore;
}
}
}
then iin your any as3 class if you import the singleton class
import Singleton
thn where u need to update the global var_score
use for example
var s:Singleton=Singleton.getInstance();
s.score=50;
trace(s.score);
same thing to display the 50 from another class
var wawa:Singleton=Singleton.getInstance();
trace(wawa.score)

Creating Dynamically Flex Custom ItemRender (Constructor)

am creating some Advanced Datagrid with actionscript.
I have created an actionscript class where I extend the VBox object:
package core
{
import mx.containers.VBox;
import mx.controls.TextInput;
public class customItemRender extends VBox
{
public function customItemRender(_TextInput:TextInput, _TextInput2:TextInput)
{
//TODO: implement function
super.addChild(_TextInput);
super.addChild(_TextInput2);
}
}
}
The problem comes up when I declare de itemrender property on the data grid:
AdvancedDataGridColumn.itemRenderer = new ClassFactory(customItemRender(_TextInput1,_TextInput2));
The compiler wont let me instanciate my customItemRender.
Does any one know if there is an alternative solution to solve the problem?
Thanks in advance for you helps,
Regards Javier
private var _ItemRendere:ClassFactory;
private function get MyItemRendere():ClassFactory
{
if (_ItemRendere == null)
{
_ItemRendere = new ClassFactory();
_ItemRendere.generator = customItemRender;
_ItemRendere.properties = {
_TextInput1:MY_TextInput1_OBJECT,
_TextInput2:MY_TextInput2_OBJECT
};
}
return _ItemRendere;
}
then you can use
AdvancedDataGridColumn.itemRenderer = MyItemRendere;
I've only tried to do this using MXML. In that case, i usually have to wrap the IListItemRenderer instance in mx:Component tags. I'm not exactly sure what is going on programmatically when I do this, but it works. The reason is that the itemRender is actually looking for an instance of IFactory rather than an instance so I suppose to do this strictly using AS you would need to create your own IFactory implementation.
e.g.
<mx:List>
<mx:itemRenderer>
<mx:Component>
<mx:Text />
</mx:Component>
</mx:itemRenderer>
</mx:List>
ClassFactory's constructor has a Class as a parameter, not an instance. You need to call:
new ClassFactory(customItemRender);
and not:
new ClassFactory(new customItemRender(_TextInput1,_TextInput2));
or:
new ClassFactory(customItemRender(_TextInput1,_TextInput2));
Now, since the constructor will not be called with reference to TextInput1 and TextInput2, you'll need to instantiate your own TextInputs in the custom renderer itself. (But this is a good thing, if you continue to call new customItemRender(_TextInput1, _TextInput2), then the two TextInputs will only be added to the LAST instance of customItemRender, and all of the others will not have these two objects ).

Howto embed images in Actionscript 3 / Flex 3 the right way?

I'm creating a game where a lot of images are being used in Actionscript / Flex 3 (Flash). Now that I've reached the designer stage, I have to work out a structural way of using embedded images (which have to be manipulated with rotation, color, etc.).
Unfortunately, after investigating a bit, it looks like you have to manually embed images before you can use them. I currently have it setup like this:
Resource.as class file:
package
{
public final class Resource
{
[Embed (source="/assets/ships/1.gif" )]
public static const SHIPS_1:Class;
}
}
So, just for one ship I so for have to:
Put the image in the correct folder with the correct name
Name it in the same way in the Resource.as file
Create the constant with the same name in the Resource.as file
Even though this should all be possible by simply putting the file in a specified folder.
To make things even worse, I still have to call it using:
var test:Bitmap = new Resource.SHIPS_1();
There must be better ways to handle resources when creating very huge applications? Imagine I need thousands of images, this system simply wouldn't fit.
If you need to handle a large number of resources you can follow these 3 steps:
Place them in an uncompressed zip archive
Embed the zip file as binary data:
[Embed(source = 'resources.zip', mimeType = 'application/octet-stream')]
Access the resources using FZip
If you choose a different method that involves loading external files be aware that some flash game websites require the games they host to be contained within a single swf file.
instead of
var test:Bitmap = new Resource.SHIPS_1();
Use
myImage.source = Resource.SHIPS_1;
The embedding is correct. :D the way you use it is wrong :)
Adrian
This is really what Flash CS4 is for. Your way seems fine to me though - although I wouldn't use all caps for a class name even if it is a constant. Just put your head down and get copy-pasting!
Alternatively you could load the files at runtime.
This is old but since I stumbled across it searching for something different I'll write here for future generations : )
I use a different approach. I create a swf movie with flash professional and import all graphics in it and then mark them all for "Export for ActionScript".
Compile the swf and in your main project embed only the swf and access all the graphics through it...
I find this approach much more organized. Why write the whole resources class when you can make it by importing files right? ;)
I just watched this great tutorial on the Starling framework:
http://www.hsharma.com/tutorials/starting-with-starling-ep-3-sprite-sheets/
It sounds like spritesheets are exactly what you're looking for:
You bundle all your individual textures into one big texture that is called spritesheet and create an xml file that contains information where the textures are within the spritesheet. In order to do that you can use this tool:
http://www.codeandweb.com/texturepacker
I'm not sure if you can use it for commercial projects and the amount of textures you're speaking of doesn't sound like you're doing this just as a hobby, so you might want to check the license. There's a pro version available, too.
Texturepacker creates two files: spritesheet.png and spritesheet.xml. You just copy them into your project.
Then you add this code to one of your classes.
private static var gameTextureAtlas:TextureAtlas;
[Embed(source="../media/graphics/mySpriteSheet.png")]
public static const AtlasTextureGame:Class;
[Embed(source="../media/graphics/mySpritesheet.xml", mimeType="application/octet-stream")]
public static const AtlasXmlGame:Class;
public static function getAtlas():TextureAtlas
{
if(gameTextureAtlas==null)
{
var texture:Texture=getTexture("AtlasTextureGame");
var xml:XML=XML(new AtlasXmlGame());
gameTextureAtlas=new TextureAtlas(texture,xml);
}
return gameTextureAtlas;
}
Now you can access all the textures of the spritesheet by calling
YourClass.getAtlas().getTexture("name");
It's simply awesome. When you're using texturepacker the filename of each of the sprites you bundled into the spritesheet becomes its texturename.
This is probably too late to help you, but I hope that future visitors can profit from this elegant solution.
I would like to emphasize that this answer is basically an excerpt from sharma's tutorial. I even felt free to reproduce the code he used in his screencast. All the credit goes to him
It depends how big your individual images are but you could put them all in one image like a spritesheet. If you want to draw a particular ship use the correct xy offset in the image for that ship and use copyPixels to draw it to your bitmap.
package
{
public final class Resource
{
[Embed (source="/assets/ships/1.gif" )]
public static const SHIPS_1:Class;
}
}
[Embed (source="/assets/ships/1.gif" )]
public static const SHIPS_1:Class;
I like to do my Library classes like this.
I took GSkinners code for the singleton: http://gskinner.com/blog/archives/2006/07/as3_singletons.html
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
public class Lib
{
/*
Make this an Singleton, so you only load all the images only Once
*/
private static var instance:Lib;
public static function getInstance():Lib {
if (instance == null) {
instance = new Lib(new SingletonBlocker());
}
return instance;
}
public function Lib(p_key:SingletonBlocker):void {
// this shouldn't be necessary unless they fake out the compiler:
if (p_key == null) {
throw new Error("Error: Instantiation failed: Use Singleton.getInstance() instead of new.");
}
}
/*
The actual embedding
*/
[Embed(source="assets/images/someImage.png")]
private var ImageClass:Class;
private var _imageClass:Bitmap = new ImageClass() as Bitmap;
[Embed(source="assets/images/someOtherImage.png")]
private var OtherImageClass:Class;
private var _otherImageClass:Bitmap = new ImageClass() as Bitmap;
public function get imgClass():Bitmap{
return _imageClass;
}
public function get imgClassData():BitmapData{
return _imageClass.BitmapData;
}
public function get otherImageClass():Bitmap{
return _otherImageClass;
}
public function get otherImageClassData():BitmapData{
return _otherImageClass.BitmapData;
}
}
}
internal class SingletonBlocker {}
[Embed (source="/assets/images/123.png" )]
public static const className:Class;
Good idea, lhk
That is nice solution like Source-Engine with vtf and vmt
vtf = image
vmt = script ( like xml or javascript )
Good i would like to suggest for TexturePacker, TexturePath or TextureTarget :P
Thanky ou for tip.
For example:
mytexture.js:
xml or javascript:
function mytexture(){ basedir = "/assets/mytexture.png", normalmap =
"/assets/mytexture_bump.png", normalcube ) [ 1, 1, 1 ] };
I don't think because default texture gets error somewhere mytexture.png doesn't exists than it happens again :)
[Embed(source="../assets/editors/error_texture.png")] public static
const ERROR_TEX:Class; ...
How do i know because Actionscript 3 should "read" to javascript like jsBirdge or ExternalInterface.call();
Is it possible?