AS3 | Dynamically assets embedding - actionscript-3

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.

Related

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)

Is there a way to clear out embedded Bitmap assets in AS3/AIR

first time posting on here.
I'm creating an AIR 3.0 app.
For a lot of my graphical assets I'm using the Flex embed metadata to embed bitmap objects as Classes and then instantiating them.
The problem is that it seems these never get garbage collected. I haven't found much info online but I've seen a couple of posts that seem to confirm this.
Anytime one of my classes gets instantiated that has these embedded assets, they always create new instances of the Bitmaps and BitmapDatas rather than reusing what's already in memory. This is a huge problem for memory. And I can't find any way of de-referenciong them or getting them to leave memory.
So the only solution I can think is to just load the graphics from disk rather than using the embed tag. But I'd rather not do this seeing as how when the app is packaged and installed, all of those graphcial assets will be on the end users computer rather than contained within the SWF.
Anyoen run into this? Have a solution? Or an alternate solution than the one I can think of?
Thanks!
Kyle
Well, I guess this is expected behaviour, because the new operator should always create new objects. But those new objects should get garbage collected, just the asset class will not, since it is a class.
You could build a cache that acts like a singleton factory. You request your image by specifying an id, the cache then either creates that image if it doesn't exist already, or just return the single instance if it does. It's been a while since I last coded ActionScript, so maybe you should take this as pseudo-code ;)
public class Cache {
import flash.utils.Dictionary;
import flash.utils.getDefinitionByName;
[Embed(source="example.gif")]
public static var ExampleGif:Class;
/**
* The single instance of the cache.
*/
private static var instance:Cache;
/**
* Gets the Cache instance.
*
* #return
* The Cache
*/
public static function getInstance():Cache {
if (Cache.instance == null) {
Cache.instance = new Cache();
}
return Cache.instance;
}
/**
* The cached assets are in here.
*/
private var dictionary:Dictionary
public function Chache() {
if (Cache.instance != null) {
throw new Error("Can not instanciate more than once.");
}
this.dictionary = new Dictionary();
}
/**
* Gets the single instantiated asset its name.
*
* #param assetName
* The name of the variable that was used to store the embeded class
*/
public function getAsset(assetName:String):Object {
if (this.dictionary[assetName] == null) {
var AssetClass = getDefinitionByName(assetName) as Class;
this.dictionary[assetName] = new AssetClass();
}
return this.dicionary[assetName];
}
}
You could then use it like this:
public class Example {
public static function main() {
Bitmap exampleGif1 = Cache.getInstance().getAsset("ExampleGif") as Bitmap;
Bitmap exampleGif2 = Cache.getInstance().getAsset("ExampleGif") as Bitmap;
trace("both should be the same instance: " + (exampleGif1 == exampleGif2));
}
}
I didn't test this, so let me know if it works.
I think what you're looking for is dispose() http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/BitmapData.html?#dispose()
If you decide to go with a caching system, here is a link with some code that is tested http://thanksmister.com/2009/01/29/flex-imagecache-a-cheap-way-to-cache-images/ . The link it has to another technique, using SuperImage, is broken, but I managed to find this http://demo.quietlyscheming.com/superImage/app.html .

Managing Singletons in external swfs

I'm dealing with the scenario whereby my code might be included in other Flash content either included via import .as commands and then referenced as a Singleton, e.g.
import com.as3.Singleton;
...
...
Singleton.birth();
Singleton.getInstance().test();
...but also imported as a runtime library; with the Singleton class exported as a .swf beforehand (instead of pre-baking the class).
How should I reference the Singleton once Event.COMPLETE has fired off from the Loader that brings in the swf? Normally I'd code something like:
public function singletonCompleteHandler(event:Event):void {
var mySing:Singleton = _loader.contentLoaderInfo.content as Singleton;
}
...but I know I don't want to be referencing the singleton via a "var" reference. I'm not explaining very well, but basically once the singleton.swf has loaded in I need to use the code within it within a singleton model (i.e. ensure there's only one instance of it throughout my application).
Copy of the Singleton class included below (thanks for any thoughts on this by the way).
package
{
public class Singleton extends Sprite
{
private static var instance:Singleton;
public function Singleton() {
if (instance) {
throw new Error("Singleton can only be accessed through Singleton.getInstance()");
}
}
public static function birth() {
if (instance == null) {
instance = new Singleton();
}
}
public static function getInstance():Singleton {
return instance;
}
public function test():void {
trace("Testing our singleton.");
}
}
}
First of all, if you're loading it dynamically, then you don't want to have a reference to it in your loading SWF (otherwise it would defeat the point).
So I'm guessing you're looking to do something like this:
function completeHandler(event:Event):void
{
var singleton:Object = loader.contentLoaderInfo.content;
var instance:IMyObject = singleton.getInstance();
instance.test();
}
IMyObject is of course optional here. If you do it like this, your singleton instance will have to implement IMyObject.
interface IMyObject
{
function test():void;
}
This is all to avoid having to reference the actual class in your loading SWF. Like I said, the interface is optional: you can just use Object instead.
... and now on to the main point: load the singleton SWF into the loading SWF's own "application domain".
http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/system/LoaderContext.html#applicationDomain
var lc:LoaderContext = new LoaderContext();
lc.applicationDomain = ApplicationDomain.currentDomain;
loader.load(new URLRequest("Singleton.swf"), lc);
You see, normally when you load a SWF, it gets loaded into its own application domain. But this makes it impossible to enforce the singleton pattern on the loaded SWF, because each instance of the class can live in its own application domain (hence you can end up with multiple instances). So if you want to enforce this across multiple SWF loads then you want to load it into the loading SWF's application domain.
If your question is "How should I reference the Singleton once Event.COMPLETE has fired off from the Loader that brings in the swf?", then you can do it with:
var Singleton:Object = _loader.contentLoaderInfo.applicationDomain.getDefinition('Singleton');
But, I'm not sure what you mean about not wanting to use a "var" reference.
On a side-note, there's a good chance a global variable would be a better option than a Singleton class for an API.
package myPackage
{
public var myGlobal:MyGlobal = new MyGlobal();
}
Which you can access with myPackage.myGlobal

Reducing the number of Class objects to access embedded resources

I'm building a Flex project with a lot of embedded bitmaps and such. The usual method for getting to the bitmaps in Actionscript seems to be to do something like
[Bindable] [Embed(source = '../lib/WhiteFencePost.png')]
private static var clsObstacleFencePost : Class;
var bitmap : BitmapAsset = new clsObstacleFencePost();
I've already got several dozen of these things, and I can easily see ending up with hundreds of them by the time the project's done. Is there some way that I can avoid creating a Class for every bitmap?
Try to create an assets manager with static classes like this.
class AssetManager
{
[Bindable]
[Embed(source = '../lib/WhiteFencePost.png')]
public static var WhiteFencePost:Class;
[Bindable]
[Embed(source = '../lib/BlackFencePost.png')]
public static var BlackFencePost:Class;
}
Then you can use the images like this
myImage1.source = AssetManager.WhiteFencePost;
myImage2.source = AssetManager.WhiteFencePost;
myImage3.source = AssetManager.WhiteFencePost;
myImage4.source = AssetManager.BlackFencePost;
You do not need to define a new instance of the Class images that you want to use.
There are ways... Pack all files into zip - embed zip - unpack with any zip library for actionscript, then Loader.loadBytes pic needed. Zip contents can be enumerated, so if you know what to do with files by name, you don't even need file list in application.

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?