AS3 Serialization - actionscript-3

What I'm trying to do:
-Have objects in a toolbar, drag and dropable onto a movieclip (they then become a child of the movieclip). Once this is done, I want to be able serialize this object, so I can save it to a file. Then, I can reload this file, and continue draging/dropping things onto/off of this movieclip.
How I'm doing it:
public class Serialization {
public static function serializeToString(value:Object):String{
if(value==null){
trace("null isn't a legal serialization candidate");
}
var bytes:ByteArray = new ByteArray();
bytes.writeObject(value);
bytes.position = 0;
var be:Base64Encoder = new Base64Encoder();
be.encode(bytes.readUTFBytes(bytes.length));
return be.drain();
}
public static function readObjectFromStringBytes(value:String):Object{
var dec:Base64Decoder=new Base64Decoder();
dec.decode(value);
var result:ByteArray=dec.drain();
result.position=0;
return result.readObject();
}
}
This is where call the function/write it to the file:
var fr:FileReference = new FileReference;
fr.addEventListener(Event.COMPLETE, success);
var txtString:String = new String();
txtString = save.Serialization.serializeToString(pagePic);
trace(txtString);
fr.save(txtString, "test.txt");
Unfortunately, txtString appears to be blank. Am I approaching this wrong?
Side notes:
This is being developed for a mobile platform.

Unfortunately MovieClips, Sounds, and other resources cannot be serialized. My solution is to create a custom class that will store all my properties and reassign them upon loading, or just write to/parse a text file when saving/loading.

Related

It's possible to write a sharedobject when allowscriptaccess is = "never"?

I will try to write a sharedObject item using my swf embeded into an html page.
"allowscriptaccess" is setted to "never". I can't write sharedObject!
However if I set allowscriptaccess to "always", write action work well...
If I can't use sharedObject with allowscriptaccess setted to never, exist alternative for saving data?
I write a little and stupid example:
public class Main extends Sprite {
private var SHARED_NAME:String = "__SO__";
private var so:SharedObject;
Security.allowDomain("*");
Security.allowInsecureDomain("*");
public function Main() {
this.so = SharedObject.getLocal(this.SHARED_NAME, "/");
this.setSharedObj("YEAHHHHHHHH");
this.getSharedObj();
}
public function getSharedObj(clientId:String = null):Object {
var url:String = "http://localhost:8080?so=" + this.so.data.test;
var request:URLRequest = new URLRequest(url);
var loader:URLLoader = new URLLoader();
loader.load(request);
return this.so.data;
}
public function setSharedObj(setValue:String):void {
this.so.data.test = setValue;
this.so.flush();
}
}
When embed the compiled swf using AllowScriptAccess: "never", get Request never have setted the queryparam so.
If set AllowScriptAccess to "always" queryparam will be correctly setted
#akmozo is right, the problem was not related by AllowScriptAccess, but from my way of testing.
The problem is:
Using firefox in anonymous mode, every time you reload the page, shared object are deleted.
I thought for anonymous session are saved, it is not so!

how to choose one object from a sprite as3

How to choose one object(picture that loaded by file) from a sprite when it is several object on that?
I want to drag one that mouse clicked.
private var spstage1:Sprite = new Sprite();
private var vecpic1:Vector.<String> = new Vector.<String>();
private var iconpic1:iconpic=new iconpic();
spstage1.graphics.beginFill(0xcccccc);
spstage1.graphics.drawRect(250,100,450,668);
stage.addChild(spstage1);
spstage1.addChild(iconpic1);
iconpic1.addEventListener(MouseEvent.CLICK, picclicked);
function picclicked(event:MouseEvent):void {
var txtFilter:FileFilter = new FileFilter("picture", "*.jpg;*.png");
//root.browseForOpen("Open", [txtFilter]);
file = new File();
currentload="pic";
file.addEventListener(Event.SELECT, dirSelected);
file.browseForOpen("Select a picture",[txtFilter]);
//
/*file.browse();
file.addEventListener(Event.SELECT,onselect);*/
}
protected function dirSelected(e:Event):void {
var re1:URLRequest=new URLRequest(file.nativePath);
loader=new Loader();
loader.load(re1);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,loadCompletepic);
}
function loadCompletepic(event:Event):void{
var pic:BitmapData=new BitmapData(loader.width,loader.height,false);
pic.draw(loader);
bitmap=new Bitmap(pic);
spstage1.addChild(bitmap);
bitmap.x=ix;
bitmap.y=iy;
vecpic1.push(bitmap.name);
}
Add MOUSE_DOWN event listener to spstage1.
In the listener handler, check:
function clickHandler(evt:MouseEvent):void {
if (evt.target is Bitmap) {
// here you decide what you have clicked on.
(evt.target as DisplayObject).startDrag(); // do the stuff for dragging etc.
}
}
Here evt.target will be the object that is clicked.
All you have to do is to determine if it is the right object. In this example, it is just checked to be of the Bitmap type. If you have other Bitmaps in the container that don't need to be clicked, use other means, for example store the loaded object somewhere and then compare the target against all the stored objects. Or check for bitmap.name which you seem to already have, etc.

Returning a string in Action Script 3.0

I'm really not familiar with Action Script 3 at all but I am with other languages.
I'm hoping someone could help me.
I'm attempting to make a modification to JWplayer so that an rtmp stream is retrieved via a PHP script rather than it being supplied in the HTML.
The code I currently have is below:
function useData(event:Event):void {
var data:String = event.target.data.toString();
}
/** Load content. **/
override public function load(itm:PlaylistItem):void {
_item = itm;
_position = 0;
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, useData);
loader.load(new URLRequest("http://192.168.0.12/phpauth/play1.php"));
// Set Video or StageVideo
if(!_video) {
_video = new Video(320, 240);
_video.smoothing = true;
_video.addEventListener('renderState', renderHandler);
// Use stageVideo when available
if (_stageEnabled && RootReference.stage['stageVideos'].length > 0) {
_stage = RootReference.stage['stageVideos'][0];
_stage.viewPort = new Rectangle(0,0,320,240);
_stage.addEventListener('renderState', renderHandler);
}
attachNetStream(_stream);
}
// Load either file, streamer or manifest
if (_item.file.substr(0,4) == 'rtmp') {
// Split application and stream
var definst:Number = _item.file.indexOf('_definst_');
In the load function the file name to play is held in _item.file. I'm trying to make a call to a php script which then overwrites the value in _item.file. I've confirmed that the php is being called but I don't know how to get the data from the data string in the useData function into the _item.file string.
Any help would be really appreciated - I suspect this is a simple one but my lack of AS3 knowledge is making it really difficult.
Thanks,
Your problem basically about how to access a local variable in an event handler. A quick and dirty way can be to have an anonymous function used as a handler like:
loader.addEventListener(Event.COMPLETE, function(event:Event):void {
var data:String = event.target.data.toString();
_item.file = data;
});
This approach would work, because this anonymous function has access to the local variables inside load function as is. But, you need to be cautious that the anonymous function uses the variable exactly as the calling function is using. So, let's say there is a loop in load function and _item changes in every iteration of the loop. For that scenario, when load handler gets called, its _item would also have changed to the object which was last assigned to _item.
A far cleaner and OO approach can be to have a handler class like:
package {
public class LoadHandler {
private var _item:PlaylistItem;
public function LoadHandler(item:PlaylistItem) {
_item = item;
}
public function loadHandler(event:Event):void {
var data:String = event.target.data.toString();
_item.file = data;
}
}
and then have loader.addEventListener(Event.COMPLETE, (new LoadHandler(_item)).loadHandler). Hope that helps. BTW, LoadHandler could be made more generic to take and array of objects to be used and a callback function. loadHandler function, then could just call callback function with that array of objects.
If you are returning a simple string from PHP you should be able to use
event.target.data;
e.g. from PHP... echo "hello";
var data:String = event.target.data
You could try tracing the response to ensure you are getting something back from PHP.
You can either test this from within the IDE or install the Debug version of the Flash Player browser plugin.
trace("Response from PHP: "+event.target.data);
_item.file = event.target.data;
trace("_item.file: "+_item.file);

Using the Loader display object to load X jpegs, then resize each of the images differently while they're on the stage

Hey there, I was wondering if this is possible to do
I am able to load the image in and have it displayed easily enough by using addChild(myLoader); where myLoader is in the classWide private scope.
The problem is, whenever I call my function inside that class which adds the loader to the stage, it clears the old one and puts this new one in even if I add a bit where I change myLoader.name to something related to how many images it has completed.
This is a serious hinderance as I can't do anything besides KNOW how many images I will need to load and write the code X times. The problem being is that the urls are read from an XML file.
My main desire was to have a classWide private Array which contained my loaders and I would assign them using myArray.push(myLoader) each time the load had completed. There is a problem which is that it compiles but they never get displayed
it would work as this is written
public class Images extends Sprite
{
private var imagesLoaded = 0;
private var myLoader:Loader;
...
public function Images():Void
{
myLoader = new Loader;
//loop calling a myLoader.load(imageURL) for a bunch of urls
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoaded);
}
public function imageLoaded
{
myArray[imagesLoaded] = myLoader;
trace("does\'nt get to here!!");
addChild(myArray[imagesLoaded]);
imagesLoaded++;
}
}
You could create multiple Loaders to load your multiple files:
public class Images extends Sprite
{
private var imagesLoaded = 0;
private var myArray:Array;
...
public function Images():Void
{
myArray = [];
for each (var url:String in myBunchOfURLS)
loadURL(url);
}
private function loadURL(url:String):void
{
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoaded);
loader.load(new URLRequest(url));
// you'll need to add the loader to the display list to see anything!
addChild(loader);
}
private function imageLoaded(event:Event):void
{
var info:LoaderInfo = LoaderInfo(event.currentTarget);
info.removeEventListener(Event.COMPLETE, imageLoaded);
var loader:Loader = info.loader;
myArray[imagesLoaded++] = loader;
// or you could add the loader to the display list here instead?
}
}
If you have to have one loader, then you'll need to wait for each load to complete, get the bitmap data out of the loaded bitmap, add it to a new bitmap, then start loading the next image. That's a bit more of a pain - I'd stick to this approach if I were you.

Finding (loaded) image size in AS3 (Action Script 3.0)

Im currently using the following function to load an image, however i could not figure out a way to find the width of the loaded image, which i intend to use before placing the next image using the same function.
Note that q is a a variable (a number) which is used to load differant images.
=X i need help obtainning the loaded image width...
function LoadImage(q)
{
var imageLoader:Loader = new Loader();
var image:URLRequest = new URLRequest("GalleryImages/Album1/"+q+".jpg");
imageLoader.load(image);
addChild (imageLoader);
imageLoader.x = 0 + CurrentXLength;
imageLoader.y = 0;
imageLoader.name = "image"+q;
trace(imageLoader.x)
}
You can't know the width of the bitmap until it's actually loaded:
function LoadImage(q)
{
var imageLoader:Loader = new Loader();
var image:URLRequest = new URLRequest("GalleryImages/Album1/"+q+".jpg");
imageLoader.contentLoader.addEventListener(Event.COMPLETE, ImageLoaded);
imageLoader.load(image);
addChild (imageLoader);
...
private function ImageLoaded(e:Event):void
{
var imageLoader:Loader = Loader(e.target.loader);
var bm:Bitmap = Bitmap(imageLoader.content);
var CurrentXLength = bm.width;
....
Alternativly this link might be helpful? Haven't tried it myself ...
I just asked for de width property of loader object:
var loader:Loader;
function loadImage(dir:String):void {
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, placeImage);
var urlReq:URLRequest = new URLRequest(direccion);
loader.load(urlReq);
}
function placeImage(o:Event):void {
loader.x = (1360 - loader.width)/2;
loader.y = (768 - loader.height)/2;
addChild(loader);
}
Where 1360 and 768 are the canvas dimensions...
To access the width you must do it within the function assigned to handle Event.COMPLETE.
"You will want an array containing the items you wish to load. You should probably load this data in with XML so it is dynamic and scalable. Once the xml data is loaded it should be assigned to an array in whatever fashion you like. The reason that we must use an array in this situation, rather then just using the XML object, which is essentially an array, is because you need the know an objects width so that you can base the next objects X position off of the last objects X position plus its WIDTH.
With XML it is common to use a for loop and just iterate through "x" amount of times. We do not want this, in this case. To obtain the "WIDTH" property of the loaded asset, it must be accessed from within the function assigned to fire when the loader fires Event.COMPLETE. Once the image has completed it will remove the item from the array, set a variable as to the lastX and lastWidth, and then get the next item in the array and start all over. Eventually the array is empty and the process is complete.
-Note: I will skip loading the XML and just inject the data into the array myself.
package
{
import flash.display.Sprite;
import flash.display.Loader;
import flash.net.URLRequest;
public class DocumentClass extends Sprite
{
private var _array:Array;
private var _lastX:Number;
private var _lastWidth:Number;
public function DocumentClass():void
{
_array = new Array();
//Add Items to an array however you wish. I did it
//this way to make it easier to read on this site.
_array.push({name: "image1", path: "path/to/image1"});
_array.push({name: "image2", path: "path/to/image2"});
_array.push({name: "image3", path: "path/to/image3"});
loadImage();
}
private function loadImage():void
{
if(_array.length > 0)
{
var loader:Loader = new Loader();
addChild(loader);
var request:URLRequest = new URLRequest(_array[0].path); //Loads first item in the array each time.
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
loader.x = _lastX + _lastWidth;
laoder.load(request);
_lastX = loader.x; //We set after so we are ready for the next.
_array.shift(); //Remove the first item from the array.
}
}
function onImageLoaded(e:Event):void
{
_lastWidth = e.target.width;
loadImage(); //Attempt to load another image if the array isn't empty.
}
}
}
I hope this helps, the code isn't tested, but the concept seems valid.
Yeah I used scott's answer but it's worth noting that 'imageLoader.contentLoader' should be 'imageLoader.contentLoaderInfo' in the LoadImage() function. Solved the width prob for me-- thanks mang