Unable to clone vector with deep copy of objects - actionscript-3

This is my vector that I want to fully clone (meaning that if I change the cloned vector it doesn't affect the original vector).
var vector:Vector.<Path_Tiles> = new Vector.<Path_Tiles>();
vector = path_finder.Find_Path(Gird.TILE_SET, start, end, R_G_B, SCAREDNESS);// return a vector of path_tiles in order
and I'm trying to put it into this vector
var vector2:Vector.<Path_Tiles> = clone(vector);
and clone method is this (which I found this method on a website so I do not fully understand it)
public function clone(source:Object):*
{
var myBA:ByteArray = new ByteArray();
myBA.writeObject(source);
myBA.position = 0;
return(myBA.readObject());
}
But I'm getting this error: "[Fault] exception, information=TypeError: Error #1034: Type Coercion failed: cannot convert AS3.vec::Vector.#85973d1 to AS3.vec.Vector.."
How do I convert Path_Tiles into an object?

Assure your Path_Tiles class has been registered:
flash.net.registerClassAlias("tld.domain.package.Path_Tiles", Path_Tiles);
Then, you may copy by serializing the data to a ByteArray:
var tiles:Vector.<Path_Tiles>;
var tilesCloned:Vector.<Path_Tiles>;
var byteArray = new ByteArray();
byteArray.writeObject(tiles);
byteArray.position = 0;
tilesCloned = byteArray.readObject() as Vector.<Path_Tiles>;
Cast the readObject() deserialization to Vector.<Path_Tiles> using the as keyword.
Constructors for objects serialized must accept default parameters.
To put this all together, say this was your Path_Tiles class:
Path_Tiles.as
package
{
public class Path_Tiles
{
public function Path_Tiles(property1:String=null, property2:int=undefined) {
this.property1 = property1;
this.property2 = property2;
}
public var property1:String;
public var property2:int;
}
}
Here is your main class, showing an example of deep cloning the Path_Tiles collection:
Main.as
package
{
import flash.display.Sprite;
import flash.net.registerClassAlias;
import flash.utils.ByteArray;
public class Main extends Sprite
{
public function Main() {
super();
var source:Vector.<Path_Tiles> = new <Path_Tiles>[
new Path_Tiles("Hello", 1),
new Path_Tiles("World", 2)
];
var cloned:Vector.<Path_Tiles> = clone(source);
}
public function clone(source:Vector.<Path_Tiles>):Vector.<Path_Tiles> {
flash.net.registerClassAlias("Path_Tiles", Path_Tiles);
var byteArray = new ByteArray();
byteArray.writeObject(source);
byteArray.position = 0;
return byteArray.readObject() as Vector.<Path_Tiles>;
}
}
}
Finally, we can see the object was deep copied; confirmed by memory address:

Related

Actionscript 3: Access movieclips from array with for-loop

I am having some trouble with accessing the movieclips I've added as childs. From what I've read, a way to solve this is to add every new movieclip to an array, and then loop through this array when I want to change something about all the movieclips.
In my case I want to scale them.
This is how I've tried to implement this function:
package
{
import flash.display.MovieClip;
import flash.utils.Dictionary;
import flash.events.MouseEvent;
import Airport;
public class Main extends Sprite
{
public var tile:MovieClip
public var bg_image:Sprite;
public var airport:Airport;
public static var airportDict:Dictionary = new Dictionary();
public static var collectedAirportArray:Array = new Array();
public function Main()
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
public function init(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// airportDict is being filled up here.. but that's not really relevant for my problem
bg_image = new Image();
addChild(bg_image);
bg_image.addEventListener(MouseEvent.CLICK, testfunction);
for (var k:Object in airportDict)
{
var airport:Airport = new Airport(k,airportDict[k]["x"], airportDict[k]["y"]);
collectedAirportArray.push(collectedAirportArray);
bg_image.addChild(airport);
}
}
private function testfunction(evt:MouseEvent):void
{
for each (tile in collectedAirportArray)
{
tile.scaleY = 2 * tile.scaleY;
}
}
}
}
This give me the error message TypeError: Error #1034: Type Coercion failed: cannot convert []#30977eb1 to flash.display.MovieClip.
at Main/testfunction() when clicking on the bg_image
You have an error in where you are making the array. You have there collectedAirportArray.push(collectedAirportArray); - you're basically pushing an array into itself. Nice snakey, they said. You should instead push the newly created airport in there:
collectedAirportArray.push(airport);
If your airport is any kind of DisplayObject your code should work.
What AirPort class is extending? If it extends MovieClip then try type casting like so:
private function testfunction(evt:MouseEvent):void
{
for each (tile in collectedAirportArray)
{
var myTile:MovieClip = MovieClip(tile);
myTile.scaleY = 2 * myTile.scaleY;
}
}

Reading DWORD incorrectly with AS3?

In this question I got an answer on how to use this information to read BLB files. So I followed the instructions, and it appears that I'm reading the header properly.
However, when I try to read the file IDs, I get an end of file runtime error:
[Fault] exception, information=Error: Error #2030: End of file was encountered.
Here's my code.
Base class:
package
{
import flash.display.Sprite;
import flash.filesystem.File;
import flash.filesystem.FileStream;
import flash.utils.ByteArray;
import flash.utils.IDataInput;
import flash.filesystem.FileMode;
public class BLBDecompress extends Sprite
{
private var _file:File;
private var _stream:FileStream;
private var _blbBytes:ByteArray;
private var _header:Header;
private var _fileIDs:Array;
public function BLBDecompress()
{
decompress();
}
private function decompress():void
{
_file = File.applicationDirectory.resolvePath("testfiles/t.blb");
_blbBytes = new ByteArray();
_stream = new FileStream();
_stream.open(_file, FileMode.READ);
_stream.readBytes(_blbBytes);
_stream.close();
_header = readHeader(_blbBytes);
_fileIDs = new Array();
for (var i:int = 0; i < _header.dwNumber; i++)
{
_fileIDs.push(readFileID(_blbBytes));
}
}
private function readHeader(input:IDataInput):Header
{
var header:Header = new Header();
header.szID = new ByteArray();
input.readBytes(header.szID, 0, 4);
header.bID = input.readUnsignedByte();
header.bUnknown = input.readUnsignedByte();
header.wDataSize = input.readUnsignedShort();
header.dwFileSize = input.readUnsignedInt();
header.dwNumber = input.readUnsignedInt();
return header;
}
private function readFileID(input:IDataInput):uint
{
var fileID:uint = input.readUnsignedInt();
return fileID;
}
}
}
Header class:
package
{
import flash.utils.ByteArray;
public class Header
{
public var szID:ByteArray;
public var bID:uint;
public var bUnknown:uint;
public var wDataSize:uint;
public var dwFileSize:uint;
public var dwNumber:uint;
public function Header()
{
}
}
}
The thing is that _header.dwNumber returns/traces as 1090650112 (41020000 in base 16), so I can imagine that would reach the end of the file. So am I reading it wrong, using it wrong, or doing something else wrong? The rest of the
If it helps, this is an AIR application, and I'm using FlashDevelop with the Flex 4 SDK.
That look like a simple Big/Little endian problem, the 4 bytes that make up the DWORD are in the file in a different order to that used by your processor.
You need to reverse the order of the bytes in the DWORD to get 00000241, and any other multibyte number

JSON errors on ActionScript3

I have this code for a mock up mobile app on Flash:
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.*;
import flash.net.*;
import com.adobe.serialization.json.*;
public class ScreenCategories extends Sprite
{
private var lastButtonEndedY:int;
private var categories:Array;
private var dataUrl:String = "getCategories.php";
// Change this to false to use local static data instead;
private var useRemoteData:Boolean = true;
// Constructor: Create an array of three categories
public function ScreenCategories()
{
lastButtonEndedY = 35;
if ( useRemoteData )
{
loadCategories();
}
}
public function loadCategories():void
{
var request:URLRequest = new URLRequest(dataUrl);
var loader:URLLoader = new URLLoader();
loader.dataFormat = URLLoaderDataFormat.TEXT;
loader.addEventListener(Event.COMPLETE, categoryLoad_complete);
loader.load(request);
}
private function categoryLoad_complete(evt:Event):void
{
var jsonText:String = evt.target.data;
//Deserialize JSON
categories = JSON.decode(jsonText) as Array;
}
private function initializeCategory():void
{
// for each "category" in our list (Array)...
for (var count in categories)
{
// Create a button for each of the categories that exist in our Array
var aCategory:BtnCategory = new BtnCategory(categories[count].category);
// Add the BtnCategory to the stage
aCategory.x = 0;
aCategory.y = lastButtonEndedY;
aCategory.name = categories[count].id; // give it a unique name!
addChild(aCategory);
lastButtonEndedY += (aCategory.getHeight() + 1);
}
addEventListener(MouseEvent.CLICK, mouseClicked);
}
public function mouseClicked(e:MouseEvent)
{
removeEventListener(MouseEvent.CLICK, mouseClicked);
// trace the name of the button that was pressed, in this case - the category number!
var btnPressed:int = parseInt(e.target.name);
// if the category exists in the Array (ie. not undefined), then display that category!
if (categories[btnPressed] != undefined)
{
displayCategory(btnPressed)
}
addEventListener(MouseEvent.CLICK, mouseClicked);
}
// We want to go forward to see the list of products in this category, call back to Main.as so make that happen.
public function displayCategory(categoryId)
{
trace ("display product category:" + categoryId);
var par:* = parent;
par.displayCategory(categoryId);
}
}
}
But I get the following errors:
**JSONParseError: Unexpected < encountered
at com.adobe.serialization.json::JSONTokenizer/parseError()[/Users/rominamora/Documents/AOD/term 3/interactive design/assignment3/com/adobe/serialization/json/JSONTokenizer.as:704]
at com.adobe.serialization.json::JSONTokenizer/getNextToken()[/Users/rominamora/Documents/AOD/term 3/interactive design/assignment3/com/adobe/serialization/json/JSONTokenizer.as:206]
at com.adobe.serialization.json::JSONDecoder/nextToken()[/Users/rominamora/Documents/AOD/term 3/interactive design/assignment3/com/adobe/serialization/json/JSONDecoder.as:102]
at com.adobe.serialization.json::JSONDecoder()[/Users/rominamora/Documents/AOD/term 3/interactive design/assignment3/com/adobe/serialization/json/JSONDecoder.as:71]
at com.adobe.serialization.json::JSON$/decode()[/Users/rominamora/Documents/AOD/term 3/interactive design/assignment3/com/adobe/serialization/json/JSON.as:95]
at ScreenCategories/categoryLoad_complete()[/Users/rominamora/Documents/AOD/term 3/interactive design/assignment3/ScreenCategories.as:45]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at flash.net::URLLoader/onComplete()**
You probably receive invalid JSON from getCategories.php.
Try running the getCategories.php script in a browser (by pasting the (full) URL in the address bar) and copying the JSON you get into the jsonlint validator. This should give you a heads up about anything invalid.
For a definition of valid JSON check out json.org

How to save Objects to File (AS3 / Air)

What I want?
Save my Project in a Editor created with Air Application
What is to save?
1 Object -> Type ArrayCollection -> Contains -> Objects from own classes...
What was my first try?
var stream :FileStream = new FileStream();
stream.writeObject(myArrayCollection);
What was the Problem?
The objects inside of myArrayCollection got this Structure:
public class MyClass1
{
public var title:String;
public var description:String;
public var kindOf:String = "...";
public var thumbnail:String;
public var children:ArrayCollection
...}
Every public var were saved by the FileStream.... works fine
Inside the children arrayCollection are objects from this class:
public class MyClass2 extends XMLDocument implements IExternalizable
{
public const kindOf:String = "Seite";
[Bindable]
public var title:String;
public var contenBox:OwnClass; //extended spark Group
public function get childrens():ArrayCollection
{
var childs: ArrayCollection = new ArrayCollection();
var i:int = 0;
while(i > (contenBox.container as spark.components.Group).numElements)
{
childs.addItem((contenBox.container as spark.components.Group).getElementAt(i));
i--;
}
return childs;
}
public function readExternal(input:IDataInput):void
{
trace("hello i'am reading");
}
public function writeExternal(output:IDataOutput):void
{
trace("hello i'am writing");
output.writeObject(children);
}
Now the Problem... the fileStream contains my MyClass2 objects with the var "title" but there is no children ArrayCollection... the console don't shows the traces :-/
Have you tried serializing your Object? You could serialize it to XML and than back again on reading.
It seems a good library for this is Flexxb
other way would to write the file as raw binaries with Bytearray as was explained here
hope it helps!

AS3 Error 1000 on Vector

So I've never worked with Vectors in Flash before and I wanted to write a little test application with a Vector using a custom object. But I'm getting: error 1000: Ambiguous reference to Vector when I try launching the application. I can't figure out for the life of me what's wrong. I tried not using a custom object and just instantiating a string Vector from an online tutorial and I'm getting the same thing.
Here's what I got:
package
{
import TestPlayer; // The custom player class
import flash.display.MovieClip;
public class Vector extends MovieClip
{
private var array:Array = new Array();
private var vector:Vector.<TestPlayer>;
public function Vector()
{
array[0] = [0, 0, "Bob", false];
array[1] = [1, 0, "Frank", true];
array[2] = [2, 1, "Sarah", true];
Load();
}
private function Load():void
{
var aPlayer:Player = null;
vector = new Vector.<TestPlayer>();
try
{
var numRows:int = array.length;
for (var i = 0; i < numRows; i++)
{
aPlayer = new Player();
aPlayer.playerID = array[i][0];
aPlayer.playerName = array[i][1];
aPlayer.playerTypeID = array[i][2];
aPlayer.hasProgress = array[i][3];
vector.push(aPlayer);
}
}
catch (error:Error) { }
}
}
The custom player class looks like this:
package
{
public class TestPlayer
{
private var _playerID:int;
private var _playerName:String = "";
public function get playerID():int
{
return _playerID;
}
public function set playerID(value:int):void
{
_playerID = value;
}
public function get playerName():String
{
return _playerName;
}
public function set playerName(value:String):void
{
_playerName = value;
}
[...]
}
}
I don't know if it matters, but I'm working in Flash CS5, and I have a blank FLA that imports the class. No other errors so far. Hope you can help. Let me know if you need anymore info, thanks.
The ambiguous reference is because you've got a naming collision. The class you've written is named "Vector", which it can't distinguish from the top-level class Vector. The fix is simple, avoid naming your classes the same as a pre-existing class.
If both classes belong to separate namespaces, you can reuse class names, as long as you use thier fully-qualified name whenever you call the class.
Assume you have a class:
package foo.bar
{
class MovieClip
...
}
You could instantiate both types of MovieClips as follows:
flashMovieClip = new flash.display.MovieClip();
myMovieClip = new foo.bar.MovieClip();
Unfortunately, both your Vector and the flash Vector exist in the top-level namespace, so (AFAIK) there's no way of removing the ambiguity without renaming your class. For simplicity sake, avoid naming collisions and you should be golden.