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

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?

Related

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)

as3 calling a function in another class [duplicate]

UPDATE: OK I am about ready to give up on Pacakages and classes. No answers coming. Not sure what to do. I tried to make the question easier and made a new post but I was down voted for it. as3 calling a function in another class
I am TOTALLY NEW to using PACKAGES and CLASSES. I am finally converting over from the timeline after having so many issues. Please be patient with my lack of knowledge. I need to know how to call a function in the child swf file I loaded from code in the maintime in the parent swf.
There are 2 swf files. Main.swf and pConent.swf
1. Main.swf has code in the timeline of the first frame.
2. pConent.swf is loading a PACKAGE CLASS as file.
QUESTIONS
I am trying to call a function in it from its parent Main.swf. How do I do this?
Here is sections of the code from both. Thanks
Main.swf CODE /// is an AIR for Andrid swf
function LoadContent()
{
TheContent.load(new URLRequest( "pContent.swf"));
TheContent.contentLoaderInfo.addEventListener(Event.COMPLETE, LoadContentTWO);
function LoadContentTWO(e:Event)
{
Content = TheContent.content as MovieClip;
pContent = Content as Object;
addChild(TheContent);
var OSS:String = "device";
trace(pContent); //// comes out as: [object pContent]
pContent.GetOnlineStatus(OSS); ///// HOW DO I GET THIS TO CALL FUNCTION
}
}
A SECTION OF THE "CLASS" in pContent.swf I am trying to call
public function GetOnlineStatus(OS:String)
{
if(OS=="online")
trace("inside ONLINE" );
}
if(OS=="device")
{
trace("inside DEVICE" );
}
}
THE ERROR I AM GETTING
TypeError: Error #1006: GetOnlineStatus is not a function.
UPDATE: I decided to post the FULL PACKAGE ( my first) to see if I am doing it right.
package
{
import flash.display.MovieClip;
import fl.transitions.Tween;
import fl.transitions.easing.*;
import fl.transitions.TweenEvent;
import flash.display.*;
import flash.media.Sound;
import flash.system.*;
import flash.media.SoundChannel;
import flash.display.MovieClip;
import flash.events.MouseEvent;
public class pContent extends MovieClip
{
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
var ScreenY = flash.system.Capabilities.screenResolutionY;
var ScreenX = flash.system.Capabilities.screenResolutionX;
var swf:String;
var daSounds:String;
var images:String;
var videos:String;
var OnlineStatus:Boolean;
//++++++++++++++++++++++++
//++++++++++++++++++++++++
public function pContent()
{
BG.addEventListener(MouseEvent.CLICK, mouseHandlerdown);
}
//++++++++++++++++++++++++
//++++++++++++++++++++++++
//-------- * FUNCTIONS * --------
//-------------------------------
public function mouseHandlerdown(event:MouseEvent):void
{
alpha = .3; // testing
}
public function GetOnlineStatus(OS:String)
{
if(OS=="online")
{
OnlineStatus = true;
Security.allowDomain("*");
trace("inside THE PATH " + ThePath.text);
daSounds = "http://mycontactcorner.com/upload/files/";
swf = "http://mycontactcorner.com/upload/files/";
trace("inside THE DEVICE ONLINE" );
OnlineStatus = false;
swf = "";
daSounds = "content/sounds/";
//LoadMenu();
LoadStage();
LoadBeau();
}
if(OS=="device")
{
trace("inside THE DEVICE ONLINE" );
}
}
//------ * END FUNCTIONS * -----
//------------------------------
}// END FUNCTION pContent
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
}//// END PACKAGE
Don't be disappointed, but I won't have a "real" answer to your question, and I am really not going to work through all of your code to solve it, either. It is your own task to learn how to do this, and unless people here are very, very hungry for reputation, no one will do it for you - we will only help you to find the right way.
Your problem is not "packages and classes", so please do not give up on them. They will help you a great deal, once you've started to understand them. Your problem is, that you are not facing a single problem, but actually at least two (and quite substantial ones, I might add):
You need to go back to learn about the basics of object oriented programming in ActionScript. You won't have much luck getting answers to questions like this, otherwise. And believe me, I don't mean that in a patronizing way - it is simply a complicated matter, and it is hard to communicate complicated issues, both when you don't know the terms to express them, or when your counterpart doesn't understand them. Think of it like a high school math problem: You won't ever find a solution to your trigonometry question (or get a decent answer), unless you learn some basic algebra first.
You also have a problem related to loading, application domains, and the Flash Player security model - which are all far more complicated than what you should aim at when trying out OOP stuff. This can be a major obstacle, and unless you want to frustrate yourself, you should try to avoid it, until your program actually runs.
So this here is my advice: Always try to solve one problem at a time. Do not work yourself into such complex scenarios as the one you are in right now, but take step by step, until you've reached a level where you are confident with what you are doing.
Your first issue should be to understand what's going on with classes and objects. Everything else will come later. You should try to isolate your problem in the pContent.swf and get that to work first - or better yet, put everything you need for your program into a single file. Convert to using classes. Then, once you know how to work with those, start learning about more advanced OO, decoupling your code using interfaces, type casting and loading binaries at runtime.
//makes contact with classs but comes out as: [object pContent]
its because you said
pContent = Content as Object;
I am not sure why you are doing this extra step
Change it to this
Content = TheContent.content as MovieClip;
// pContent = Content as Object; //NO NEED OF THIS
addChild(Content); // just in case this gives error change it as addChild(Content as Object);
var OSS:String = "device";
trace(Content); //now see the difference
Content.GetOnlineStatus(OSS); // it calls now
Also, give the link where you posted that scary question :P if it has rest of the code
Sorry if this does not sound like an answer, but I'm going to write a couple of doubts that I have reading your code that can possibly lead to the solution:
Why are you casting it to MovieClip? If you cast it as MovieClip, the compiler it is going to tell you that the method "GetOnlineStatus" doesn't exist, because MovieClip class doesn't have it! I think you have to cast it as pContent
Why are you trying to casting TheContent.content? What is "content"? I had a look to your previous post and I cannot see anything called "content"?
If I ignore my second doubt (TheContent.content issue), I would change the code like this:
Content = TheContent.content as pContent; // your class it's called pContent
addChild(Content);
Content.GetOnlineStatus(OSS); // it calls now
Also, keep in mind that generally it's a good pratice to capitalize name of classes and not variables.
Let me know!
private function GetOnlineStatus
Try making this a public function instead. When it's private it can't be accessed outside the scope of the class that owns it.
I believe that in order to make this work, content property of the Loader. You have to create a reference to the loaded SWF as the class you are trying to call. This class has to be included in the main SWF's project. Then you can call the functions of that particular class in the child.
function LoadContent()
{
TheContent.load(new URLRequest( "pContent.swf"));
TheContent.contentLoaderInfo.addEventListener(Event.COMPLETE, LoadContentTWO);
}
function LoadContentTWO(e:Event)
{
var pContent:GetOnlineStatus = GetOnlineStatus(e.target.content);
addChild(e.target.content); //Assuming that "TheContent was
// declared as var TheContent:Loader , you'd be adding the loader to the stage when I think you actually wanted // to add the content.
var OSS:String = "device";
trace(pContent); //// comes out as: [object pContent]
pContent.GetOnlineStatus(OSS); ///// HOW DO I GET THIS TO CALL FUNCTION
// This should work now. If not, try to loading a function that is not the class' main function. Because I think you might get an "unable to call static function error". I'm a begginner too though, so sorry if I'm wrong. Example: pContent.GetOnlineStatusFunction(OSS);
}
This answer assumes that the pContent.swf contains a class file that looks like this:
package {
public class GetOnlineStatus {
public function GetOnlineStatus (OSS:String) {
//Do your GetOnlineStatus Logic. This is the main function.
}
/*public function GetOnlineStatusFunction (OSS:String) {
//Example non-main function
} */
}
}
Source: http://www.scottgmorgan.com/accessing-document-class-of-externally-loaded-swf-with-as3/

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 .

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.